8

I want to solve an equation with a parameter $a$, and define the result as a function of $a$. It is something like this:

f[a_] := FindRoot[x^2 + 2 x + a == 0, {x, 0.5}]
f[0.2]
(* -> {x -> -0.105573} *)

The equation I want to solve is a large expression, so I do not want to put it explicitly inside the FindRoot. But this does not work:

eq := x^2 + 2 x + a;
f[a_] := FindRoot[eq == 0, {x, 0.5}]
f[0.2]
(* -> FindRoot::nlnum: The function value {1.25 +a} is not a list of numbers with dimensions {1} at {x} = {0.5}. *)

I do not want to define the equation as eq[a], because this equation is also used to do other things, for which it is better to just use eq. The following ways also do not work:

f[a_] := FindRoot[Evaluate[eq] == 0, {x, 0.5}]
f[a_] := Evaluate[FindRoot[eq == 0, {x, 0.5}]]

(However, if we want to solve the above equation analytically, f[a_] := Evaluate[Solve[eq == 0, x]] works, and f[a_] := Solve[Evaluate[eq] == 0, x] does not. How to explain this?)

Kuba
  • 136,707
  • 13
  • 279
  • 740
renphysics
  • 1,560
  • 1
  • 10
  • 19

2 Answers2

10

To achieve what you want, you can use the following

eq := x^2 + 2 x + a;
Function[f[a_] := FindRoot[# == 0, {x, 0.5}]][eq]

to define your f.

halirutan
  • 112,764
  • 7
  • 263
  • 474
  • 5
    Wow!... Interesting crazy code injection. This is the kind of operations that make new users get in a non excited state about Mathematica. – Murta May 25 '14 at 14:35
3

As an alternative to halirutan's answer, you could define f like this

eq := x^2 + 2 x + a;
Unevaluated[
  f[a_] := FindRoot[eq == 0, {x, 0.5}]
  ] /. OwnValues[eq]

Using Unevaluated in the first argument of ReplaceAll like this is similar to, but avoids, With. You cannot use With here, because With will try to prevent that the a in a_ and the a in eq match.

Note that here eq is never really evaluated, so that we even get a solution if x has a value.

Also ReleaseHold is totally pro (x cannot have a value now)

eq := x^2 + 2 x + a;
Clear@f
ReleaseHold@
 Hold[SetDelayed][f[a_], Hold[FindRoot][eq == 0, {x, 0.5}]]
f[0.2]

{x -> -0.105573}

Jacob Akkerboom
  • 12,215
  • 45
  • 79
  • Very nice, thanks ;) I was thinking about this but I forgot about OwnValues. I think it's the first time I see it can be really useful :) #newbie – Kuba May 26 '14 at 20:55
  • @Kuba Well, I saw you use ReleaseHold today too, which is totally pro :P. Actually I could probably use that here :P – Jacob Akkerboom May 26 '14 at 21:07
  • My version with ReleaseHold was not working, I was not aware about sneaky little With renaming variables. I'm glad you can't see deleted answers :P my is full of pro solutions like: With[{e = eq}, ToExpression[ MakeBoxes[f[a_] := FindRoot[e == 0, {x, 0.5}]] /. "a$_" -> "a_"] ] – Kuba May 26 '14 at 21:24
  • @Kuba as long as you are the first to answer, it is ok to show off your knowledge of functions that are not really necessary, don't you think :P? I agree With is quite sneaky. The behaviour is mentioned in the docs under With>possible issues, though. – Jacob Akkerboom May 27 '14 at 07:16
  • oh thank you, now I'm feeling better :P – Kuba May 27 '14 at 07:19