## Using a compiled function inside NIntegrate gives "CompiledFunction::cfsa" message

25

12

The following function is defined for Real input:

FFc = Compile[{{x, _Real}, {EF, _Real}},If[x > EF, 0., If[x == EF, 0.5, 1.]]]


FFc is now used in the function called foo:

EBoundary = 6.5;
foo[Ef_?NumericQ] := NIntegrate[FFc[x, Ef] , {x, -EBoundary, EBoundary}]


When I call foo like

foo[3.2]


I get an error message:

CompiledFunction::cfsa: "Argument x at position 1 should be a machine-size real number.


Since I'm using real numbers I have no idea why I get this message. What is the problem? Is it because If[] can return 0?

20

It's because FFc is being passed x and Ef symbolically, at first. To cure the problem, add an intermediate function between FFc and NIntegrate, such as

f[x_?NumericQ, Ef_?NumericQ] := FFc[x,Ef]


then

foo[Ef_?NumericQ] := NIntegrate[f[x, Ef] , {x, -EBoundary, EBoundary}]


A same trick has been applied in this question, too. http://mathematica.stackexchange.com/q/40755/5943

– saturasl – 2014-03-09T21:41:44.177

I am worried that this solution might affect the performance boost that Compile is supposed to give. I am referring to the _?NumericQ pattern matching. Isn't there a more direct solution? Perhaps in Math 10? – becko – 2014-10-21T15:42:10.703

@becko have you tried it with and without NumericQ? That is the only way to tell definitively. But, I suspect the speed hit will be marginal. – rcollyer – 2014-10-21T15:47:35.560

What effect does the introduction of an interim function have on performance? Is there another solution? – Doug Kimzey – 2016-04-29T18:31:50.573

@DougKimzey honestly, I don't know if it has much effect on performance, but relative to NIntegrate, I don't expect it to be very large. That said, you can turn off symbolic processing in NIntegrate by setting Method -> {Automatic, "SymbolicProcessing" -> 0}.

– rcollyer – 2016-04-29T18:48:38.447

4Do you perhaps know why adding "RuntimeOptions" -> {"EvaluateSymbolically" -> False} to FFc does not cure the problem? – Ajasja – 2013-01-18T09:40:31.483

1@Ajasja Seems related to why FFc[-x,0.] gives error while FFc[x,0.] doesn't. I wonder why NIntegrate passes -x as argument to the function. (This comment is assuming {"EvaluateSymbolically" -> False}) – ssch – 2013-01-18T12:20:40.930

@Ajasja Seems if the integration region is {x,-a,a} it doesn't work, while it is unsymmetric like {x,-a-0.00001,a} it does – ssch – 2013-01-18T12:26:09.307

@Ajasja no idea. Compile is not my strong suit. – rcollyer – 2013-01-18T13:14:47.030

Thanks. Perhaps @OleksandR will see this:) – Ajasja – 2013-01-18T13:47:24.557

11

Do you perhaps know why adding "RuntimeOptions" -> {"EvaluateSymbolically" -> False} to FFc does not cure the problem?

This is due to the fact that the methods inside NIntegrate[] (attempt to) perform a preliminary symbolic analysis, which can be helpful for integrands composed of built-in mathematical functions, but not terribly useful for compiled functions. Thus, one has to turn it off in this case, in addition to enabling the compilation options mentioned by Ajasja.

Here is a quick demonstration:

FFc = Compile[{{x, _Real}, {EF, _Real}},
If[x > EF, 0., If[x == EF, 0.5, 1.]],
"RuntimeOptions" -> {"EvaluateSymbolically" -> False}];


With the default setting, we get this (Mathematica 10.4):

NIntegrate[FFc[x, 3.2], {x, -6.5, 6.5}]

CompiledFunction::cfsa: Argument -x at position 1 should be a machine-size real number.
CompiledFunction::cfsa: Argument -x at position 1 should be a machine-size real number.
NIntegrate::slwcon: Numerical integration converging too slowly; suspect one of the
following: singularity, value of the integration is 0, highly oscillatory integrand, or
WorkingPrecision too small.
NIntegrate::ncvb: NIntegrate failed to converge to prescribed accuracy after 9
recursive bisections in x near {x} = {3.22441}. NIntegrate obtained 9.699759342263453
and 0.0005405922634428764 for the integral and error estimates.


before 9.69976 is returned. In contrast, if we disable symbolic processing like so:

NIntegrate[FFc[x, 3.2], {x, -6.5, 6.5}, Method -> {Automatic, "SymbolicProcessing" -> 0}]

NIntegrate::slwcon: Numerical integration converging too slowly; suspect one of the
following: singularity, value of the integration is 0, highly oscillatory integrand, or
WorkingPrecision too small.
NIntegrate::ncvb: NIntegrate failed to converge to prescribed accuracy after 9
recursive bisections in x near {x} = {3.22441}. NIntegrate obtained 9.699759342263453
and 0.0005405922634428764 for the integral and error estimates.


we no longer get the CompiledFunction::cfsa message.

Nice find and explanation. – rcollyer – 2016-03-30T12:43:16.877

@rcollyer, I think this was asked during one of my hiatuses, so I had missed it until Jason linked to it in another question. :) – J. M.'s ennui – 2016-03-30T13:10:22.410

1For some reason it does not work in M11.1 or 11.2 – luu – 2017-10-05T05:35:37.160

Using f1p11 = Compile[{{p, _Real, 1}, {pq, _Real, 1}, {pqq, _Real, 1}}, E^-(#.# &[p + pq/2 - pqq/2]), CompilationTarget -> "C", RuntimeOptions -> {"Speed", "EvaluateSymbolically" -> False}] and NIntegrate[ f1p11[{px, py}, {1, 1}, {2, 2}], {px, py} \[Element] BoundaryDiscretizeRegion[Disk[{1, 1}/2 - {2, 2}/2, 3]], Method -> {"MonteCarlo", "SymbolicProcessing" -> 0, Method -> {"MonteCarloRule", "Points" -> 500}}, PrecisionGoal -> 3] <br/> I get CompiledFunction::cfta: Argument {px,py}... – luu – 2017-10-05T05:44:21.240

@luu, I don't have a C compiler to verify your observations; 2. IIRC special handling is done for geometric integrals (i.e. those involving regions). This answer is mostly intended to explain the univariate case. Consider asking a new question if this is still troubling you.

– J. M.'s ennui – 2017-10-13T04:44:37.757

Sometimes life can be so easy, thank you for this comment. I also stumbled over this tiny little problem. – Display Name – 2018-12-13T17:30:46.353