1
$\begingroup$

Problem

I have a compiled function that I want to use in an equation given to NSolve. I can get the code to run, but it first produces warning messages that result from NSolve trying to evaluate the function with symbolic arguments. I want to prevent that attempt from happening.

To demonstrate the problem and avoid unrelated details of my application, I've created a compiled version of the Beta function.

Clear[myBetaV1];
myBetaV1 = Compile[{{alpha, _Real}, {beta, _Real}},
   Exp[LogGamma[alpha] + LogGamma[beta] - LogGamma[alpha + beta]],
   CompilationTarget -> "C"];

Now suppose I want to solve the equation

NSolve[Beta[5, 3] == myBetaV1[a, 3], a, Reals]
(*CompiledFunction::cfsa: Argument a at position 1 should be a machine-size real number.
NSolve::fexp: Warning: NSolve used FunctionExpand to transform the system. Since FunctionExpand transformation rules are only generically correct, the solution set might have been altered.
{{a -> 5.}}*)

The first message, about a machine-size real number, happens because the symbol a in myBetaV1[a,3] is not a machine-size real number.

Attempted solutions

1) Include Method -> {Automatic, "SymbolicProcessing" -> 0} as an option given to NSolve

NSolve[Beta[5, 3] == myBetaV1[a, 3], a, Reals, 
 Method -> {Automatic, "SymbolicProcessing" -> 0}]
(*CompiledFunction::cfsa: Argument a at position 1 should be a machine-size real number.
NSolve::fexp: Warning: NSolve used FunctionExpand to transform the system. Since FunctionExpand transformation rules are only generically correct, the solution set might have been altered.
{{a -> 5.}}*)

That option doesn't appear to change anything.

2) Use RuntimeOptions -> {"EvaluateSymbolically" -> False} as an option when creating the compiled function, and try in combination with attempt 1.

Clear[myBetaV2];
myBetaV2 = Compile[{{alpha, _Real}, {beta, _Real}},
   Exp[LogGamma[alpha] + LogGamma[beta] - LogGamma[alpha + beta]],
   RuntimeOptions -> {"EvaluateSymbolically" -> False},
   CompilationTarget -> "C"];

NSolve[Beta[5, 3] == myBetaV2[a, 3], a, Reals]
(*NSolve[1/105 == CompiledFunction[][a, 3], a, Reals]*)

NSolve[Beta[5, 3] == myBetaV2[a, 3], a, Reals, 
 Method -> {Automatic, "SymbolicProcessing" -> 0}]
(*NSolve[1/105 == CompiledFunction[][a, 3],a, Reals, Method -> {Automatic, "SymbolicProcessing" -> 0}]*)

Now NSolve doesn't even find the solution with warning messages.

3) Wrap the compiled function in a rule with NumericQ pattern tests to ensure it is called with numeric arguments.

Clear[myBetaV3];
myBetaV3[a_?NumericQ, b_?NumericQ] = myBetaV2[a, b];

NSolve[Beta[5, 3] == myBetaV3[a, 3], a, Reals]
(*NSolve[1/105 == myBetaV3[a, 3], a, Reals]*)

NSolve[Beta[5, 3] == myBetaV3[a, 3], a, Reals, 
 Method -> {Automatic, "SymbolicProcessing" -> 0}]
(*NSolve[1/105 == myBetaV3[a, 3], a, Reals, 
 Method -> {Automatic, "SymbolicProcessing" -> 0}]*)

This didn't work either.

Question

How do I use a compiled function within an equation given to NSolve and avoid any attempts to evaluate the function symbolically?

$\endgroup$
2
$\begingroup$

From its documentation, "NSolve deals primarily with linear and polynomial equations." I find that FindRoot does not exhibit the behaviour you wish to suppress. (Guessing: perhaps NSolve attempts to get a symbolic gradient, or some other measure of sensitivity, which FindRoot does not.) Mix in your NumericQ test and I think you have what you want.

Clear[myBetaV1];
myBetaV1 = 
    Compile[{{alpha, _Real}, {beta, _Real}}, 
        Exp[LogGamma[alpha] + LogGamma[beta] - LogGamma[alpha + beta]], 
        CompilationTarget -> "C"];

FindRoot[Beta[5, 3] == myBetaV1[a, 3], {a, 5}]
(* CompiledFunction::cfsa: Argument a at position 1 should be a machine-size real number. >>  *)
(* {a -> 5.} *)

myBetaV3[a_?NumericQ, b_?NumericQ] := myBetaV1[a, b];

FindRoot[Beta[5, 3] == myBetaV3[a, 3], {a, 5}]
(* {a -> 5.} *)

Note that I've added the given value of the first argument to Beta as a starting place for FindRoot. I don't trust me to remember to change that starting point every time, so

findAlpha[a_?NumericQ, b_?NumericQ] := 
    FindRoot[Beta[a, b] == myBetaV3[α, b], {α, a}]

findAlpha[5, 3]
(* {a -> 5.} *)
$\endgroup$
  • $\begingroup$ Thanks for directing me to FindRoot. I also discovered that removing the restriction to Reals resolves the problem for NSolve with myBetaV3 in my example. $\endgroup$ – FalafelPita Jul 26 '17 at 14:03

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.