FAQ
overflow

Great Answers to
Questions About Everything

QUESTION

I am working with some unpleasantly tedious polynomials, which need to be manipulated in various ways (integrate with respect to some variable, differentiate with respect to another). Since these will eventually be part of numeric routines, I'd like to pull out common subexpressions that I can reuse, e.g.

(G u^2 (6 p (2 h + p) - 8 (h + p) u + 3 u^2))/(12 h^2)
(G (3 h + 3 p - 2 u) u^2)/(3 h^2)

should at least note that both have a common factor of

(G u^2)/(3 h^2)

Is there a convenient way to instruct Mathematica to look for this sort of computational-expense-reduction in pairs of expressions? Ideally it would notice even in the case where it's not just a factor multiplied by both, e.g. if I added + 1 to the second equation, I'd still like it to find that common subexpression.


Just for clarification, this is what I do by hand:

e1 = (G u^2)/(12 h^2) * (6 p (2 h + p) - 8 (h + p) u + 3 u^2))
e2 = (G u^2)/( 3 h^2) * (3 h + 3 p - 2 u)

A = (G u^2)/(12 h^2)
e1 = A * (6 p (2 h + p) - 8 (h + p) u + 3 u^2))
e2 = A * (12 (h + p) - 6 u)

B = u^2
C = h + p
A = (G B)/(12 h^2)
e1 = A * (6 p (2 h + p) - 8 C u + 3 B)
e2 = A * (12 C - 6 u)

to go from 6 additions, 20 multiplications, 2 divisions, and 2 assignments, to 5 additions, 14 multiplications, 1 division, and 5 assignments (the extra three of which are temporary so can be in registers and cost essentially nothing).

{ asked by Rex Kerr }

ANSWER

The engine behind this inside Compile is a well-hidden function called OptimizeExpression. it has two levels, 1 and 2. Setting to 2 makes it work harder to find CSEs.

e1 = (G u^2 (6 p (2 h + p) - 8 (h + p) u + 3 u^2))/(12 h^2);
e2 = (G (3 h + 3 p - 2 u) u^2)/(3 h^2);

Experimental`OptimizeExpression[{e1, e2}, 
 OptimizationLevel -> 2]

(* Out[40]= Experimental`OptimizedExpression[
 Block[{Compile`$7, Compile`$9, Compile`$10}, Compile`$7 = h^2; 
  Compile`$9 = 1/Compile`$7; 
      Compile`$10 = 
   u^2; {1/12 G Compile`$9 Compile`$10 (6 p (2 h + p) - 8 (h + p) u + 
          3 Compile`$10), 
   1/3 G Compile`$9 (3 h + 3 p - 2 u) Compile`$10}]] *)

{ answered by Daniel Lichtblau }
Tweet