|
Packit |
67cb25 |
.. index::
|
|
Packit |
67cb25 |
single: simulated annealing
|
|
Packit |
67cb25 |
single: combinatorial optimization
|
|
Packit |
67cb25 |
single: optimization, combinatorial
|
|
Packit |
67cb25 |
single: energy function
|
|
Packit |
67cb25 |
single: cost function
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*******************
|
|
Packit |
67cb25 |
Simulated Annealing
|
|
Packit |
67cb25 |
*******************
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Stochastic search techniques are used when the structure of a space is
|
|
Packit |
67cb25 |
not well understood or is not smooth, so that techniques like Newton's
|
|
Packit |
67cb25 |
method (which requires calculating Jacobian derivative matrices) cannot
|
|
Packit |
67cb25 |
be used. In particular, these techniques are frequently used to solve
|
|
Packit |
67cb25 |
combinatorial optimization problems, such as the traveling salesman
|
|
Packit |
67cb25 |
problem.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The goal is to find a point in the space at which a real valued
|
|
Packit |
67cb25 |
*energy function* (or *cost function*) is minimized. Simulated
|
|
Packit |
67cb25 |
annealing is a minimization technique which has given good results in
|
|
Packit |
67cb25 |
avoiding local minima; it is based on the idea of taking a random walk
|
|
Packit |
67cb25 |
through the space at successively lower temperatures, where the
|
|
Packit |
67cb25 |
probability of taking a step is given by a Boltzmann distribution.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The functions described in this chapter are declared in the header file
|
|
Packit |
67cb25 |
:file:`gsl_siman.h`.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Simulated Annealing algorithm
|
|
Packit |
67cb25 |
=============================
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The simulated annealing algorithm takes random walks through the problem
|
|
Packit |
67cb25 |
space, looking for points with low energies; in these random walks, the
|
|
Packit |
67cb25 |
probability of taking a step is determined by the Boltzmann distribution,
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. math:: p = e^{-(E_{i+1} - E_i)/(kT)}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if
|
|
Packit |
67cb25 |
:math:`E_{i+1} > E_i`, and
|
|
Packit |
67cb25 |
:math:`p = 1` when
|
|
Packit |
67cb25 |
:math:`E_{i+1} \le E_i`.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
In other words, a step will occur if the new energy is lower. If
|
|
Packit |
67cb25 |
the new energy is higher, the transition can still occur, and its
|
|
Packit |
67cb25 |
likelihood is proportional to the temperature :math:`T` and inversely
|
|
Packit |
67cb25 |
proportional to the energy difference
|
|
Packit |
67cb25 |
:math:`E_{i+1} - E_i`.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. index::
|
|
Packit |
67cb25 |
single: cooling schedule
|
|
Packit |
67cb25 |
single: schedule, cooling
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The temperature :math:`T` is initially set to a high value, and a random
|
|
Packit |
67cb25 |
walk is carried out at that temperature. Then the temperature is
|
|
Packit |
67cb25 |
lowered very slightly according to a *cooling schedule*, for
|
|
Packit |
67cb25 |
example: :math:`T \rightarrow T/\mu_T`
|
|
Packit |
67cb25 |
where :math:`\mu_T` is slightly greater than 1.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The slight probability of taking a step that gives higher energy is what
|
|
Packit |
67cb25 |
allows simulated annealing to frequently get out of local minima.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Simulated Annealing functions
|
|
Packit |
67cb25 |
=============================
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. function:: void gsl_siman_solve (const gsl_rng * r, void * x0_p, gsl_siman_Efunc_t Ef, gsl_siman_step_t take_step, gsl_siman_metric_t distance, gsl_siman_print_t print_position, gsl_siman_copy_t copyfunc, gsl_siman_copy_construct_t copy_constructor, gsl_siman_destroy_t destructor, size_t element_size, gsl_siman_params_t params)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function performs a simulated annealing search through a given
|
|
Packit |
67cb25 |
space. The space is specified by providing the functions :data:`Ef` and
|
|
Packit |
67cb25 |
:data:`distance`. The simulated annealing steps are generated using the
|
|
Packit |
67cb25 |
random number generator :data:`r` and the function :data:`take_step`.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The starting configuration of the system should be given by :data:`x0_p`.
|
|
Packit |
67cb25 |
The routine offers two modes for updating configurations, a fixed-size
|
|
Packit |
67cb25 |
mode and a variable-size mode. In the fixed-size mode the configuration
|
|
Packit |
67cb25 |
is stored as a single block of memory of size :data:`element_size`.
|
|
Packit |
67cb25 |
Copies of this configuration are created, copied and destroyed
|
|
Packit |
67cb25 |
internally using the standard library functions :func:`malloc`,
|
|
Packit |
67cb25 |
:func:`memcpy` and :func:`free`. The function pointers :data:`copyfunc`,
|
|
Packit |
67cb25 |
:data:`copy_constructor` and :data:`destructor` should be null pointers in
|
|
Packit |
67cb25 |
fixed-size mode. In the variable-size mode the functions
|
|
Packit |
67cb25 |
:data:`copyfunc`, :data:`copy_constructor` and :data:`destructor` are used to
|
|
Packit |
67cb25 |
create, copy and destroy configurations internally. The variable
|
|
Packit |
67cb25 |
:data:`element_size` should be zero in the variable-size mode.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The :data:`params` structure (described below) controls the run by
|
|
Packit |
67cb25 |
providing the temperature schedule and other tunable parameters to the
|
|
Packit |
67cb25 |
algorithm.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
On exit the best result achieved during the search is placed in
|
|
Packit |
67cb25 |
:data:`x0_p`. If the annealing process has been successful this
|
|
Packit |
67cb25 |
should be a good approximation to the optimal point in the space.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
If the function pointer :data:`print_position` is not null, a debugging
|
|
Packit |
67cb25 |
log will be printed to :code:`stdout` with the following columns::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#-iter #-evals temperature position energy best_energy
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
and the output of the function :data:`print_position` itself. If
|
|
Packit |
67cb25 |
:data:`print_position` is null then no information is printed.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The simulated annealing routines require several user-specified
|
|
Packit |
67cb25 |
functions to define the configuration space and energy function. The
|
|
Packit |
67cb25 |
prototypes for these functions are given below.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_Efunc_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should return the energy of a configuration :data:`xp`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double (*gsl_siman_Efunc_t) (void *xp)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_step_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should modify the configuration :data:`xp` using a random step
|
|
Packit |
67cb25 |
taken from the generator :data:`r`, up to a maximum distance of
|
|
Packit |
67cb25 |
:data:`step_size`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void (*gsl_siman_step_t) (const gsl_rng *r, void *xp,
|
|
Packit |
67cb25 |
double step_size)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_metric_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should return the distance between two configurations
|
|
Packit |
67cb25 |
:data:`xp` and :data:`yp`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double (*gsl_siman_metric_t) (void *xp, void *yp)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_print_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should print the contents of the configuration :data:`xp`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void (*gsl_siman_print_t) (void *xp)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_copy_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should copy the configuration :data:`source` into :data:`dest`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void (*gsl_siman_copy_t) (void *source, void *dest)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_copy_construct_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should create a new copy of the configuration :data:`xp`::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void * (*gsl_siman_copy_construct_t) (void *xp)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_destroy_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This function type should destroy the configuration :data:`xp`, freeing its
|
|
Packit |
67cb25 |
memory::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void (*gsl_siman_destroy_t) (void *xp)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. type:: gsl_siman_params_t
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
These are the parameters that control a run of :func:`gsl_siman_solve`.
|
|
Packit |
67cb25 |
This structure contains all the information needed to control the
|
|
Packit |
67cb25 |
search, beyond the energy function, the step function and the initial
|
|
Packit |
67cb25 |
guess.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
========================================= ============================================================
|
|
Packit |
67cb25 |
:code:`int n_tries` The number of points to try for each step.
|
|
Packit |
67cb25 |
:code:`int iters_fixed_T` The number of iterations at each temperature.
|
|
Packit |
67cb25 |
:code:`double step_size` The maximum step size in the random walk.
|
|
Packit |
67cb25 |
:code:`double k, t_initial, mu_t, t_min` The parameters of the Boltzmann distribution and cooling
|
|
Packit |
67cb25 |
schedule.
|
|
Packit |
67cb25 |
========================================= ============================================================
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Examples
|
|
Packit |
67cb25 |
========
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The simulated annealing package is clumsy, and it has to be because it
|
|
Packit |
67cb25 |
is written in C, for C callers, and tries to be polymorphic at the same
|
|
Packit |
67cb25 |
time. But here we provide some examples which can be pasted into your
|
|
Packit |
67cb25 |
application with little change and should make things easier.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Trivial example
|
|
Packit |
67cb25 |
---------------
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The first example, in one dimensional Cartesian space, sets up an energy
|
|
Packit |
67cb25 |
function which is a damped sine wave; this has many local minima, but
|
|
Packit |
67cb25 |
only one global minimum, somewhere between 1.0 and 1.5. The initial
|
|
Packit |
67cb25 |
guess given is 15.5, which is several local minima away from the global
|
|
Packit |
67cb25 |
minimum.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. include:: examples/siman.c
|
|
Packit |
67cb25 |
:code:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
:numref:`fig_siman-test` is generated by running
|
|
Packit |
67cb25 |
:code:`siman_test` in the following way::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
$ ./siman_test | awk '!/^#/ {print $1, $4}'
|
|
Packit |
67cb25 |
| graph -y 1.34 1.4 -W0 -X generation -Y position
|
|
Packit |
67cb25 |
| plot -Tps > siman-test.eps
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
:numref:`fig_siman-energy` is generated by running
|
|
Packit |
67cb25 |
:code:`siman_test` in the following way::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
$ ./siman_test | awk '!/^#/ {print $1, $5}'
|
|
Packit |
67cb25 |
| graph -y -0.88 -0.83 -W0 -X generation -Y energy
|
|
Packit |
67cb25 |
| plot -Tps > siman-energy.eps
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. _fig_siman-test:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. figure:: /images/siman-test.png
|
|
Packit |
67cb25 |
:scale: 60%
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Example of a simulated annealing run: at higher temperatures (early in
|
|
Packit |
67cb25 |
the plot) you see that the solution can fluctuate, but at lower
|
|
Packit |
67cb25 |
temperatures it converges.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. _fig_siman-energy:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. figure:: /images/siman-energy.png
|
|
Packit |
67cb25 |
:scale: 60%
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Simulated annealing energy vs generation
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. index::
|
|
Packit |
67cb25 |
single: TSP
|
|
Packit |
67cb25 |
single: traveling salesman problem
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Traveling Salesman Problem
|
|
Packit |
67cb25 |
--------------------------
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The TSP (*Traveling Salesman Problem*) is the classic combinatorial
|
|
Packit |
67cb25 |
optimization problem. I have provided a very simple version of it,
|
|
Packit |
67cb25 |
based on the coordinates of twelve cities in the southwestern United
|
|
Packit |
67cb25 |
States. This should maybe be called the *Flying Salesman Problem*,
|
|
Packit |
67cb25 |
since I am using the great-circle distance between cities, rather than
|
|
Packit |
67cb25 |
the driving distance. Also: I assume the earth is a sphere, so I don't
|
|
Packit |
67cb25 |
use geoid distances.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The :func:`gsl_siman_solve` routine finds a route which is 3490.62
|
|
Packit |
67cb25 |
Kilometers long; this is confirmed by an exhaustive search of all
|
|
Packit |
67cb25 |
possible routes with the same initial city.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The full code is given below.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. include:: examples/siman_tsp.c
|
|
Packit |
67cb25 |
:code:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Below are some plots generated in the following way::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
$ ./siman_tsp > tsp.output
|
|
Packit |
67cb25 |
$ grep -v "^#" tsp.output
|
|
Packit |
67cb25 |
| awk '{print $1, $NF}'
|
|
Packit |
67cb25 |
| graph -y 3300 6500 -W0 -X generation -Y distance
|
|
Packit |
67cb25 |
-L "TSP - 12 southwest cities"
|
|
Packit |
67cb25 |
| plot -Tps > 12-cities.eps
|
|
Packit |
67cb25 |
$ grep initial_city_coord tsp.output
|
|
Packit |
67cb25 |
| awk '{print $2, $3}'
|
|
Packit |
67cb25 |
| graph -X "longitude (- means west)" -Y "latitude"
|
|
Packit |
67cb25 |
-L "TSP - initial-order" -f 0.03 -S 1 0.1
|
|
Packit |
67cb25 |
| plot -Tps > initial-route.eps
|
|
Packit |
67cb25 |
$ grep final_city_coord tsp.output
|
|
Packit |
67cb25 |
| awk '{print $2, $3}'
|
|
Packit |
67cb25 |
| graph -X "longitude (- means west)" -Y "latitude"
|
|
Packit |
67cb25 |
-L "TSP - final-order" -f 0.03 -S 1 0.1
|
|
Packit |
67cb25 |
| plot -Tps > final-route.eps
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
This is the output showing the initial order of the cities; longitude is
|
|
Packit |
67cb25 |
negative, since it is west and I want the plot to look like a map::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
# initial coordinates of cities (longitude and latitude)
|
|
Packit |
67cb25 |
###initial_city_coord: -105.95 35.68 Santa Fe
|
|
Packit |
67cb25 |
###initial_city_coord: -112.07 33.54 Phoenix
|
|
Packit |
67cb25 |
###initial_city_coord: -106.62 35.12 Albuquerque
|
|
Packit |
67cb25 |
###initial_city_coord: -103.2 34.41 Clovis
|
|
Packit |
67cb25 |
###initial_city_coord: -107.87 37.29 Durango
|
|
Packit |
67cb25 |
###initial_city_coord: -96.77 32.79 Dallas
|
|
Packit |
67cb25 |
###initial_city_coord: -105.92 35.77 Tesuque
|
|
Packit |
67cb25 |
###initial_city_coord: -107.84 35.15 Grants
|
|
Packit |
67cb25 |
###initial_city_coord: -106.28 35.89 Los Alamos
|
|
Packit |
67cb25 |
###initial_city_coord: -106.76 32.34 Las Cruces
|
|
Packit |
67cb25 |
###initial_city_coord: -108.58 37.35 Cortez
|
|
Packit |
67cb25 |
###initial_city_coord: -108.74 35.52 Gallup
|
|
Packit |
67cb25 |
###initial_city_coord: -105.95 35.68 Santa Fe
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
The optimal route turns out to be::
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
# final coordinates of cities (longitude and latitude)
|
|
Packit |
67cb25 |
###final_city_coord: -105.95 35.68 Santa Fe
|
|
Packit |
67cb25 |
###final_city_coord: -103.2 34.41 Clovis
|
|
Packit |
67cb25 |
###final_city_coord: -96.77 32.79 Dallas
|
|
Packit |
67cb25 |
###final_city_coord: -106.76 32.34 Las Cruces
|
|
Packit |
67cb25 |
###final_city_coord: -112.07 33.54 Phoenix
|
|
Packit |
67cb25 |
###final_city_coord: -108.74 35.52 Gallup
|
|
Packit |
67cb25 |
###final_city_coord: -108.58 37.35 Cortez
|
|
Packit |
67cb25 |
###final_city_coord: -107.87 37.29 Durango
|
|
Packit |
67cb25 |
###final_city_coord: -107.84 35.15 Grants
|
|
Packit |
67cb25 |
###final_city_coord: -106.62 35.12 Albuquerque
|
|
Packit |
67cb25 |
###final_city_coord: -106.28 35.89 Los Alamos
|
|
Packit |
67cb25 |
###final_city_coord: -105.92 35.77 Tesuque
|
|
Packit |
67cb25 |
###final_city_coord: -105.95 35.68 Santa Fe
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. figure:: /images/siman-initial-route.png
|
|
Packit |
67cb25 |
:scale: 60%
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Initial route for the 12 southwestern cities Flying Salesman Problem.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. figure:: /images/siman-final-route.png
|
|
Packit |
67cb25 |
:scale: 60%
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Final (optimal) route for the 12 southwestern cities Flying Salesman Problem.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Here's a plot of the cost function (energy) versus generation (point in
|
|
Packit |
67cb25 |
the calculation at which a new temperature is set) for this problem:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
.. figure:: /images/siman-12-cities.png
|
|
Packit |
67cb25 |
:scale: 60%
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Example of a simulated annealing run for the 12 southwestern cities
|
|
Packit |
67cb25 |
Flying Salesman Problem.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
References and Further Reading
|
|
Packit |
67cb25 |
==============================
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Further information is available in the following book,
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
* *Modern Heuristic Techniques for Combinatorial Problems*, Colin R. Reeves
|
|
Packit |
67cb25 |
(ed.), McGraw-Hill, 1995 (ISBN 0-07-709239-2).
|