Skip to main content

How to stop optimization (e.g. NMinimize) after reaching target value


Suppose we have some function f[x,y] that we want to optimize in way that we are only interested in values (x,y) that guarantee our function value is below some value target. See the following MWE:


f[x_, y_] := f[x, y] = x^2 - 4*x + y^2 - y - x*y;

findMin[target_, steps_] := Block[{nbr = -1},
solsOpt = NMinimize[
f[x, y],
{x, y},

Method -> "NelderMead",
(*EvaluationMonitor:>{nbr += 1; If[Mod[nbr, steps] == 0, Print["Step: ", nbr," ; Current value: ",f[x,y], " ; parameters: ",{x,y}],Print]}*)
EvaluationMonitor :> {nbr += 1; If[Mod[nbr, steps] == 0, Print["Step: ", nbr," ; Current value: ", f[x, y], " ; parameters: ", {x, y}], Print] || If[f[x, y] <= target, Abort[], Print]}
];
Print["Number of iterations: ", nbr];
Print["Final value: ", solsOpt[[1]]];
Return[solsOpt];
]

Of course findMin[-5,1] stops after a few iterations and I can read the values (x,y) that satisfy my criterion. However, I need to do that for a bunch of different functions f inside a ParallelTable structure, that in the end holds (function_index, final value, parameter values). By aborting no values are stored. What I want is something like "After reaching target, just assume optimization is finished and go on with the next one". Is that possible with the built-in function(s)?




Answer



Catch/Throw:


 findMin[target_, steps_] := 
Block[{nbr = -1},
solsOpt =
ReleaseHold@Catch@NMinimize[f[x, y], {x, y},
Method -> "NelderMead",
EvaluationMonitor :> {nbr += 1;
If[Mod[nbr, steps] == 0,
Print["Step: ", nbr, " ; Current value: ", f[x, y],

" ; parameters: ", {x, y}], Print] ||
If[f[x, y] <= target, Print["good enough"];
Throw[{f[x, y], {HoldForm[x] -> x, HoldForm[y] -> y}}],
Print]}];
Print["Number of iterations: ", nbr];
Print["Final value: ", solsOpt];
solsOpt]


findMin[-5, 1] (* three iterations, stop for threshold *)



{-6.1742, {x -> 2.2116, y -> 1.00612}}



 findMin[-50, 1]  (* 89 iterations , regular convergence *)


{-7., {x -> 3., y -> 2.}}



Aside , I don't know why you have the symbol Print in there a few times not applied to any arguments..



Also, aside from the question you can do NMinimize[fn = f[x, y],... then use the symbol fn in your conditional If[fn <= target .. so avoiding redundant evaluation of the function.


Comments