I'm minimizing a large function. Evaluating the function is very slow symbolically but using Compile I can get ~100x speed-up on this step. However, despite this, the NMinimize process is only marginally faster for large equations, and very much slower for small ones.
Is there a way to pass NMinimize the information it would normally get from a symbolic function but in compiled form? An example in this would be passing the function and its Jacobian to a root finder, avoiding the need to use finite differences.
Here is the example I'm working on. Any comments/pedantry as to how I've written this would also be appreciated; I still have no idea about the best ways to do things, and have trouble forcing/maintaining consistency.
centralangle[{q1_, p1_}, {q2_, p2_}] :=
ArcCos[Sin[q1] Sin[q2] + Cos[q1] Cos[q2] Cos[p1 - p2]];
energy[qp_, i_, max_] :=
Sum[If[s == i, 0, (centralangle[qp[[i]], qp[[s]]])^-1], {s, 1, max}];
totalenergy[qp_, max_] := Sum[energy[qp, i, max], {i, 1, max}]/2;
Now test this for 10 particles, and I find the symbolic minimization to be ~6x faster
ClearAll[q, p]
max = 10;
qp = Table[Unique[{q, p}], {max}];
qpFlat = Flatten[qp];
eqn = totalenergy[qp, max];
ceqn = Compile[Evaluate[{#, _Real} & /@ qpFlat], Evaluate[eqn],
"RuntimeOptions" -> {"EvaluateSymbolically" -> False}];
Timing[
NMinimize[eqn, qpFlat];
]
Timing[
NMinimize[ceqn[Sequence @@ qpFlat], qpFlat];
]
{0.374402, Null}(symbolic)
{2.246414, Null}(compiled)
Although for 100 particles, I find single evaluations ~100x faster when compiled
ClearAll[q, p]
max = 100;
qp = Table[Unique[{q, p}], {max}];
qpFlat = Flatten[qp];
eqn = totalenergy[qp, max];
ceqn = Compile[Evaluate[{#, _Real} & /@ qpFlat], Evaluate[eqn],
"RuntimeOptions" -> {"EvaluateSymbolically" -> False}];
init = RandomReal[1., 2 max];
Timing[
eqn /. Table[qpFlat[[i]] -> init[[i]], {i, 1, 2 max}];
]
Timing[
ceqn[Sequence @@ init];
]
{1.279208, Null}(symbolic)
{0.015600, Null}(compiled)
The minimization for 100 particles is overall 1.5x faster for the compiled function, clearly as a trade-off between whatever is going on here.
NMinimize
) rather than local (FindMinimum
)? Any information you have such as good initial guesses will help speed up the problem. $\endgroup$NMinimize
does not require (and cannot accept) gradients. All its methods are direct search algorithms; there is no more information required than a black box function. If the Nelder-Mead method would be sufficient for you, perhaps you might like to try a compiled implementation of that. $\endgroup$