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$
1

2 Answers 2

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$
1
  • 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
    Commented May 25, 2014 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$
5
  • $\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
    Commented May 26, 2014 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$ Commented May 26, 2014 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
    Commented May 26, 2014 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$ Commented May 27, 2014 at 7:16
  • $\begingroup$ oh thank you, now I'm feeling better :P $\endgroup$
    – Kuba
    Commented May 27, 2014 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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