8

If I use FullSimplify on a large formula it will consequently return a much smaller expression. However, suppose I notice the simplified expression can benefit from further intermediate definitions. For example, say I observe c = (1-a)(1-b), would make my expression drastically smaller.

Instead of spending time to try such substitutions, does Mathematica have functionality to perform this work for me? More particularly, how would I find optimal sub-expressions to simplify the following expression?

(1/(a^2 (b + m)))(-(-1 + a + 2 b) (-1 + 2 b + 2 m) - 4 b ArcTanh[1 - 2 b] + Log[4] + 2 ((2 + a) b + m + a m) Log[1 + a] - a (b + m) Log[4 - 4 b] + a Log[(2 - 2 b)/(1 + a)] - m Log[1 - b] + 2 Log[(1 - b)/(1 + a)] + (m - a (b + m)) Log[b])
gpap
  • 9,707
  • 3
  • 24
  • 66
user120911
  • 2,655
  • 9
  • 18
  • 1
    Probably not out of the box. However, there are further techniques that you could use to nudge MMA in the right direction, but we would absolutely need a practical example of an expression that displays these properties in order to give you a more specific answer. – MarcoB Sep 13 '18 at 14:23
  • 4
    Experimental`OptimizeExpression can look for common subexpressions, but it won't change the way the expression is written to expose more such subexpressions. I believe it is meant for speeding up computations (avoid computing the same thing twice), not for simplification. BTW +1, I wished for such a feature many times. – Szabolcs Sep 13 '18 at 14:48
  • @MarcoB, I provided an example that FullSimplify cannot reduce further, but where I can see the module a(b + m). – user120911 Sep 13 '18 at 17:46
  • Compile[] is also able to find common subexpressions if the whole expression is compilable in general. The resulting CompiledFunction contains a list of imperative program steps that is equal to the original expression. – Thies Heidecke Sep 17 '18 at 16:46

2 Answers2

5

Note, that if you just propose Mathematica additional equalities, it will give them try:

f = (1/(a^2 (b + m))) (-(-1 + a + 2 b) (-1 + 2 b + 2 m) - 
    4 b ArcTanh[1 - 2 b] + Log[4] + 
    2 ((2 + a) b + m + a m) Log[1 + a] - a (b + m) Log[4 - 4 b] + 
    a Log[(2 - 2 b)/(1 + a)] - m Log[1 - b] + 
    2 Log[(1 - b)/(1 + a)] + (m - a (b + m)) Log[b]);



In[6]:= 
LeafCount[f]
fs = FullSimplify[f, {c == 1 + a}];
LeafCount[fs]


Out[6]= 114

Out[8]= 90

Sometimes you can make a good guess from the additional information you have about you problem (in physics you often do).

One way to find repeating sub expressions:

SortBy[Select[
  Tally[Level[f, -1]],
  LeafCount[First[#]] > 3 &
], Last][[-3 ;;]] // Column

enter image description here

Johu
  • 4,918
  • 16
  • 43
2

Compile[] is also able to find common subexpressions if the whole expression is compilable in general. The resulting CompiledFunction contains a list of imperative program steps that is equal to the original expression.

expr = (1/(a^2 (b+m))) (-(-1+a+2 b) (-1+2 b+2 m)-
       4 b ArcTanh[1-2 b]+Log[4]+2 ((2+a) b+m+a m) Log[1+a]-
       a (b+m) Log[4-4 b]+a Log[(2-2 b)/(1+a)]-m Log[1-b]+
       2 Log[(1-b)/(1+a)]+(m-a (b+m)) Log[b]);

cf = Compile[{{a, _Real}, {b, _Real}, {m, _Real}}, Evaluate@expr]

Clicking on the + symbol reveals the generated code:

View of compiled function

This expression can also be found as second to last part of the CompiledFunction expression:

cf[[-2]]

Function[{a, b, m}, 
 Block[{Compile`$5, Compile`$2, Compile`$21, Compile`$28, Compile`$33,
    Compile`$34}, Compile`$5 = -2 b; Compile`$2 = b + m; 
  Compile`$21 = 1 + a; Compile`$28 = 1/Compile`$21; Compile`$33 = -b; 
  Compile`$34 = 1 + Compile`$33; (1/(
  a^2 Compile`$2))((1 - a + Compile`$5) (-1 + 2 b + 2 m) - 
    4 b ArcTanh[1 + Compile`$5] + Log[4] + 
    2 ((2 + a) b + m + a m) Log[Compile`$21] - 
    a Compile`$2 Log[4 - 4 b] + a Log[Compile`$28 (2 + Compile`$5)] - 
    m Log[Compile`$34] + 
    2 Log[Compile`$28 Compile`$34] + (m - a Compile`$2) Log[b])]]
Thies Heidecke
  • 8,814
  • 34
  • 44