Simulated Annealing (SA)¶
A module for parallel Simulated Annealing. A Synchronous Approach with Occasional Enforcement of Best Solution.
Original paper: Onbaşoğlu, E., Özdamar, L. (2001). Parallel simulated annealing algorithms in global optimization. Journal of global optimization, 19(1), 27-50..
What can you use?¶
Multi processing: ✔️
Discrete spaces: ✔️
Continuous spaces: ✔️
Mixed Discrete/Continuous spaces: ✔️
Parameters¶
-
class
neorl.evolu.sa.SA(mode, bounds, fit, cooling='fast', chain_size=10, Tmax=10000, Tmin=1, chi=0.1, move_func=None, reinforce_best='soft', lmbda=1.5, alpha=1.5, threshold=10, ncores=1, seed=None)[source]¶ Parallel Simulated Annealing
- Parameters
mode – (str) problem type, either
minfor minimization problem ormaxfor maximizationbounds – (dict) input parameter type and lower/upper bounds in dictionary form. Example:
bounds={'x1': ['int', 1, 4], 'x2': ['float', 0.1, 0.8], 'x3': ['float', 2.2, 6.2]}fit – (function) the fitness function
cooling – (str) cooling schedule, choose
fast,boltzmann,cauchy,``equilibrium``. Theequilibriummode is only valid withncores > 1(See Notes below)chain_size – (int) number of individuals to evaluate in the chain every generation (e.g. like
npopfor other algorithms)Tmax – (int) initial/maximum temperature
Tmin – (int) final/minimum temperature
chi – (float or list of floats) probability of perturbing every attribute of the input
x, ONLY used ifmove_func=None. Forncores > 1, if a scalar is provided, constant value is used across allncores. If a list of sizencoresis provided, each core/chain uses different value ofchi(See Notes below)move_func – (function) custom self-defined function that controls how to perturb the input space during annealing (See Notes below)
reinforce_best – (str) an option to control the starting individual of the chain at every generation. Choose
None,hard,soft(See Notes below).lmbda – (float) ONLY used if
cooling = equilibrium, control the cooling rate, and the speed at which the algorithm converges.alpha – (float) ONLY used if
cooling = equilibrium, control the initial temperature of the cooling schedule.threshold – (float) ONLY used if
cooling = equilibrium. The threshold (in %) for the acceptance rate of solution under which the algorithm stops running.ncores – (int) number of parallel processors (
ncores > 1is required forcooling = equilibrium)seed – (int) random seed for sampling
-
evolute(ngen, x0=None, verbose=False)[source]¶ This function evolutes the SA algorithm for number of generations.
- Parameters
ngen – (int) number of generations to evolute
x0 – (list of lists) initial samples to start the evolution (
len(x0)must be equal toncores)verbose – (int) print statistics to screen
- Returns
(tuple) (best individual, best fitness, and dictionary containing major search results)
Example¶
from neorl import SA
import matplotlib.pyplot as plt
import random
#Define the fitness function
def FIT(individual):
"""Sphere test objective function.
"""
y=sum(x**2 for x in individual)
return y
#Setup the parameter space (d=5)
nx=5
BOUNDS={}
for i in range(1,nx+1):
BOUNDS['x'+str(i)]=['float', -100, 100]
#define a custom moving function
def my_move(x, **kwargs):
#-----
#this function selects two random indices in x and perturb their values
#-----
x_new=x.copy()
indices=random.sample(range(0,len(x)), 2)
for i in indices:
x_new[i] = random.uniform(BOUNDS['x1'][1],BOUNDS['x1'][2])
return x_new
#setup and evolute a serial SA
sa=SA(mode='min', bounds=BOUNDS, fit=FIT, chain_size=50, chi=0.2, Tmax=10000,
move_func=my_move, reinforce_best='soft', cooling='boltzmann', ncores=1, seed=1)
#setup and evolute parallel SA with `equilibrium` cooling
#sa=SA(mode='min', bounds=BOUNDS, fit=FIT, chain_size=20, chi=0.2, Tmax=10000, threshold = 1, lmbda=0.05,
# move_func=my_move, reinforce_best='soft', cooling='equilibrium', ncores=8, seed=1)
x_best, y_best, sa_hist=sa.evolute(ngen=100, verbose=1)
#plot different statistics
plt.figure()
plt.plot(sa_hist['accept'], '-o', label='Acceptance')
plt.plot(sa_hist['reject'], '-s', label='Rejection')
plt.plot(sa_hist['improve'], '-^', label='Improvement')
plt.xlabel('Generation')
plt.ylabel('Rate (%)')
plt.legend()
plt.show()
Notes¶
Temperature is annealed between
TmaxandTminif any of the followingcoolingschedules is used:fast,cauchy, andboltzmann.A special cooling schedule
equilibriumis supported, which is associated with the following arguments:The initial temperature is determined by \(T_0=Max (\alpha * STD(\vec{E}_0), Tmin)\), where \(STD(\vec{E}_0)\) is the standard deviation of the finesses of the initial chains. A tolerance is applied to the temperature if the standard deviation converged to zero.
alphais the parameter above that controls the initial temperature of SA.lmbdaexpresses the cooling rate or the speed of the temperature decay. Larger values lead to faster cooling.The
threshold(in %) expresses the acceptance rate threshold under which the SA stops running. For example, ifthreshold=10, when the mean of acceptance rate of all chains falls below 10%, SA terminates. For zero threshold, SA will terminate when all chains no longer accept any new solution.The
equilibriumcooling option is activated for parallel SA chains only, i.e. whenncores > 1.
Custom
move_funcis allowed by following the input/output format in the example above. IfNonethe default moving function is used, which is controlled by thechiparameter. Therefore,chiis used ONLY ifmove_func=None.chicontrols the probability of perturbing an attribute of the individual. For example, ford=4, \(\vec{x}=[x_1,x_2,x_3,x_4]\), for every \(x_i\), a uniform random number \(U[0,1]\) is compared tochi, ifU[0,1] < chi, the attribute is perturbed. Otherwise, it remains fixed.For every generation, a total of
chain_sizeindividuals are executed. Therefore, look for an optimal balance betweenchain_sizeandngen.Option
reinforce_bestallows enforcing a solution from the previous generation to use as a chain startup in the next generation. Three options are available for this argument:None: No solution is enforced. The last chain state is preserved to the next generation.hard: the best individual in the chain is used as the initial starting point.soft: an energy-based sampling approach is utilized to draw an individual from the chain to start the next generation.
Total number of cost evaluations for SA is
chain_size*(ngen + 1).If
ncores > 1, parallel SA chains are initialized to accelerate the calculations.If
ncores > 1andmove_func=None, parallel SA chains can have differentchivalues, provided as a list/vector.