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?
LetL
is defined as? $\endgroup$Experimental`OptimizeExpression
on your expression? A few refs: (25136), (31614), (32097), (58985) $\endgroup$Experimental
OptimizeExpression` 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 toOptimizeExpression
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. $\endgroup$