On Sat, Jul 9, 2011 at 12:48 PM, Ronan Lamy <ronan.l...@gmail.com> wrote:
> Le samedi 09 juillet 2011 à 10:29 -0700, Brian Granger a écrit :
>> > As many of you may know, the main thing blocking the merge of my work
>> > on the Risch algorithm (see my integration3 branch) is not any
>> > deficiency in the algorithm, though there are several parts that are
>> > still not implemented, but the lack of a so called "atomic
>> > substitution" framework.  The relevant issue here is 2026
>> > (http://code.google.com/p/sympy/issues/detail?id=2026).
>> >
>> > Basically, the following breaks the preprocessing code in risch_integrate:
>> >
>> > In [1]: exp(2*x).subs(exp(x), y)
>> > Out[1]:
>> >  2
>> > y
>> >
>> > I need a way for subs to behave exactly, so the above would return
>> > exp(2*x).   Thus, I have disabled this completely in my integration3
>> > branch, but this is only a temporary solution, as there is a lot of
>> > code that relies on this behavior (especially in the series/limits
>> > code), and it would be a regression anyway.
>>
>> I have always thought that subs should not know about any mathematical
>> relationships, but should behave as you are proposing (atomic or
>> exact=True).  In my mind, subs is a foundation that can be used to
>> build more advanced pattern matching and rule capabilities.  But those
>> more advanced rules (such as done by power) should be in subs itself,
>> but in that higher level.  Thus.
>
> I agree. We need some way of performing direct replacements, based only
> on the structure of the expression. We also need a way to transform
> expressions while preserving their mathematical meaning. Currently,
> subs() tries to do both, which causes most of the problems with it.

Yes, exactly.  I actually need both in my Risch code: a way to do very
precise exact substitution of terms I find using .atoms(), and a
method that tries to be as mathematically smart as possible to "get a
term back in the expression" regardless of its form.

The former is needed for the preprocessing step, where I only want to
substitute dummy symbols for exactly the expressions I want, and the
latter is for after integration, where I often need to do a back
substitution to make the integral look like the integrand. For
example, to integrate 2**x, it first has to be converted to
exp(x*log(2)).  But I try to replace it back after integration, so the
integral has 2**x like the user expects.  If the integrand had 2**x
and the integral has exp(2*x*log(x)), it won't work without fancy
power substitution that recognizes that as (2**x)**2.  I will also
need ways to convert trig expressions back and forth to each other
once I have that implemented.

>>
>> I am +1 on the exact or atomic keyword to subs (I prefer exact).
>>
>> I am ++1 on having that be the default behavior
>
> -1 on adding keyword arguments. These are different operations that
> require different interfaces and implementations. Lumping together
> distinct functions under the same name via keyword switches always
> creates a mess.

Well, how would you do it?  I am very open to suggestions.

Aaron Meurer

>>
>> Cheers,
>>
>> Brian
>>
>> > So there needs to be a way to do
>> >
>> >>>> exp(2*x).subs(exp(x), y, atomic=True)
>> > exp(2*x)
>> >
>> > Now, as it turns out, it has come up in other places that people want
>> > control over the way that subs works in other ways.  In the issue, I
>> > talk about something called integer_powers, which would work like
>> >
>> >>>> exp(2*x).subs(exp(x), y, integer_powers=True)
>> > y**2
>> >>>> exp(x).subs(exp(2*x), y, integer_powers=True)
>> > exp(x)
>> >
>> > In other words, it does not do power manipulation in the replacement
>> > unless the resulting power is an integer.  This is needed in some
>> > places such as the heurisch algorithm to ensure that the resulting
>> > expression will be a polynomial (actually, a rational function) in the
>> > substitution variable.  In addition, there is also some concern about
>> > the assumptions validity of certain algebraic substitution rules.  See
>> > issues 2081 and 2552.
>> >
>> > So in the interest of doing this right, I think there needs to be some
>> > kind of hints mechanism to subs.  My question is, what do you think
>> > would be the best way to implement this?  Presently the expand
>> > function has something like this, but I'm not really convinced that
>> > the way that it's implemented is a very good one.
>> >
>> > Here's (roughly) the way that subs works now:  Basic defines two
>> > methods, .subs and ._eval_subs.  Basic.subs() is of course the user
>> > level function that everyone calls, and pretty much no subclass of
>> > Basic overrides it.  The actual substitution happens in ._eval_subs,
>> > which is also responsible for recursing the substitution down the
>> > .args.  Basic has a simple implementation, but most classes end up
>> > overriding it (for example, exp has overridden it to allow the above
>> > fancy algebraic substitution).
>> >
>> > What's the best way to implement the various hints I want to add to
>> > .subs()?  A few things to take into consideration:
>> >
>> > - .expand() works, as I mentioned earlier, by having
>> > ._eval_expand_hint() methods.  I don't think this is the best way, so
>> > that's why I'm asking here to see if anyone has any better ideas.
>> >
>> > - It should remain backwards compatible with any class that defines
>> > ._eval_subs(self, old, new).  Unfortunately, there wasn't much
>> > foresight when this was originally designed, so the protocol does not
>> > call for any *args or **kwargs.  However, that doesn't necessarily
>> > weigh those options out, as we could easily make Basic.subs() check
>> > for an old style definition and ignore hints in that case.
>> >
>> > - I haven't looked at it, but we might be able to implement at least
>> > atomic substitution entirely in Basic (no class need override any
>> > methods to get it to work).  This is because it is so simple that the
>> > default agnostic method might be able to do it entirely.  The rule for
>> > atomic substitution by the way is that expr.subs(old, new,
>> > atomic=True) should replace old with new in expr if and only if old is
>> > in expr.atoms(old.__class__).
>> >
>> > So I'm open to any ideas on how to implement this, API-wise.
>> >
>> > Also, Chris, did you start this at all in any of your branches and/or
>> > are you willing to help with this?
>> >
>> > Aaron Meurer
>> >
>> > --
>> > You received this message because you are subscribed to the Google Groups 
>> > "sympy" group.
>> > To post to this group, send email to sympy@googlegroups.com.
>> > To unsubscribe from this group, send email to 
>> > sympy+unsubscr...@googlegroups.com.
>> > For more options, visit this group at 
>> > http://groups.google.com/group/sympy?hl=en.
>> >
>> >
>>
>>
>>
>> --
>> Brian E. Granger
>> Cal Poly State University, San Luis Obispo
>> bgran...@calpoly.edu and elliso...@gmail.com
>>
>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To post to this group, send email to sympy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sympy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sympy?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to sympy@googlegroups.com.
To unsubscribe from this group, send email to 
sympy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.

Reply via email to