Fw: [sage-support] (5-e^x).substitute(x=log(x)) goes wrong?
Hi, This was reported to the sage-support list. I was intending to CC ginac-list in my reply, but hit send a bit too soon. Cheers, Burcin Begin forwarded message: On Fri, 10 Sep 2010 08:10:45 -0700 (PDT) KvS <keesvanschaik@gmail.com> wrote:
Dear all,
I'm sorry I have yet again something to bother you with. Running the following few lines:
eq=5-e^x print "1:",eq.substitute(x=3*x) print "2:",eq.substitute(x=log(x))
yields the output (Sage 4.5.2 with Ubuntu):
1: -e^(3*x) + 5 2: -log(x) + 5
So 1 is fine, but it seems that to get to 2 Sage actually substitutes twice no: 5-e^x -> 5-x -> 5-log(x). I had expected it would just give me 5-x rather, is it a bug or a feature?
Thanks for reporting the problem. This looks like a bug in GiNaC, the library we use for the symbolic expressions. ginsh - GiNaC Interactive Shell (ginac V1.5.7) __, _______ Copyright (C) 1999-2010 Johannes Gutenberg University Mainz, (__) * | Germany. This is free software with ABSOLUTELY NO WARRANTY. ._) i N a C | You are welcome to redistribute it under certain conditions. <-------------' For details type `warranty;'. Type ?? for a list of help topics.
subs(5-exp(x),x==log(x)); 5-log(x)
I opened a ticket for this: http://trac.sagemath.org/sage_trac/ticket/9891
Hi! Burcin Erocal wrote:
This looks like a bug in GiNaC, the library we use for the symbolic expressions.
ginsh - GiNaC Interactive Shell (ginac V1.5.7) __, _______ Copyright (C) 1999-2010 Johannes Gutenberg University Mainz, (__) * | Germany. This is free software with ABSOLUTELY NO WARRANTY. ._) i N a C | You are welcome to redistribute it under certain conditions. <-------------' For details type `warranty;'.
Type ?? for a list of help topics.
subs(5-exp(x),x==log(x)); 5-log(x)
Thank your for the bug report. The problem is that exprseq::subs(x==log(x)) first recurses into its child, resulting in exp(log(x)) and then it invokes subs_one_level(x==log(x)) on that result again, but the result has meanwhile automagically evaluated to x! To see this, here is how the call tree for subs(exp(x),x==log(x)) looks like: exprseq::subs([(x,log(x))], pattern_is_not_product) (*this==[x]) exprseq::subschildren([(x,log(x))], pattern_is_not_product) (*this==[x]) basic::subs_one_level([(x,log(x))], pattern_is_not_product) (*this==x) exprseq::subs([], no_pattern|pattern_is_not_product) (*this==[x]) exprseq::subschildren([], no_pattern|pattern_is_not_product) (*this==[x]) basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==x) -> x basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==log(x)) -> log(x) -> log(x) basic::subs_one_level([(x,log(x))], pattern_is_not_product) (*this==x) exprseq::subs([], no_pattern|pattern_is_not_product) (*this==[x]) exprseq::subschildren([], no_pattern|pattern_is_not_product) (*this==[x]) basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==x) -> x basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==log(x)) -> log(x) -> log(x) In contrast, the call tree for subs(exp(x),x==log(y)) looks like this: exprseq::subs([(x,log(y))], pattern_is_not_product) (*this==[x]) exprseq::subschildren([(x,log(y))], pattern_is_not_product) (*this==[x]) basic::subs_one_level([(x,log(y))], pattern_is_not_product) (*this==x) exprseq::subs([], no_pattern|pattern_is_not_product) (*this==[y]) exprseq::subschildren([], no_pattern|pattern_is_not_product) (*this==[y]) basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==y) -> y basic::subs_one_level([], no_pattern|pattern_is_not_product) (*this==log(y)) -> log(y) -> log(y) basic::subs_one_level([(x,log(y))], pattern_is_not_product) (*this==y) -> y I'm not sure how to fix this. Calling subs_one_level([x,log(x)]) is certainly necessary. Otherwise, subs(sin(1+sin(x)),sin($1)==cos($1)) would return sin(1+cos(x)) instead of cos(1+cos(x)). Bye! -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi! I have pushed a patch that fixes the problem. The patch avoids the final subs_one_level on anything but containers. Why? As the bug shows, this substitution is wrong in the general case: f(x).subs(x==f^-1(x)) -> f(f^-1(x)) [subschildren] -> x [eval] -> f^-1(x) [subs_one_level] Bug! On the other hand, the intent (as advertised e.g. in the tutorial) is to syntactically substitute functions of a certain kind etc., so, assuming three hypothetical function f, g, and h where f(h(x)) evaluates to g(x): f(g(x)).subs(g(x)==h(x)) -> f(h(x)) [subschildren] -> g(x) [eval] -> h(x) [subschildren] Okay! In this case, stopping after the second step would not be satisfactory. This syntactic substitution is clearly only for the top level (as the method's name subs_one_level implies) but should not be applied to symbols. This patch is for container<C> a.k.a. exprseq, so besides for functions it also applies to classes indexed and ncmul. I am reasonably sure it's also correct there. This case is very similar to a problem that lead to release of GiNaC 1.0.6. Burcin, this should apply cleanly to Sage. Bye! -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Richard B. Kreckel wrote:
On the other hand, the intent (as advertised e.g. in the tutorial) is to syntactically substitute functions of a certain kind etc., so, assuming three hypothetical function f, g, and h where f(h(x)) evaluates to g(x):
f(g(x)).subs(g(x)==h(x)) -> f(h(x)) [subschildren] -> g(x) [eval] -> h(x) [subschildren] Okay!
Oops, the last line is due to subs_one_level, not to subschildren, of course. -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi Richard, On Wed, 15 Sep 2010 09:42:50 +0200 "Richard B. Kreckel" <kreckel@ginac.de> wrote:
I have pushed a patch that fixes the problem. <snip description>
Burcin, this should apply cleanly to Sage.
Thank you very much for this. I just merged your patch and it works perfectly. Cheers, Burcin
participants (2)
-
Burcin Erocal
-
Richard B. Kreckel