Given that the documentation for FindMinimum uses ReplaceAll for its various examples of what to do with the found solution to an optimization problem, it would seem to be the right tool for the job. However, the following MWE highlights the speed problem I ran into using ReplaceAll for such a situation. Is using Block the appropriate tool in this case and why?
vars = Table[f[i], {i, 1, 10000}];
vals = RandomReal[1, Length[vars]];
soln = MapThread[#1 -> #2 &, {vars, vals}];
Total[vars] /. soln // Timing
(*{1.395787, 4980.51}*)
Block[{f},
ReleaseHold[
MapThread[Hold[#1 = #2] &, Transpose[List @@ # & /@ soln]]];
Total[vars]] // Timing
(*{0.033995, 4980.51}*)
A slight variation on the Block approach, which I expect would be equivalent, is also slightly slower (here both have been repeated 1000 times to show the less-significant difference of ~20%). Is there another approach that would achieve the same but faster?
Do[Block[{f},
ReleaseHold[
MapThread[Hold[#1 = #2] &, Transpose[List @@ # & /@ soln]]];
Total[vars]], {1000}]; // Timing
(*{26.072036, Null}*)
Do[Block[{f}, (Set @@ # &) /@ (List @@ # & /@ soln);
Total[vars]], {1000}]; // Timing
(*{31.651188, Null}*)
Further testing has found that the problem is exasperated by "bigger" expressions than Total, in particular by the use of ListInterpolation. This appears to be resolved by only Replacing at the right level, which works in this particular example because all the variables have the same levelspec ({-2} or {3}).
vars = Table[f[i], {i, 1, 10000}];
vals = RandomReal[{-1, 1}, Length[vars]];
soln = MapThread[#1 -> #2 &, {vars, vals}];
i = ListInterpolation[RandomReal[1, 40], {-1, 1},
"ExtrapolationHandler" -> {(0 &), "WarningMessage" -> False}];
expr = Plus @@
MapThread[Times, RotateLeft[i@vars, #] & /@ Range[0, 4]];
expr /. Dispatch[soln] // Timing
(*{2.504619, 309.407}*)
Replace[expr, Dispatch[soln], {-2}] // Timing
(*{0.124981, 309.407}*)
Block[{f},
ReleaseHold[
MapThread[Hold[#1 = #2] &, Transpose[List @@ # & /@ soln]]];
expr] // Timing
(*{0.146978, 309.407}*)
In the actually problem I am facing, not all the variables have the same levelspec, so it seems to require the range {-2,-1}, which ends up taking slightly longer than Block.
soln = Dispatch[MapThread[#1 -> #2 &, {vars, vals}]];– ilian May 20 '15 at 02:38Dispatch[]is quite invaluable if you have a lot of replacement rules. – J. M.'s missing motivation May 20 '15 at 02:52Dispatch:(soln = AssociationThread[vars, vals]; Total[vars] /. soln) // AbsoluteTiming. – Michael E2 May 20 '15 at 03:19Lookupfaster still in this case; reference: (55980) – Mr.Wizard May 20 '15 at 03:26