14
$\begingroup$

I want to compile a variety of commands, including a function. I need to map this function, inside the compilation, and I can't include the function without facing errors such as "CompiledFunction::cfex: Could not complete external evaluation at instruction 27; proceeding with uncompiled evaluation."

The code finds the root of a function, it's a complicated way to do it but as I want to compute roots of complicated functions I can't simply use FindRoot.

For simplicity I'll include an example in which I try to evaluate the root of $y^3+5y^2−5$, such as 0.919089. Note that the problem is in the line "gg[y_] = y^3 + 5 y^2 - 5;"

Raiz = Compile[{{xmin, _Real}, {xmax, _Real}, {npts, _Real}},
  Module[{xrange, tab, par, roots, pos, xtab, xt, xmin2, xmax2, xmed},
    xrange = With[{d1 = N@xmin, d2 = N@xmax},
      d1+(d2-d1)/(npts-1) Range[0,npts-1]];
  gg[y_] = y^3 + 5 y^2 - 5;
  tab = Map[gg, xrange];
  par = Partition[tab, 2, 1];
  roots = Flatten@Select[par, NonPositive[Times @@ #] &];
  pos = Flatten[Position[tab, #] & /@ roots];
  xtab = Partition[xrange[[pos]], 2];
  Table[
    xmin2 = xt[[1]]; xmax2 = xt[[2]];
      Do[
        xmed = N@(xmax2 + xmin2)/2;
        If[Sign[gg[xmin2] gg[xmed]] == 1, xmin2 = xmed, xmax2 = xmed];
      ,npts];
    (xmin2 + xmax2)/2
  , {xt, xtab}]
 ]
]

Sorry if it's a duplicate, I couldn't find any answer for my problem.

$\endgroup$
13
$\begingroup$

This is covered by the 3rd rule in this post:

Compiled evaluation can't work with patterns… Notice that function definition like f[x_] = … or f[x_] := … also uses pattern so they can't be compiled.

So, how to circumvent? There exist at least 2 types of possible approaches.

  1. As mentioned by halirutan, define the function gg as another compiled function outside and then introduce it with With or "InlineExternalDefinitions" -> True.

    Notice the "InlineCompiledFunctions" -> True option isn't actually necessary to make the code fully compiled. "InlineCompiledFunctions" -> False will just lead to a CompiledFunctionCall, which isn't slow. Of course, sometimes inlining the compiled function manually speeds up the code, but not always, see here for an example.

    Instead of compiled function, one can also define gg as a pure function (Function), see here for an example.

  2. Meta-programming based on pattern-matching:

    gg[y_] = y^3 + 5 y^2 - 5;
    cf = ReleaseHold[Hold@Compile[{{list, _Real, 1}}, Map[gg[#]&, list]] /. DownValues@gg]
    

    Notice I've rewrite Map[gg, …] to Map[gg[#]&,…, or Downvalues@gg won't match it. As to the advantage of this approach, see here for one example.

$\endgroup$
9
$\begingroup$

That is a weak point of Mathematica. We have questions here that explain how to include other compiled functions into a compiled function. For your specific case you could use something along this line:

gg = Compile[{{y, _Real, 0}},
   y^3 + 5 y^2 - 5
   ];

With[{gg = gg},
 fc = Compile[{{list, _Real, 1}},
   Map[gg, list],
   CompilationOptions -> {"InlineCompiledFunctions" -> True}
   ]
 ]

This creates a real inlined function and you should be aware of this. The body of the function gg, meaning the y^3 + 5 y^2 - 5 par, is copied at each place you are calling gg inside fc.

For small functions gg, the option "InlineCompiledFunctions" -> True is not necessary. For larger functions gg, if you don't set this option, you will get a CompiledFunctionCall inside fc.

The crucial part of understanding is, that inlining a function means that your final fc might become very large because it will contain a copy of gg at every place where you call it. Be aware of that.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.