scipy.optimize.anneal¶
- scipy.optimize.anneal(*args, **kwds)[source]¶
anneal is deprecated! Deprecated in scipy 0.14.0, use basinhopping instead
Minimize a function using simulated annealing.
Uses simulated annealing, a random algorithm that uses no derivative information from the function being optimized. Other names for this family of approaches include: “Monte Carlo”, “Metropolis”, “Metropolis-Hastings”, etc. They all involve (a) evaluating the objective function on a random set of points, (b) keeping those that pass their randomized evaluation critera, (c) cooling (i.e., tightening) the evaluation critera, and (d) repeating until their termination critera are met. In practice they have been used mainly in discrete rather than in continuous optimization.
Available annealing schedules are ‘fast’, ‘cauchy’ and ‘boltzmann’.
Parameters: func : callable
The objective function to be minimized. Must be in the form f(x, *args), where x is the argument in the form of a 1-D array and args is a tuple of any additional fixed parameters needed to completely specify the function.
- x0: 1-D array
An initial guess at the optimizing argument of func.
- args : tuple, optional
Any additional fixed parameters needed to completely specify the objective function.
- schedule : str, optional
The annealing schedule to use. Must be one of ‘fast’, ‘cauchy’ or ‘boltzmann’. See Notes.
- full_output : bool, optional
If full_output, then return all values listed in the Returns section. Otherwise, return just the xmin and status values.
- T0 : float, optional
The initial “temperature”. If None, then estimate it as 1.2 times the largest cost-function deviation over random points in the box-shaped region specified by the lower, upper input parameters.
- Tf : float, optional
Final goal temperature. Cease iterations if the temperature falls below Tf.
- maxeval : int, optional
Cease iterations if the number of function evaluations exceeds maxeval.
- maxaccept : int, optional
Cease iterations if the number of points accepted exceeds maxaccept. See Notes for the probabilistic acceptance criteria used.
- maxiter : int, optional
Cease iterations if the number of cooling iterations exceeds maxiter.
- learn_rate : float, optional
Scale constant for tuning the probabilistc acceptance criteria.
- boltzmann : float, optional
Boltzmann constant in the probabilistic acceptance criteria (increase for less stringent criteria at each temperature).
- feps : float, optional
Cease iterations if the relative errors in the function value over the last four coolings is below feps.
- quench, m, n : floats, optional
Parameters to alter the fast simulated annealing schedule. See Notes.
- lower, upper : floats or 1-D arrays, optional
Lower and upper bounds on the argument x. If floats are provided, they apply to all components of x.
- dwell : int, optional
The number of times to execute the inner loop at each value of the temperature. See Notes.
- disp : bool, optional
Print a descriptive convergence message if True.
Returns: xmin : ndarray
The point where the lowest function value was found.
- Jmin : float
The objective function value at xmin.
- T : float
The temperature at termination of the iterations.
- feval : int
Number of function evaluations used.
- iters : int
Number of cooling iterations used.
- accept : int
Number of tests accepted.
- status : int
A code indicating the reason for termination:
- 0 : Points no longer changing.
- 1 : Cooled to final temperature.
- 2 : Maximum function evaluations reached.
- 3 : Maximum cooling iterations reached.
- 4 : Maximum accepted query locations reached.
- 5 : Final point not the minimum amongst encountered points.
See also
- basinhopping
- another (more performant) global optimizer
- brute
- brute-force global optimizer
Notes
Simulated annealing is a random algorithm which uses no derivative information from the function being optimized. In practice it has been more useful in discrete optimization than continuous optimization, as there are usually better algorithms for continuous optimization problems.
Some experimentation by trying the different temperature schedules and altering their parameters is likely required to obtain good performance.
The randomness in the algorithm comes from random sampling in numpy. To obtain the same results you can call numpy.random.seed with the same seed immediately before calling anneal.
We give a brief description of how the three temperature schedules generate new points and vary their temperature. Temperatures are only updated with iterations in the outer loop. The inner loop is over loop over xrange(dwell), and new points are generated for every iteration in the inner loop. Whether the proposed new points are accepted is probabilistic.
For readability, let d denote the dimension of the inputs to func. Also, let x_old denote the previous state, and k denote the iteration number of the outer loop. All other variables not defined below are input variables to anneal itself.
In the ‘fast’ schedule the updates are:
u ~ Uniform(0, 1, size = d) y = sgn(u - 0.5) * T * ((1 + 1/T)**abs(2*u - 1) - 1.0) xc = y * (upper - lower) x_new = x_old + xc c = n * exp(-n * quench) T_new = T0 * exp(-c * k**quench)
In the ‘cauchy’ schedule the updates are:
u ~ Uniform(-pi/2, pi/2, size=d) xc = learn_rate * T * tan(u) x_new = x_old + xc T_new = T0 / (1 + k)
In the ‘boltzmann’ schedule the updates are:
std = minimum(sqrt(T) * ones(d), (upper - lower) / (3*learn_rate)) y ~ Normal(0, std, size = d) x_new = x_old + learn_rate * y T_new = T0 / log(1 + k)
Examples
Example 1. We illustrate the use of anneal to seek the global minimum of a function of two variables that is equal to the sum of a positive- definite quadratic and two deep “Gaussian-shaped” craters. Specifically, define the objective function f as the sum of three other functions, f = f1 + f2 + f3. We suppose each of these has a signature (z, *params), where z = (x, y), params, and the functions are as defined below.
>>> params = (2, 3, 7, 8, 9, 10, 44, -1, 2, 26, 1, -2, 0.5) >>> def f1(z, *params): ... x, y = z ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params ... return (a * x**2 + b * x * y + c * y**2 + d*x + e*y + f)
>>> def f2(z, *params): ... x, y = z ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params ... return (-g*np.exp(-((x-h)**2 + (y-i)**2) / scale))
>>> def f3(z, *params): ... x, y = z ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params ... return (-j*np.exp(-((x-k)**2 + (y-l)**2) / scale))
>>> def f(z, *params): ... x, y = z ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params ... return f1(z, *params) + f2(z, *params) + f3(z, *params)
>>> x0 = np.array([2., 2.]) # Initial guess. >>> from scipy import optimize >>> np.random.seed(555) # Seeded to allow replication. >>> res = optimize.anneal(f, x0, args=params, schedule='boltzmann', full_output=True, maxiter=500, lower=-10, upper=10, dwell=250, disp=True) Warning: Maximum number of iterations exceeded. >>> res[0] # obtained minimum array([-1.03914194, 1.81330654]) >>> res[1] # function value at minimum -3.3817...
So this run settled on the point [-1.039, 1.813] with a minimum function value of about -3.382. The final temperature was about 212. The run used 125301 function evaluations, 501 iterations (including the initial guess as a iteration), and accepted 61162 points. The status flag of 3 also indicates that maxiter was reached.
This problem’s true global minimum lies near the point [-1.057, 1.808] and has a value of about -3.409. So these anneal results are pretty good and could be used as the starting guess in a local optimizer to seek a more exact local minimum.
Example 2. To minimize the same objective function using the minimize approach, we need to (a) convert the options to an “options dictionary” using the keys prescribed for this method, (b) call the minimize function with the name of the method (which in this case is ‘Anneal’), and (c) take account of the fact that the returned value will be a OptimizeResult object (i.e., a dictionary, as defined in optimize.py).
All of the allowable options for ‘Anneal’ when using the minimize approach are listed in the myopts dictionary given below, although in practice only the non-default values would be needed. Some of their names differ from those used in the anneal approach. We can proceed as follows:
>>> myopts = { 'schedule' : 'boltzmann', # Non-default value. 'maxfev' : None, # Default, formerly `maxeval`. 'maxiter' : 500, # Non-default value. 'maxaccept' : None, # Default value. 'ftol' : 1e-6, # Default, formerly `feps`. 'T0' : None, # Default value. 'Tf' : 1e-12, # Default value. 'boltzmann' : 1.0, # Default value. 'learn_rate' : 0.5, # Default value. 'quench' : 1.0, # Default value. 'm' : 1.0, # Default value. 'n' : 1.0, # Default value. 'lower' : -10, # Non-default value. 'upper' : +10, # Non-default value. 'dwell' : 250, # Non-default value. 'disp' : True # Default value. } >>> from scipy import optimize >>> np.random.seed(777) # Seeded to allow replication. >>> res2 = optimize.minimize(f, x0, args=params, method='Anneal', options=myopts) Warning: Maximum number of iterations exceeded. >>> res2 status: 3 success: False accept: 61742 nfev: 125301 T: 214.20624873839623 fun: -3.4084065576676053 x: array([-1.05757366, 1.8071427 ]) message: 'Maximum cooling iterations reached' nit: 501