Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Scipy minimize after set time

Tags:

python

scipy

I use minimize from the Scipy module on Python 3.4, specifically:

resultats=minimize(margin_rate, iniprices, method='SLSQP',
jac=margin_rate_deriv, bounds=pricebounds, options={'disp': True,
'maxiter':2000}, callback=iter_report_margin_rate)

The maximum number of iterations can be set (as above), but is there a way to tell minimize to stop searching for a solution after a given set time? I looked at the general options of minimize as well as the specific options of the SLSQP solver, but could not work it out.

Thanks

like image 542
Charles Avatar asked Jul 18 '14 12:07

Charles


2 Answers

You can use the callback argument to raise a warning or exception if the execution time exceeds some threshold:

import numpy as np
from scipy.optimize import minimize, rosen
import time
import warnings

class TookTooLong(Warning):
    pass

class MinimizeStopper(object):
    def __init__(self, max_sec=60):
        self.max_sec = max_sec
        self.start = time.time()
    def __call__(self, xk=None):
        elapsed = time.time() - self.start
        if elapsed > self.max_sec:
            warnings.warn("Terminating optimization: time limit reached",
                          TookTooLong)
        else:
            # you might want to report other stuff here
            print("Elapsed: %.3f sec" % elapsed)

# example usage
x0 = [1.3, 0.7, 0.8, 1.9, 1.2]
res = minimize(rosen, x0, method='Nelder-Mead', callback=MinimizeStopper(1E-3))
like image 57
ali_m Avatar answered Oct 23 '22 01:10

ali_m


No. What you can do is start the optimizer in a separate process, keep track of how long it has been running and terminate it if necessary:

from multiprocessing import Process, Queue
import time
import random
from __future__ import print_function

def f(param, queue):
    #do the minimization and add result to queue
    #res = minimize(param)
    #queue.put(res)

    #to make this a working example I'll just sleep a 
    #a random amount of time
    sleep_amount = random.randint(1, 10)
    time.sleep(sleep_amount)
    res = param*sleep_amount
    queue.put(res)

q = Queue()
p = Process(target=f, args=(2.2, q))
max_time = 3
t0 = time.time()

p.start()
while time.time() - t0 < max_time:
    p.join(timeout=1)
    if not p.is_alive():
        break

if p.is_alive():
    #process didn't finish in time so we terminate it
    p.terminate()
    result = None
else:
    result = q.get()
print(result)
like image 42
numentar Avatar answered Oct 23 '22 02:10

numentar