Skip to content
  • Simulated Annealing & Beam Search · Artificial Intelligence

Simulated Annealing & Beam Search

LearnViaNotes @learnvianotes· 3 min read

Simulated annealing is hill climbing that sometimes accepts a worse move — often early on, rarely later — so it can shake itself out of local optima. Beam search keeps several states instead of one.

The name comes from metallurgy: heating metal and cooling it slowly lets atoms settle into a low-energy crystal. The algorithm picks a random neighbour; if it is better it always moves, and if it is worse by ΔE it moves with probability:

P(accept worse move) = e^(−ΔE / T)

Python
import math

accept = {T: [round(math.exp(-delta / T), 3) for delta in (1, 2, 5)] for T in (10, 1, 0.1)}
print(accept[10])      # [0.905, 0.819, 0.607] ← hot: almost any move is accepted (ΔE = 1, 2, 5)
print(accept[1])       # [0.368, 0.135, 0.007]
print(accept[0.1])     # [0.0, 0.0, 0.0] ← cold: pure hill climbing

The temperature T starts high (random walk) and decreases according to a schedule (e.g. T ← 0.99·T). As T → 0 it becomes plain hill climbing. If T is lowered slowly enough, it finds the global optimum with probability approaching 1.

Python
import math
import random

def conflicts(s):
    return sum(1 for i in range(8) for j in range(i + 1, 8) if s[i] == s[j] or abs(s[i] - s[j]) == j - i)

def simulated_annealing(state, T=2.0, cooling=0.995, steps=20000):
    for t in range(steps):
        if conflicts(state) == 0:
            return state, t
        col, row = random.randrange(8), random.randrange(8)
        nxt = state[:col] + (row,) + state[col + 1:]           # a random neighbour
        delta = conflicts(nxt) - conflicts(state)              # > 0 means worse
        if delta <= 0 or random.random() < math.exp(-delta / T):
            state = nxt
        T = max(T * cooling, 1e-3)                             # cooling schedule
    return state, steps

random.seed(1)
start = tuple(random.randrange(8) for _ in range(8))      # the start where hill climbing got stuck
end, t = simulated_annealing(start)
print(end, conflicts(end), t)                             # (2, 5, 7, 0, 3, 6, 4, 1) 0 711

Local beam search

Keep k states instead of one. Each step, generate all successors of all k states and keep the best k overall. Unlike k independent restarts, information is shared: states on a good hill attract the whole beam.

MethodStates keptAccepts worse moves?Complete?
Hill climbing1NoNo
Random-restart HC1 (many runs)NoWith probability → 1
Simulated annealing1Yes, with prob. e^(−ΔE/T)With a slow enough schedule (in the limit)
Local beam searchkOnly via the beamNo
Genetic algorithmPopulationYes (selection is stochastic)No

How does simulated annealing escape local optima?

Local beam search vs k random restarts?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report