3
$\begingroup$

This question already has an answer here:

I have defined a function which takes a coefficient for a differential equation as an argument, solves the differential equation with NDSolve, and returns the value of the solution at time t=10. I can plot this, but I can't seem to find the minimum value.

This code demonstrates the problem i'm having:

f[k_] := y[10] /. NDSolve[
    {y''[t] == -k*y[t], y[1] == 2 , y'[2] == 1},
    y,
    {t, 0, 10}
];
Plot[f[k], {k, 0, 2}] (* works great *)
NMinimize[{f[k], k > 0, k < .75}, k] (* fails *)

The NMinimize fails with the error NDSolve::ndnum: Encountered non-numerical value for a derivative at t == 1.'.

So how do I find the minimum of my function f?

$\endgroup$

marked as duplicate by Michael E2, m_goldberg, ciao, RunnyKine, Yves Klett May 9 '14 at 5:31

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    $\begingroup$ Try f[k_?NumericQ] := y[10] /. First @ NDSolve[{y''[t] == -k*y[t], y[1] == 2, y'[2] == 1}, y, {t, 0, 10}]. See the pitfalls question. You also might want to consider FindMinimum instead of NMinimize. $\endgroup$ – Michael E2 May 8 '14 at 23:36
  • $\begingroup$ Be sure to Clear[f] before you try Michael E2's solution, otherwise Mathematica will overload f with two definitions and use the less-restrictive one that you don't want. $\endgroup$ – Chris K May 8 '14 at 23:38
4
$\begingroup$

Although Michael E2's suggestion in his comment about using the argument pattern k_?NumericQ will certainly work, I would like to suggest a double interpolation approach because it is much faster.

ff[k_] := NDSolve[{y''[t] == -k*y[t], y[1.] == 2, y'[2.] == 1.}, y, {t, 0., 10.}][[1, 1, 2]]
AbsoluteTiming[
  f = Interpolation@Table[{k, ff[k][10.]}, {k, 0., 2, .01}];]
{2.748679, Null}
AbsoluteTiming @ NMinimize[{f[k], {k > 0., k < .5}}, k]
{0.075349, {-3.95571, {k -> 0.212177}}}

Now compare this with

g[k_?NumericQ] := 
  NDSolve[{y''[t] == -k*y[t], y[1.] == 2, y'[2.] == 1.}, y, {t, 0., 10.}][[1, 1, 2]][10.]
AbsoluteTiming @ NMinimize[{g[k], {k > 0., k < .5}}, k]
{44.634075, {-3.95571, {k -> 0.212174}}}

The first result for the minimum is a little less precise, but much faster.

$\endgroup$
  • $\begingroup$ I think FindMinimum is even faster. On this particular problem, it's even faster with DSolve. $\endgroup$ – Michael E2 May 9 '14 at 1:02
  • $\begingroup$ @MichaelE2. Didn't get that far out the box when I was thinking about out-of-box ideas to improve the wretched performance of the OP approach :) $\endgroup$ – m_goldberg May 9 '14 at 2:03
  • $\begingroup$ @m_goldberg could you explain a little why your double interpolation approach works out so fast, and how broadly it can be applied? $\endgroup$ – Chris K May 9 '14 at 2:22
  • 1
    $\begingroup$ @ChrisK. I would say it's because ff in my method gets called many fewer times than g does in my version of the OP's method. But in this case, you should look at J. W. Perry's answer which shows an even better approach. However, it is a generally applicable trick and you might find other occasions where it will help. $\endgroup$ – m_goldberg May 9 '14 at 2:50
2
$\begingroup$

For the record, here is my implementation of DSolve and FindMinimum on the same equation. This does not address your NDSolve work but the result is relatively instantaneous.

soln = DSolve[{y''[t] == -k*y[t], y[1] == 2, y'[2] == 1}, y[t], t];
f[k_] := Evaluate[y[t] /. soln] /. t -> 10
FindMinimum[{f[k][[1]], 0 <= k <= 3/4}, {k, 1/10}]

I plot the same with

Plot[f[k], {k, 0, 2}]
$\endgroup$

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