This question is tightly related to the answer Shaving the last 50 ms off NMinimize.
There @OleksandR shows how inlined closures can be used to eliminate calls to MainEvaluate. This is crucial for my application, since I need every last drop of performance mma can offer. Here is an extremely simplified working example (before you run this code, make sure to evaluate this package, containing the NelderMeadMinimize code):
Needs["CompiledFunctionTools`"]
With[{minimizer =
NelderMeadMinimize`Dump`CompiledNelderMead[
Function[{a, b, c}, (a - d1)^2 + (b - d2)^2 + (c - d3)^2], {a, b, c},
"ReturnValues" -> "OptimizedParameters"],
epsilon = $MachineEpsilon},
orgFitter =
Compile[{{d1, _Real, 0}, {d2, _Real, 0}, {d3, _Real, 0}},
minimizer[RandomReal[{0, 1}, {3 + 1, 3}], epsilon, -1],
CompilationOptions -> {"InlineCompiledFunctions" -> True},
RuntimeOptions -> {"Speed", "EvaluateSymbolically" -> False}]];
StringMatchQ[CompilePrint[orgFitter], "*MainEvaluate*"]
(* -> False *)
orgFitter[12, 2, 3]
Now, if I change (a - d1)^2 + (b - d2)^2 + (c - d3)^2 to calling a compiled function the calls to MainEvalute are not eliminated! Please, instead of the simple myHi2 imagine a monster of a compiled procedure containing several hundred lines.
myHi2 = Compile[{{a, _Real, 0}, {b, _Real, 0}, {c, _Real,
0}, {d1, _Real, 0}, {d2, _Real, 0}, {d3, _Real,
0}}, (a - d1)^2 + (b - d2)^2 + (c - d3)^2];
With[{minimizer =
NelderMeadMinimize`Dump`CompiledNelderMead[
Function[{a, b, c}, myHi2[a, b, c, d1, d2, d3]], {a, b, c},
"ReturnValues" -> "OptimizedParameters"],
epsilon = $MachineEpsilon},
orgFitter =
Compile[{{d1, _Real, 0}, {d2, _Real, 0}, {d3, _Real, 0}},
minimizer[RandomReal[{0, 1}, {3 + 1, 3}], epsilon, -1],
CompilationOptions -> {"InlineCompiledFunctions" -> True,
"InlineExternalDefinitions" -> True},
RuntimeOptions -> {"Speed", "EvaluateSymbolically" -> False}]];
StringMatchQ[CompilePrint[orgFitter], "*MainEvaluate*"]
(* -> True *)
orgFitter[12., 2., 3.]
How can I eliminate this calls to MainEvaluate?
Also, could someone help me understand, why this does not compile:
orgFitter = Compile[{{d1, _Real, 0}, {d2, _Real, 0}, {d3, _Real, 0}},
With[{minimizer =
NelderMeadMinimize`Dump`CompiledNelderMead[
Function[{a, b, c}, (a - d1)^2 + (b - d2)^2 + (c - d3)^2], {a,
b, c}, "ReturnValues" -> "OptimizedParameters"],
epsilon = $MachineEpsilon},
minimizer[RandomReal[{0, 1}, {3 + 1, 3}], epsilon, -1]],
CompilationOptions -> {"InlineCompiledFunctions" -> True,
"InlineExternalDefinitions" -> True},
RuntimeOptions -> {"Speed", "EvaluateSymbolically" -> False}];
CompilePrint[orgFitter]
Withblock would inject the minimize inside theCompileblock before anything else happens, so that myHi2 would effectively appear insideCompile. Well obviously I was wrong and it's not that simple:) – Ajasja Oct 19 '12 at 13:48Compileon the outside. Do you think it would be possible to useInternalCompileValuesto makeNelderMeadMinimizeDumpCompiledNelderMead` compilable? (asking purely out of curiosity, since you have already presented 3 solutions to my problem:) – Ajasja Oct 19 '12 at 13:52Withdid successfully inject the minimizer into the compiled code--but you hadn't followed that through to its logical conclusion and injectedmyHi2into the minimizer (remember,FunctionisHoldAlltoo). Once you've dealt with all the dependencies, everything should work out automatically. BTW, I forgot to mention that inlining like this avoids the need forCompilationOptions -> "InlineCompiledFunctions" -> Truein all cases (AFAIK) except that of compiled closures, which won't work otherwise (and also aren't supported prior to version 8). – Oleksandr R. Oct 21 '12 at 03:04Internal`CompileValuesgoes, the answer is probably yes but I'm not certain how to do it. These values are only looked at fairly deep insideCompileand after a lot of preprocessing has already been done, so I don't really know exactly what's supported using this mechanism. The functionInternal`CompileInlineprobably has something to do with what you're after, but I've no idea how to use it. – Oleksandr R. Oct 21 '12 at 03:10