Heuristic — local search (stochastic)
▶ Open interactive explainer →Simulated Annealing
| Alias | sa, simulated_annealing |
| Type | Heuristic — local search (stochastic) |
| Complexity | O(epochs · n) |
| Auto-seeds from | shuffle (random tour) |
| Benchmarks | published results ↓ |
Description
Probabilistic local search inspired by the annealing process in metallurgy. Each iteration proposes a random tour modification. Improvements are always accepted; worsenings are accepted with probability exp(−Δ/T), where T is the current “temperature”. Temperature decreases each step according to the cooling rate, so the algorithm transitions from broad exploration at high temperature to fine-tuned exploitation at low temperature.
Auto-expands to pipeline(shuffle, sa). The temperature schedule is calibrated for cold starts — seeding SA from a greedy NN tour constrains early exploration and typically worsens the final result. For a warm-started SA run use the classic preset (nn → 2opt → sa): the 2-opt stage removes edge crossings before SA fine-tunes the result.
procedure SimulatedAnnealing(cities, T_start, T_end, cooling):
tour ← random_tour(cities)
best ← tour
T ← T_start
while T > T_end:
neighbour ← random_2opt_swap(tour)
Δ ← length(neighbour) − length(tour)
if Δ < 0 or random() < exp(−Δ / T):
tour ← neighbour
if length(tour) < length(best):
best ← tour
T ← T × cooling
return best
Options
Both stopping rules are strict caps: the run ends at whichever is reached first. The
temperature schedule normally finishes first, and --epochs is a safety bound.
| Flag | Description | Default |
|---|---|---|
--max_temperature |
Starting temperature | 1000.0 |
--min_temperature |
Stopping temperature | 0.001 |
--cooling_rate |
Fractional temperature drop per step | 0.0001 |
--epochs |
Maximum iterations (safety cap) | derived — see below |
--epochs 0 means no epoch cap: the temperature schedule alone decides.
The default budget is sized above the cooling schedule, which is derived from the parameters as
ceil(ln(max/min) / -ln(1 - cooling_rate)) — matching the loop’s T ← T × (1 − cooling_rate).
At the defaults that schedule needs ~138,149 iterations; a slower rate needs far more (0.00001
requires ~1.38M). Setting --epochs below the schedule length is allowed but logged as a
warning: the run then stops while the temperature is still high, which accepts nearly every move
and looks like a poor solver rather than a truncated run.
Because the schedule is the primary stopping rule, a --min_temperature of 0 is rejected — the
loop stops on temperature <= min_temperature and the f32 cooling step never actually reaches
zero.
Usage
# auto-expands to pipeline(shuffle, sa)
teeline solve sa -i ./data/tsplib/berlin52.tsp
teeline solve sa -i ./data/tsplib/berlin52.tsp --verbose
# run SA from input city order (no shuffle)
teeline solve sa --no-seed -i ./data/tsplib/berlin52.tsp
# warm-start from a 2-opt-refined tour
teeline solve classic -i ./data/tsplib/berlin52.tsp
# custom temperature schedule
teeline solve sa -i ./data/tsplib/berlin52.tsp --cooling_rate=0.003 --max_temperature=500.0
References
- AIMA, Section 4.1.2 — Simulated Annealing
- Simulated annealing (Wikipedia)
- Kirkpatrick, S., Gelatt, C. D. & Vecchi, M. P. (1983) — “Optimization by Simulated Annealing”, Science, 220(4598), 671–680. DOI: 10.1126/science.220.4598.671
Benchmarks
Loading published results…