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
min
for minimization problem ormax
for 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``. Theequilibrium
mode is only valid withncores > 1
(See Notes below)chain_size – (int) number of individuals to evaluate in the chain every generation (e.g. like
npop
for 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 sizencores
is 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 > 1
is 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
Tmax
andTmin
if any of the followingcooling
schedules is used:fast
,cauchy
, andboltzmann
.A special cooling schedule
equilibrium
is 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.
alpha
is the parameter above that controls the initial temperature of SA.lmbda
expresses 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
equilibrium
cooling option is activated for parallel SA chains only, i.e. whenncores > 1
.
Custom
move_func
is allowed by following the input/output format in the example above. IfNone
the default moving function is used, which is controlled by thechi
parameter. Therefore,chi
is used ONLY ifmove_func=None
.chi
controls 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_size
individuals are executed. Therefore, look for an optimal balance betweenchain_size
andngen
.Option
reinforce_best
allows 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 > 1
andmove_func=None
, parallel SA chains can have differentchi
values, provided as a list/vector.