0

I'm trying to use the callback argument in the scipy.optimize.differential_evolution method to stop the minimization process after some specified max_time parameter.

The code below apparently reaches the callbackF() function once and then never again.

What am I doing wrong here?


from scipy.optimize import differential_evolution as DE
import time as t

# Max time in seconds
max_time = 3.

def callbackF(start_t):
    time_elapsed = t.time() - start_t
    if time_elapsed > max_time:
        print("Stop")
        return True

def DEdist(model):
    res = (1. - model[0])**2 + 100.0 * (model[1] - model[0]**2)**2 + \
        (1. - model[1])**2 + 100.0 * (model[2] - model[1]**2)**2
    return res

start_t = t.time()
bounds = [[0., 10.], [0., 10.], [0., 10.], [0., 10.]]
result = DE(
    DEdist, bounds, popsize=100, maxiter=1500, callback=callbackF(start_t))
print(t.time() - start_t)
Gabriel
  • 40,504
  • 73
  • 230
  • 404

1 Answers1

2

You're passing in the return value from calling callbackF(start_t). What you want is to pass in the function itself. Here's one way to do this

from scipy.optimize import differential_evolution as DE
import time as t

# Max time in seconds
max_time = 3.

def get_callback(start_t):
    def callbackF(current_params, convergence):
        time_elapsed = t.time() - start_t
        if time_elapsed > max_time:
            print("Stop")
            return True
    return callbackF

def DEdist(model):
    res = (1. - model[0])**2 + 100.0 * (model[1] - model[0]**2)**2 + \
        (1. - model[1])**2 + 100.0 * (model[2] - model[1]**2)**2
    return res

start_t = t.time()
bounds = [[0., 10.], [0., 10.], [0., 10.], [0., 10.]]
result = DE(
    DEdist, bounds, popsize=100, maxiter=1500, callback=get_callback(start_t))
print(t.time() - start_t)

I added the *args, **kwargs because some kwarg call convergence gets passed in, and I didn't want to look up in the docs whether there's anything else that is passed to a callback function.

EDIT - made the function signature more meaningful.

Nathan
  • 9,651
  • 4
  • 45
  • 65
  • The way to define `callback` looks incredibly convoluted, but works perfectly nonetheless. Thank you Nathan! – Gabriel May 16 '19 at 21:00
  • 1
    If you prefer you could also do `callback=lambda *args, **kwargs: callbackF(start_t)` to create the wrapping function inline instead of defining it ahead of time. – Nathan May 16 '19 at 21:22