| Did you know ... | Search Documentation: |
| Pack logtalk -- logtalk-3.98.0/library/simulated_annealing/NOTES.md |
This file is part of Logtalk https://logtalk.org/ SPDX-FileCopyrightText: 1998-2026 Paulo Moura <pmoura@logtalk.org> SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
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.
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.
| ?- simulated_annealing(quadratic)::run(State, Energy).
State = 3.001..., Energy = 0.000...
| ?- simulated_annealing(quadratic)::run(State, Energy, [max_steps(50000)]).
State = 3.000..., Energy = 0.000...
| ?- simulated_annealing(quadratic)::run(State, Energy, Stats, []).
State = 3.001..., Energy = 0.000...,
Stats = [steps(10000), acceptances(...), improvements(...), final_temperature(...)]
| ?- simulated_annealing(quadratic)::run(S1, E1, [seed(42)]),
simulated_annealing(quadratic)::run(S2, E2, [seed(42)]).
S1 = S2, E1 = E2.
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...
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 = ...
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...