Search code examples
python-3.xscipy-optimize

SciPy - Optimize: callback(intermediate_result: OptimizeResult) what does it mean?


I believe it is a trivial question but I was not able to find any example and I am struggling to understand how to use this instruction for creating a callback for scipy.optimize

import scipy.optimize as sp
res = sp.minimize(FUN, 0.25,method='Nelder-Mead',bounds=None,callback=STOP)

where the callback is defined as:

def STOP(intermediate_result: sp.OptimizeResult):
    print('intermediate_results',intermediate_result)
    if intermediate_result.fun < 0.005:
        return StopIteration
    else:
        return 0

The intermediate_resultappears to be only the optimal parameter (so it seems I am implemented the instruction callback(xk) and not callback(intermediate_result: OptimizeResult) )

I would like that my function STOP analyse the value of the returned function value and stop in case the value is smaller than 0.005

But generally I would like to understand what the guidance is saying:

All methods except TNC, SLSQP, and COBYLA support a callable with the signature:

callback(intermediate_result: OptimizeResult)

where intermediate_result is a keyword parameter containing an OptimizeResult with attributes x and fun, the present values of the parameter vector and objective function.

Could you please help me ?

When I tried that I got:

AttributeError: 'numpy.ndarray' object has no attribute 'fun'

I tried different way to change the keyword in the function and inside the optimizer but I have not clue of what I am doing


Solution

  • In previous version of SciPy the callback parameter was the current x value as a nd.array (<= 1.9.3). In newer version it is a partial OptimizeResult with fun and x (1.12.0).

    First upgrade to latest version of SciPy, then try this MCVE

    from scipy import optimize
    
    def callback(intermediate_result):
        if intermediate_result.fun < 0.5:
            raise StopIteration
    
    optimize.minimize(optimize.rosen, x0=[0, 0, 0, 0], method='Nelder-Mead', tol=1e-6, callback=callback)
    

    Also notice that exception should be raised not returned.

    For older versions, you have to compute the solution by yourself and raising StopIetration will stop the script (so you have to catch it):

    def callback(intermediate_result):
        if optimize.rosen(intermediate_result) < 0.5:
            raise StopIteration
    

    Where new version will stop the algorithm and return a solution with corresponding message:

    #   message: `callback` raised `StopIteration`.
    #   success: False
    #    status: 99
    #       fun: 0.4281196937835328
    

    To update your WSL to the latest scipy, issue the following command:

    python -m pip install -U --user scipy