Closed jschueller closed 6 months ago
Thank you @jschueller . Could we ask the SciPy people what is the standard / preferred signature of this callback function, e.g., at https://github.com/scipy/scipy/issues/18118#issuecomment-1715536813 ? Thanks.
seems they only report x: https://github.com/scipy/scipy/blob/main/scipy/optimize/cobyla/cobyla.pyf#L11C9-L15C32
I am copying from https://github.com/libprima/prima/pull/69#issuecomment-1722190222
The first question that we have to discuss is as follows. In
callback(x, f, terminate, [, other inputs])
, what do we wantx
andf
to be? There are two possibilities.
x
is the current best point andf
is its function valuex
is the most recently evaluated point andf
is its function valueAnother possibility is to change the signature of the callback function to
callback(xnew, fnew, xbest, fbest, terminate, ...)
to include both of them.In addition,
- for
lincona
, we must includecstrv
(constraint violatio) as an input tocallback
,- for
cobyla
, we must include bothcstrv
andconstr
.Insights from SciPy maintainers are greatly needed.
Thanks.
Comments by @andyfaff copied from the SciPy issue.
The design of the callback is made easier if the Fortran code can be stepped through as an iterator. i.e. Python takes control of the solve, possibly supplying things (e.g. func/grad evalutions) to the solver. It's best to have as much logic in Python as possible, Fortran as a whole is difficult to maintain.
For example, the core of
differential_evolution
is something akin to the following:def solve(self): for i in range(numiters): if converged: # return final result else: result = next(self) def __next__(self): # call the external code to take one solve step, fortran returns interesting things. x, fun, etc = make_fortran_step() # make intermediate result im_result = OptimizeResult(x=x, fun=fun) # call callback callback(intermediate_result=im_result) return im_result
L-BFGS-B/SLSQP kind of follow this pattern, and could be made cleaner in that regard.
Modern callbacks are being designed to return an intermediate
OptimizeResult
. See the docstring forminimize
. The intermediate result should be filled out with as much information that makes sense to offer to the user.
with the new callback we can do something similar as you get the new optimum, and if the point is good enough you can decide to continue or to stop
This was resolved in https://github.com/libprima/prima/pull/113, recommend we close this issue.
for scipy integration we should be able to pass an optional callback function to report at least the current best x/f values
I propose it could also to cancel the minimization (or via the objective function) according to a "stop" argument (and add a new return code for this):
I dont know if there are other useful stuff we want to track, like the number of evaluations ...
in C it is usual to pass an additional pointer argument to hook back to struct/data:
see the "callback" argument of minimize: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
could also be useful for nlopt: https://github.com/stevengj/nlopt/issues/37