3

Super simple question, but I'm lost here.

f = Compile[{{a, _Real}, {b, _Real}, {c, _Real}}, 
  x /. NSolve[a x^2 + b x + c == 0, {x}]]
f[1., -4., -5.]

gives the error

CompiledFunction::cfse: Compiled expression {-1.,5.} should be a machine-size real number.

But

g = Compile[{{a, _Real}, {b, _Real}, {c, _Real}}, 
  x /. NSolve[a x^2 + b x + c == 0, {x}][[1]]]
g[1., -4., -5.]

works fine.

How do I type the result so that it knows it's a list. I haven't had any problems getting Compile to return a list before, and

h = Compile[{{a, _Real}, {b, _Real}, {c, _Real}}, 
  sol = NSolve[a x^2 + b x + c == 0, {x}]; {x /. sol[[1]], 
   x /. sol[[2]]}]
h[1., -4., -5.]

gets around the issue, but there's got to be a better way than that.

This gives the same error, even though the output should be a real number. Somehow the list can't exist within the compiled function. I don't understand.

k = Compile[{{a, _Real}, {b, _Real}, {c, _Real}}, 
  listofSolutions = x /. NSolve[a x^2 + b x + c == 0, {x}]; 
  listofSolutions[[1]]]
k[1., -4., -5.]

Edited to add: I know NSolve isn't compilable; I'm trying to get the speed up from the typing of a, b, and c, among other things in my actual code.

NathanRL
  • 127
  • 6
  • 1
    ReplaceAll and NSolve are not compilable. Just get rid of Compile. – Michael E2 Jul 09 '20 at 19:00
  • I don't know what speed-up you mean. Compile is likely to slow things down in this case. Compared to the slowness of NSolve, though, it will be negligible....Okay, I guess I can imagine a use-case that this would be reasonable. You should Block/Module/localize x, though, to protect the code when x has a global value. (And thanks for the accept. :) – Michael E2 Jul 09 '20 at 19:25
  • @MichaelE2 Maybe I'm mistaken, but I'm solving the same polynomial with different parameter values and I want to save that structure and feed in (typed) parameter values. I thought that Compile would help. And NSolve seems to take forever for sure. I've been trying to switch to Root with a few different starting points. – NathanRL Jul 09 '20 at 19:37
  • 2
    You know about CompilePrint to inspect what the compiler is doing? (Needs@"CompiledFunctionTools`"; CompilePrint[f]) – Michael E2 Jul 09 '20 at 19:39

1 Answers1

3

See my comment, but here goes:

f = Compile[{{a, _Real}, {b, _Real}, {c, _Real}},
   x /. NSolve[a x^2 + b x + c == 0, {x}],
   {{ReplaceAll[_, _], _Real, 1}}];  (* <-- return type declarations *)
f[1., -4., -5.]

(* {-1., 5.} *)

If you have many different kinds of calls to ReplaceAll, you can make more specific patterns. For example:

{{ReplaceAll[_, _NSolve], _Real, 1}}
Michael E2
  • 235,386
  • 17
  • 334
  • 747