| Did you know ... | Search Documentation: |
| Pack logtalk -- logtalk-3.98.0/docs/handbook/_sources/libraries/simulated_annealing.rst.txt |
.. _library_simulated_annealing:
simulated_annealingSimulated annealing is a probabilistic meta-heuristic for approximating the global optimum of a given function. It is particularly useful for combinatorial optimization problems such as the Traveling Salesman Problem (TSP), graph coloring, and scheduling.
The library provides the parametric object
simulated_annealing(Problem, RandomAlgorithm) where Problem is
an object implementing the simulated_annealing_protocol protocol and
RandomAlgorithm is one of the algorithms supported by the
fast_random library. The algorithm minimizes the energy (cost)
function defined by the problem.
A convenience object simulated_annealing(Problem) is also provided,
using the Xoshiro128++ random number generator (xoshiro128pp) as the
default.
Open the `../../docs/library_index.html#simulated-annealing <../../docs/library_index.html#simulated-annealing>`__ link in a web browser.
To load all entities in this library, load the loader.lgt file:
::
| ?- logtalk_load(simulated_annealing(loader)).
To test this library predicates, load the tester.lgt file:
::
| ?- logtalk_load(simulated_annealing(tester)).
fast_random algorithm. Available algorithms
include xoshiro128pp, xoshiro128ss, xoshiro256pp,
xoshiro256ss, well512a, splitmix64, and as183. The
convenience object simulated_annealing(Problem) defaults to
xoshiro128pp.exp(-DeltaE / Temperature), allowing the search to
escape local minima early in the run while converging as the
temperature cools.NewTemp is Temp * 0.995), overridable by defining
cooling_schedule/3 in the problem object.seed(S) option initializes the random
number generator for reproducible runs.restarts(N) option runs N additional
SA cycles after the first. Each restart reheats the temperature to the
initial value and begins from the best state found so far, allowing
the search to escape deep local minima. Statistics accumulate across
all cycles.estimate_temperature/1-2
predicates sample random neighbor transitions and compute an initial
temperature that would produce a target acceptance rate, avoiding
manual tuning.
A problem object must implement the simulated_annealing_protocol
protocol by defining (at least) the following four predicates:
initial_state(-State) â returns the starting state.neighbor_state(+State, -Neighbor) â generates a neighboring state.state_energy(+State, -Energy) â computes the cost of a state (to
be minimized).initial_temperature(-Temperature) â returns the starting
temperature.
Optionally, the problem object may also define:
neighbor_state(+State, -Neighbor, -DeltaEnergy) â generates a
neighboring state and returns the energy change directly, avoiding a
full energy recomputation. Useful when computing the delta is cheaper
than recomputing the full energy (e.g. TSP with a 2-opt swap).cooling_schedule(+Temperature, +Step, -NewTemperature) â computes
the next temperature. Default: geometric cooling
(NewTemp is Temp * 0.995).stop_condition(+Step, +Temperature, +BestEnergy) â succeeds when
the search should terminate early (e.g. when a good-enough solution is
found). Default: the search runs until the maximum number of steps is
reached or the temperature drops below the minimum temperature.progress(+Step, +Temperature, +BestEnergy, +AcceptanceRate, +ImprovementRate)
â called periodically during the optimization to report progress. A
final report is always produced when the loop terminates. The
acceptance and improvement rates are floats between 0.0 and 1.0.
Options for the run/3-4 predicates:
max_steps(N) â maximum number of iterations per cycle (default:
10000).min_temperature(T) â minimum temperature floor; the search stops
when the temperature drops below this value (default: 0.001).updates(N) â number of progress reports during the run. Progress
is reported by calling progress/5 on the problem object. Set to
0 to disable (default: 0).seed(S) â positive integer seed for the random number generator,
enabling reproducible runs (default: none).restarts(N) â number of additional SA cycles after the first. Each
restart reheats the temperature to the initial value and begins from
the best state found so far, allowing the search to escape local
minima (default: 0).
Options for the estimate_temperature/2 predicate:
samples(N) â number of random neighbor transitions to sample
(default: 200).acceptance_rate(P) â target initial acceptance rate as an integer
percentage between 1 and 99 (default: 80).The run/4 predicate returns a list of statistics about the completed run:
steps(N) â total number of steps executed.acceptances(A) â number of accepted moves (both improving and
uphill).improvements(I) â number of moves that strictly improved the best
energy found.final_temperature(T) â temperature at termination... _defining-a-problem-1:
Defining a problem
Define an object implementing the ``simulated_annealing_protocol``
protocol. For example, a simple quadratic minimization problem:
::
:- object(quadratic,
implements(simulated_annealing_protocol)).
initial_state(50.0).
neighbor_state(X, Y) :-
random::random(-5.0, 5.0, Delta),
Y is X + Delta.
state_energy(X, E) :-
E is (X - 3.0) * (X - 3.0).
initial_temperature(100.0).
:- end_object.
Running the algorithm
~~~~~~~~~~~~~~~~~~~~~
::
| ?- simulated_annealing(quadratic)::run(State, Energy).
State = 3.001..., Energy = 0.000...
Running with custom options
~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
| ?- simulated_annealing(quadratic)::run(State, Energy, [max_steps(50000)]).
State = 3.000..., Energy = 0.000...
Running with statistics
~~~~~~~~~~~~~~~~~~~~~~~
::
| ?- simulated_annealing(quadratic)::run(State, Energy, Stats, []).
State = 3.001..., Energy = 0.000...,
Stats = [steps(10000), acceptances(...), improvements(...), final_temperature(...)]
Reproducible runs with seed
~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
| ?- simulated_annealing(quadratic)::run(S1, E1, [seed(42)]),
simulated_annealing(quadratic)::run(S2, E2, [seed(42)]).
S1 = S2, E1 = E2.
Reheating restarts
Run 3 SA cycles (1 initial + 2 restarts). Each restart reheats the temperature and begins from the best state found so far:
::
| ?- simulated_annealing(quadratic)::run(State, Energy, [restarts(2)]).
State = 3.000..., Energy = 0.000...
Auto-temperature estimation ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Estimate a good initial temperature for the problem by sampling random neighbor transitions:
::
| ?- simulated_annealing(quadratic)::estimate_temperature(T).
T = ...
With custom parameters (500 samples, 90% target acceptance rate):
::
| ?- simulated_annealing(quadratic)::estimate_temperature(T, [samples(500), acceptance_rate(90)]).
T = ...
Using a custom random number generator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the two-parameter version to select a specific fast_random
algorithm:
::
| ?- simulated_annealing(quadratic, well512a)::run(State, Energy).
State = 3.001..., Energy = 0.000...
| ?- simulated_annealing(quadratic, xoshiro256ss)::run(State, Energy, [seed(42)]).
State = 3.000..., Energy = 0.000...