4
$\begingroup$

I don't know how to fix this problem:

In[175]:= test = Compile[{{x, _Real}}, If[Sin[x] > 0.1, Tan[x], 0]];
FindMinimum[test[x], {x, 1.}, WorkingPrecision -> MachinePrecision]

During evaluation of In[175]:= CompiledFunction::cfsa: Argument x at position 1 should be a machine-size real number. >>

Out[176]= {0., {x -> -1.02705}}

I understand why it's complaining. But I need to use compile as my function has many lines with all sorts of comditionals. Speed is important. Stuck with this optimization step of FindMinimum. Any idea how to fix it without derailing up Compile?

$\endgroup$
3
  • 3
    $\begingroup$ Indeed a duplicate. But there is a different problem too with your compiled function: it is not really compiled. That's because the "else" branch of the If is missing, which is forcing Mathematica to resort to non-compiled evaluation to handle it. To understand why, consider what would happen if Sin[x] < 0.1. Search this site for CompilePrint to see how to diagnose the problem. Use something like If[Sin[x] > 0.1, Tan[x], 0] to fix it. $\endgroup$
    – Szabolcs
    Commented Nov 2, 2015 at 8:46
  • $\begingroup$ But creating an additional function is the only way? Isn't it going to slow down everything? $\endgroup$
    – Al Guy
    Commented Nov 2, 2015 at 8:47
  • $\begingroup$ You should test, but I don't think so. That additional layer should add very little overhead. If that overhead does really make a significant difference, relative to the execution time of the compiled function, then it is quite possible that compilation didn't help anyway ... In this case compilation is most helpful if test takes a non-trivial amount of time uncompiled. But actually: you don't need to create an additional function. You can just ignore the error. It won't affect the result. $\endgroup$
    – Szabolcs
    Commented Nov 2, 2015 at 9:16

1 Answer 1

3
$\begingroup$

I suggest altering the definition of test as follows:

test = Compile[{{x, _Real}},
  If[Sin[x] > 0.1, Tan[x], 0.], 
  "RuntimeOptions" -> "EvaluateSymbolically" -> False
 ];

Note that the 0 third argument of If is changed to 0.. While it seems to compile correctly anyway for this particular example, my experience has been that Compile can sometimes fail to correctly cast types, and this may be the case in your larger function. So, I personally prefer to make these explicit, i.e. not to write an integer where a real-typed register is going to hold the result. To expand on Szabolcs's comment, if nothing is given as the third argument then it is an implicit Null. This is of type Void, which cannot be cast to a real, and so will guarantee a failure to compile.

The other option performs as a close functional analog of a _?NumericQ pattern test in the definition, as it is shown in the linked question.

$\endgroup$

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