6

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

?

mmj
  • 5,514
  • 2
  • 44
  • 51

2 Answers2

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.

Robert Dodier
  • 16,905
  • 2
  • 31
  • 48
  • 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? – mmj Mar 27 '14 at 22:08
  • 5
    @mmj Try `scanmap(letsimp, expr)`. – Robert Dodier Mar 27 '14 at 22:35
  • 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. –  May 07 '18 at 01:59
  • 1
    @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. – Robert Dodier May 07 '18 at 03:46
  • 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. –  May 07 '18 at 20:13
  • @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. – Robert Dodier May 08 '18 at 18:30
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
slitvinov
  • 5,693
  • 20
  • 31
  • 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`. – mmj Mar 27 '14 at 15:45
  • 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? – mmj Mar 27 '14 at 16:06
  • In this case @RobertDodier gives a better suggestion. – slitvinov Mar 27 '14 at 22:55