I want to numerically calculate the maximum of a function defined by the minimization of another function, like the following:
NMaximize[b/.NMinimize[(a^2+b)^2,{b}][[2]],{a}]
Obviously the intended result (for this simple test function) would be:
{0., {a->0.}}
because the inner minimization would give b=-a^2 for any value of a, and maximizing that gives 0 for a=0.
However I get the error message NMinimize::nnum: "The function value (-0.829053+a^2)^2 is not a number at {b} = {-0.829053}."
and the result NMaximize[b/.{b},{a}]
. I figured that this is due to premature evaluation of the argument (i.e. before a
got anumerical value), therefore I tried to wrap either the whole first argument of just the NMinimize
call in Unevaluated
, but neither helped.
So my question is: How can I do this combined numerical optimization?
Answer
This is a rather common issue that comes up with many numerical functions (FindRoot
, NIntegrate
, FindMaximum
, NMaximize
, etc.) It is also explained in this Wolfram Knowledge Base article. Sometimes you want to pass these functions an expression that has a symbolic parameter, and compute the result for different values of that parameter.
Example:
fun[a_] := Block[{b}, b /. NMinimize[(a^2 + b)^2, {b}][[2]]]
This will work nicely if you call it with a numeric argument: fun[3]
. But it will cause an error in NMinimize
if you call it with a symbolic parameter: fun[a]
(for obvious reasons).
The solution is:
Clear[fun]
fun[a_?NumericQ] := Block[{b}, b /. NMinimize[(a^2 + b)^2, {b}][[2]]]
NMaximize[fun[a], {a}]
(Be sure to evaluate Clear[...]
to get rid of the previous definition of fun
!)
This ensures that fun
will only evaluate for numerical arguments, i.e. fun[a]
won't evaluate inside NMaximize
before NMaximize
actually substitutes a number for a
.
And this is also the answer to your specific question: make the inner NMinimize
expression a separate function, and make sure it only evaluates for numerical arguments.
Requested edit
An important related point is: how can we match only numerical quantities using a pattern? One might think of using _Real
(as in the comment below). The problem with this is that it will only match numbers whose Head
is Real
. This excludes integers (such as 1,2,3
), rationals (2/3, 4/5
), constants (such as Pi
or E
), or expressions like Sqrt[2]
.
The only robust solution is using NumericQ[]
(x_ ? NumericQ
in a pattern). NumericQ
will return True
for anything that gives a number when N[]
is applied to it.
There's another related function, NumberQ[]
, which gives True
only for objects with Integer
, Rational
, Real
or Complex
, but not for constant or expressions (Pi
or Sin[3]
).
Comments
Post a Comment