As halirutan comments Dispatch
will speed the application of long lists of rules:
SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]
n = 1500;
big = Sum[Expand[(RandomInteger[99] + a[i])^RandomInteger[9]], {i, n}];
vals = RandomInteger[9999, n];
rules = Thread[Array[a, n] -> vals];
big /. rules // timeAvg
big /. Dispatch[rules] // timeAvg
0.936
0.008608
Somewhat faster, you could convert your entire expression into an anonymous Function
one time, and Apply
it to your list of values:
big2 = Function @@ {big} /. Dispatch@Thread[Array[a, n] -> Array[Slot, n]];
big2 @@ vals // timeAvg
0.004496
For variety, if all of the expressions to replace are Symbols you could use a variation of listWith
from this post. It is between the two others in speed in this test.
syms = Table[Symbol["a" <> ToString@i], {i, n}];
big3 = big /. Dispatch@Thread[Array[a, n] -> syms];
SetAttributes[listBlock, HoldAll];
listBlock[(set : Set | SetDelayed)[L_, R_], body_] :=
Inner[set, L, R, Hold] /. _[x__] :> Block[{x}, body]
listBlock[syms = vals, big3] // timeAvg
0.005368
This has the advantage of keeping your expression in the normal form rather than turning it into a Function
.
Optimizing the expression
In light of the nature of the actual expression which contains a number of repeated sub-expressions we can improve the performance a bit by exploiting this commonality. An internal function exists that attempts this automatically: Experimental`OptimizeExpression
. You can search the site for "OptimizeExpression" for more details and other examples of use.
With your full expression assigned to fullAE
:
vars = Variables@Level[fullAE, {-1}];
rules = MapIndexed[Function[{a, b}, a -> Slot[b[[1]]]], vars];
func = Function @@ {fullAE} /. rules;
optimized = Experimental`OptimizeExpression[fullAE];
funcOptimized = Function @@ optimized /. rules;
values = RandomInteger[99, 12];
Timings for the incrementally faster methods:
fullAE /. Thread[vars -> values] // timeAvg
fullAE /. Dispatch@Thread[vars -> values] // timeAvg
func @@ values // timeAvg
funcOptimized @@ values // timeAvg
0.00324
0.0022208
0.001048
0.0006752
Dispatch
? $\endgroup$