# Best approach for 'manual' common subexpression elimination

I have working code, but am looking for ways to make it more elegant.

I have a fairly large expression with plenty of repetition and structure. A shortened toy example is

expr = (a/(a + b))^4.5  + (b/(a + b))^3.5 +
(a/(a + b))^1.5 + Cosh[a + b]  +
Log[a/(a + b)] + Log[b/(a + b)]


I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
a + b -> sum,
a/sum -> g,
b/sum -> h}


In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :>
Symbol[StringJoin["\$δd", StringJoin[ToString /@ l], "x", ToString[i]]]


The simplified expression, and the actual set of replacements is provided by the following function:

replaceone[expr_, rule_] := Block[{newtemps, unique},
unique = Union@Cases[expr, rule[[1]], Infinity];
newtemps = Thread[(unique /. rule) -> unique];
Sow[newtemps];
expr /. rule
]
{newekspr, temps} = Reap[Fold[replaceone, expr, rules]]
temps = Association[temps]


I can then prepare a function for efficient evaluation of the expression, like this, with a nested Block.

exprfun[av_, bv_] :=
Block[{a = av, b = bv},
Block[Evaluate[Keys[temps]], KeyValueMap[Set, temps];
newekspr]]


I can Compile this function, although I suspect that the result is that the entire expression is expanded and simplified again.

Compile[{a, b}, Evaluate[exprfun[a, b]]]


Is this the best way of doing this?

Can I write a higher order function that takes my original expression, and a rules set, simplifies it and provides a optimised, and possibly compiled function?

What is the benefit of a nested With, and LetL, that I have seen elsewhere, compared with this approach?

• And LetL is defined as? – Daniel Lichtblau Mar 10 '16 at 15:50
• Next time, when using a function obtained from another post on this site, please link to the original post. – J. M. is away Mar 10 '16 at 16:32
• @J.M. Yes, of course. Thanks for correcting. – Åsmund Hj Mar 10 '16 at 18:51
• Have you tried ExperimentalOptimizeExpression on your expression? A few refs: (25136), (31614), (32097), (58985) – Michael E2 Mar 13 '16 at 17:07
• @MichaelE2 My first attempts on ExperimentalOptimizeExpression failed, but I tried it again on a smaller problem, and now it works. Don't know why. Still, it seems a bit inelegant to let the expression explode in complexity, for then to leave to OptimizeExpression to clean up afterwards. My expression, with an original leafcount of around 150 000 is now calculated in 13 ns, compared to 28ms before compilation. Still, I would really like to use the manual rules as well, as these intermediary results are interesting by their own as well. – Åsmund Hj Mar 13 '16 at 17:37