8
$\begingroup$

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?)

$\endgroup$
10
$\begingroup$

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.

$\endgroup$
  • 5
    $\begingroup$ Wow!... Interesting crazy code injection. This is the kind of operations that make new users get in a non excited state about Mathematica. $\endgroup$ – Murta May 25 '14 at 14:35
3
$\begingroup$

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}

$\endgroup$
  • $\begingroup$ 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 $\endgroup$ – Kuba May 26 '14 at 20:55
  • $\begingroup$ @Kuba Well, I saw you use ReleaseHold today too, which is totally pro :P. Actually I could probably use that here :P $\endgroup$ – Jacob Akkerboom May 26 '14 at 21:07
  • $\begingroup$ 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_"] ] $\endgroup$ – Kuba May 26 '14 at 21:24
  • $\begingroup$ @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. $\endgroup$ – Jacob Akkerboom May 27 '14 at 7:16
  • $\begingroup$ oh thank you, now I'm feeling better :P $\endgroup$ – Kuba May 27 '14 at 7:19

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.