Maxima: how to replace common subexpressions with symbols
Asked Answered
B

2

7

Suppose I have an expression like (actually mine is much more complex, thousands of characters)

expr:a+b*c+b*c*d;

and I want to replace an internal sub-expression with a symbol (useful to avoid recomputation of common subexpressions), say k in place of b*c:

subst(b*c=k,expr);

returns

k+b*c*d+a

How I can make Maxima calculate the "right" substitution so to return (apart from obviuos simplification, here)

k+k*d+a

?

Bindweed answered 27/3, 2014 at 11:11 Comment(0)
S
11

Take a look at let and letsimp. E.g.:

(%i2) expr : a + b*c + b*c*d;
(%o2) b*c*d+b*c+a
(%i3) let (b*c, k);
(%o3) b*c --> k
(%i4) letsimp (expr);
(%o4) d*k+k+a

letsimp differs from subst and tellsimp or defrule in that those other functions make only formal substitutions, i.e., replacing subexpressions which are exactly the same as some pattern.

Sclater answered 27/3, 2014 at 17:33 Comment(6)
This is exactly what I was looking for, but unfortunately it does not work under square root. If you put b*c*d under square root, letsimp fails to replace b*c with k. How can I make it work everywhere?Bindweed
@Bindweed Try scanmap(letsimp, expr).Sclater
This is nice, but doesn't seem to work in many cases, e.g., expr : %e^-1*x; let(%e^-1*x,y); scanmap(letsimp, expr); doesn't work, but it does work if I replace %e^-1 with 2.Paramagnetic
@BenCrowell it turns out you need to enable the letrat flag (q.v.) to simplify negative powers. E.g. letrat:true; letsimp(...);. Remember that a quotient is represented as a product of the numerator times the denominator to the power negative 1.Sclater
It also seems that it only does one substitution at a time, so, e.g., this works: letrat:true; let(x*x,u); let(sin(u),y); scanmap(letsimp,scanmap(letsimp, sin(x*x)));, but it doesn't work if you don't nest the scanmap functions two deep.Paramagnetic
@BenCrowell Well, the problem is that letsimp needs to see different levels of the expression -- there's sin(x^2) with something inside it that letsimp needs to work on, and then it needs to work on the whole sin(u) afterwards. I think it's reasonable to expect that scanmap + letsimp won't be able to handle all such problems in one pass. In this case, however, I find that scanmap(letsimp, sin(x*x), bottomup) yields y as expected. See ? scanmap for some description of the bottomup flag.Sclater
E
4

You can try optimize

http://maxima.sourceforge.net/docs/manual/en/maxima_6.html#IDX219

(%i14) example(optimize);

(%i15) diff(exp(y+x^2)/(y+x),x,2)
                        2            2              2            2
               2   y + x        y + x          y + x        y + x
            4 x  %e         2 %e         4 x %e         2 %e
(%o15)      ------------- + ---------- - ------------ + ----------
                y + x         y + x               2             3
                                           (y + x)       (y + x)
(%i16) optimize(%)
                                                 2         y + %2       1
(%o16) block([%1, %2, %3, %4], %1 : y + x, %2 : x , %3 : %e      , %4 : --, 
                                                                        %1
                                                                 4 x %3   2 %3
                                          4 %2 %4 %3 + 2 %4 %3 - ------ + ----)
                                                                    2       3
                                                                  %1      %1
Exarate answered 27/3, 2014 at 11:12 Comment(3)
Nice! But suppose you want to avoid a verbose replacement (subjective), say %2 : x^2, how can you obtain that? Indeed, in my real expression I'm actually interested in just 2 out of 16 replacements suggested by optimize.Bindweed
And what if you know in advance the substitutions you need (as in my question), and you just want Maxima to apply them to a complex expression?Bindweed
In this case @RobertDodier gives a better suggestion.Exarate

© 2022 - 2024 — McMap. All rights reserved.