All Modules Annealing Genetic Tabu Exercise

Local Search & Optimization

Simulated annealing, local beam search, genetic algorithms and tabu search — how to keep improving a single solution when the state space is far too large to search in full.

Module 7 · Based on the course slides & Russell & Norvig, AIMA Chapter 4

Advanced Optimization ~60 min

What You'll Learn

  • Understand local search — optimising a single current state instead of building a path from a root
  • Escape local maxima with simulated annealing and its acceptance probability eΔE/T
  • Keep several candidates alive at once with local beam search
  • Evolve a population of solutions with a genetic algorithm — selection, crossover and mutation
  • Escape cycling with tabu search and apply it to a constrained minimum spanning tree

Prerequisites: Module 6 (Informed Search & A*), where hill climbing and heuristic evaluation were introduced. Local search is what you reach for when hill climbing alone keeps getting stuck.

A Different Kind of Search

Every search so far — BFS, DFS, A*, minimax — built a path from a start state to a goal, and the path itself was the answer. But for a huge class of problems the path is irrelevant: we only care about the final configuration. Where should eight queens sit so none attack? Which layout minimises wire length on a chip? What assignment of variables satisfies an equation? These are optimisation problems, and for them we use local search.

The idea of local search

  • Keep one current state (not a frontier of paths) and try to improve it by moving to a neighbour.
  • Use almost no memory — you forget how you got here — and can run on enormous or even infinite state spaces.
  • Judge a state by an objective function (also called the fitness or evaluation function). We picture it as a landscape: we want to climb to the highest peak (a global maximum) — or, equivalently, descend to the lowest valley (a global minimum).

The trouble with plain hill climbing — always step to the best neighbour, never step down — is that it halts at the first peak it reaches, even if that peak is a mere local maximum. The four methods in this module are all ways to break out of local optima and keep searching toward the global one.

A one-dimensional objective landscape with a local peak, a valley, and a taller global maximum
The objective landscape. Plain hill climbing from the current state would climb the small peak and stop; to reach the global max it must first accept a bad (downhill) move through the valley. (From the course notes.)

Simulated Annealing

A hill-climbing algorithm that never moves downhill is incomplete — it can get stuck on a local maximum. A purely random walk — move to a random neighbour regardless of value — is complete but hopelessly inefficient. Simulated annealing combines the two: mostly climb, but occasionally allow a "bad" move, and gradually reduce how often and how badly you are willing to go downhill.

Why "annealing"?

Annealing is the metallurgical process of heating a metal and cooling it slowly so its atoms settle into a strong, low-energy crystalline structure. Simulated annealing borrows the metaphor: a temperature parameter T starts high and is slowly lowered. Each time we cool, the probability of taking a bad move gets lower. Early on the search wanders freely (like a random walk); as it cools it behaves more and more like greedy hill climbing.

At each step, instead of picking the best neighbour, we pick a random neighbour and look at the change in objective value ΔE = next.VALUE − current.VALUE:

The acceptance rule

  • If ΔE > 0 (the move improves the state) — always accept it. We are on the right path.
  • If ΔE ≤ 0 (a downhill move) — accept it only with probability eΔE/T, a number less than 1.

That probability decreases exponentially with the "badness" of the move (the bigger the drop −ΔE, the less likely it is accepted) and also decreases as T falls (bad moves are common when hot, rare when cool).

function SIMULATED-ANNEALING(problem, schedule) returns a solution state // schedule maps time -> temperature current := MAKE-NODE(problem.INITIAL-STATE) for t := 1 todo T := schedule(t) if T = 0 then return current // frozen: stop and return next := a randomly selected successor of current ΔE := next.VALUE − current.VALUE if ΔE > 0 then current := next // uphill: always take it else current := next only with probability eΔE/T // downhill: maybe

Read the schedule as a cooling table: it hands out a temperature for each time step, starting high and shrinking toward zero.

TimeTemperature TBehaviour
t₁0.95Hot — downhill moves accepted readily (near random walk)
t₂0.90Cooling — still fairly exploratory
t₃0.85Bad moves becoming less likely
tₙ0Frozen — no more changes possible; return the current state

Cool slowly, or miss the peak

Once T reaches 0 the algorithm can no longer change — whatever state it is on is final, so if it froze on a local optimum it will not reach the goal. The theoretical guarantee is precise: if the schedule lowers T slowly enough, simulated annealing finds a global optimum with probability approaching 1. Cool too fast and you gamble. Simulated annealing is widely used in real optimisation such as VLSI chip layout and airline scheduling.

Local Beam Search

Simulated annealing keeps a single state. Local beam search keeps several. Instead of one current state it holds the k most promising nodes at once — the number k (also written B) is the beam width. At each level it expands all k nodes, gathers all their successors, and keeps only the best k of those to carry to the next level. The rest are discarded.

Definition

A heuristic search algorithm that examines a graph by extending the most promising nodes within a limited set. More than one node can be kept at each level — exactly k of them (the beam width). It is a middle ground between greedy best-first (which keeps everything on a frontier) and hill climbing (which keeps just one state).

A node fanning out to several successors, with only some kept in the beam
A node expands to many successors, but only the best few are kept in the beam. Widening the beam (a larger k) explores more and improves the result at the cost of memory. (From the course notes.)
PropertyLocal beam search
Complete?No — all k beams can converge and miss the goal.
Optimal?No — a better solution may be pruned away early.
TimeO(B · m)
SpaceO(B · m)

Here B is the beam width and m is the maximum path length.

Worked example (beam width k = 2)

Each node carries a heuristic estimate of its distance to the goal — smaller is better, and the goal node Z has value 0. We keep only the 2 most promising (lowest-value) nodes at each step. The numbers next to nodes are their heuristic values.

A search tree rooted at C, with node heuristic values, and the solution path C to O to I to Z highlighted
Local beam search with k = 2 toward goal Z; the highlighted path is the solution C → O → I → Z. (From the course notes.)

We track two lists: Open (nodes still to expand, capped at k = 2) and Closed (already expanded).

StepExpandOpen (best 2)Closed
0[C][ ]
1C → B14, T5, O7, E12, P15[T5, O7][C]
2T (a leaf, no children)[O7][C, T]
3O → I4, N44[I4, N44][C, T, O]
4I → Z0[Z0, N44][C, T, O, I]
5Z is the goal ✓Solution path: C → O → I → Z

At every step the Open list is trimmed back to the two lowest-valued nodes, so weak branches such as B, E and P are dropped immediately after C is expanded. Follow the surviving nodes and the path C → O → I → Z emerges — the goal is reached without ever expanding most of the tree.

Genetic Algorithms

A genetic algorithm (GA) is a search heuristic developed at the University of Michigan in the 1970s (John Holland), inspired by Darwin's theory of natural evolution. It mimics natural selection: the fittest individuals of a population are chosen to reproduce, passing their traits to the next generation. Instead of improving one state, a GA evolves a whole population of candidate solutions, generation after generation, until it converges on a global optimum.

The vocabulary of a GA

  • Gene — a single variable of the problem (e.g. x₁, x₂, x₃).
  • Chromosome — a group of genes: one complete candidate solution, e.g. [x₁ | x₂ | x₃].
  • Population — a group of chromosomes (many candidate solutions at once).
  • Fitness function — measures how good a chromosome is (its ability to "compete"). It is the objective function.

Say we must solve 2x₁ + 3x₂ + 4x₃ = 40, i.e. drive f = 2x₁ + 3x₂ + 4x₃ − 40 to 0. The genes are x₁, x₂, x₃. An initial population is generated at random — each chromosome is just a guess:

Chromosomex₁x₂x₃Binary encoding (alternative)
C₁91011001 1100 1000
C₂2341010 1001 111
C₃567

Chromosomes can be encoded as integers or as binary strings — binary makes the crossover and mutation operators especially simple, as we will see.

The genetic algorithm loop

1. Initialize population // random chromosomes 2. Evaluate population // compute fitness of each chromosome 3. while (stopping condition not met): Select parents for reproduction // fitter parents preferred Crossover (recombination) // mix two parents -> offspring Mutate the offspring // random small change Evaluate population // re-score by fitness

We keep producing offspring (“spring”) generation after generation until the population reaches the global optimum — or we accept the best local solution found. The fitness function determines how fit each individual is: its fitness score ranks it against the rest.

Reading fitness on our equation

For f(x) = 2x² + 3x − 44 the goal is f(x) = 0. Trying x = 3, 6, 7, 4 gives fitness values −17, 46, 76, 0. The value nearest zero is the best fitness — here x = 4 gives exactly 0, so it is the fittest (in fact an exact solution). This "distance from the target" is precisely what selection will reward.

Selection techniques

How do we pick which chromosomes get to reproduce? Four common techniques:

  • Random selection — pick parents at random (ignores fitness).
  • Roulette-wheel selection — give each chromosome a slice of a wheel proportional to its fitness, then "spin".
  • Elitism — always carry the best chromosome unchanged into the next generation, so the best solution is never lost.
  • Rank selection — rank all chromosomes and select by rank (helps when fitness values are very close).

In roulette-wheel selection each chromosome's selection probability is its fitness divided by the total fitness, and the cumulative probabilities carve the wheel into slices. Spinning a random number in [0, 1) lands in one slice — fatter slices (fitter chromosomes) are hit more often.

ChromosomeFitnessSelection prob.Cumulative
A1010/50 = 0.200.20
B2020/50 = 0.400.60
C1515/50 = 0.300.90
D55/50 = 0.101.00
Total501.00
A cumulative probability bar from 0 to 1 and a pie chart split A 20 percent, B 40, C 30, D 10
The wheel as a bar over [0, 1] (cut at 0.20, 0.60, 0.90) and as a pie: A 20%, B 40%, C 30%, D 10%. A spin of, say, 0.75 falls in C's slice. (From the course notes.)

Crossover (recombination)

Crossover creates new individuals by combining parts of two selected parents. Two parents go in, two offspring come out. The common types:

Single-point and double-point crossover on two binary parent strings
Single-point crossover swaps everything after one cut point; double-point crossover swaps the segment between two cut points. (From the course notes.)
  • Single-point: choose one cut point; offspring 1 = parent 1's head + parent 2's tail, offspring 2 the reverse.
  • Double-point: choose two cut points; swap the middle segment between the parents.
  • Uniform / arithmetic: decide each gene independently (uniform uses a random mask; arithmetic blends numeric genes).
Uniform crossover using a binary mask, and a mutation flipping a single bit
Uniform crossover: a random mask α decides, gene by gene, which parent each offspring inherits from. Mutation: flip a random bit of a chromosome (1010110 → 1000110). (From the course notes.)

Mutation keeps diversity alive

After crossover, mutation randomly alters a gene — flipping a bit in a binary chromosome, or nudging an integer. It happens with low probability, but it is essential: it injects fresh genetic material so the population does not prematurely converge and get stuck on a local optimum. Crossover exploits what the population already knows; mutation explores beyond it.

Tabu Search

Tabu search is a high-level meta-heuristic. Like the others it uses an iterative-improvement strategy — start from a random initial solution and keep moving to a better one — but it adds memory. Plain local search can get stuck on a local optimum, or worse, cycle back and forth between the same few states. Tabu search forbids recently visited moves so the search is forced to explore somewhere new. Together with genetic algorithms it is widely regarded as one of the most promising methods for hard practical problems.

"Meta-heuristic" = a constraint on the solution

A meta-heuristic sits above a basic search and steers it — imposing constraints that trade completeness for speed. It uses less time than an exhaustive search, but the constraints may cause it to miss the very best path. That is the bargain: good solutions fast, without a guarantee of the optimum.

Flowchart: initial solution, create candidate list, evaluate, choose best admissible, check stopping condition, loop or finish
The tabu search loop: from an initial solution, build a candidate list of neighbouring moves, evaluate them, choose the best admissible (non-tabu) one, and repeat until a stopping condition is met. (From the course notes.)

The three elements of tabu search

  • Current solution Xjcurrent — the optimised solution of n parameter values at iteration j.
  • Moves — the operations that generate trial (candidate) solutions from the current one.
  • Tabu restrictions — conditions that mark some moves as forbidden ("tabu"). Forbidden moves are held in a tabu list of a fixed size. Their purpose: prevent cycling and stop the search from returning to a local optimum it just left.

Application: Spanning Trees & a Constrained MST

A perfect setting for tabu search is the constrained minimum spanning tree. First, the plain version.

Spanning tree — definition

A spanning tree of a graph is a subgraph that includes all the vertices, is connected, and has no cycle (it is acyclic). It always has exactly |edges| = |vertices| − 1. A graph is connected when, from every node, you can reach every other node. The minimum spanning tree (MST) is the spanning tree of least total edge cost.

A connected weighted graph and a spanning tree that keeps all vertices with no cycle
A connected graph on 4 vertices and a spanning tree: 4 vertices → 4 − 1 = 3 edges, all connected, no cycle. (From the course notes.)

Kruskal's algorithm for the MST

Kruskal's algorithm builds the MST greedily: sort the edges by cost, then add the cheapest edge that does not create a cycle, repeating until the tree spans every vertex.

Kruskal's algorithm ordering edge costs and building a minimum spanning tree of cost 40
Sort the costs (a,b = 10; c,d = 15; a,d = 15; b,d = 20; a,c = 20), then accept the cheapest edges that avoid a cycle. Accepting a-b, c-d, a-d gives an MST of cost 10 + 15 + 15 = 40 — the global optimum; b,d and a,c are skipped because they would close a cycle. (From the course notes.)

Now add constraints — and let tabu search solve it

Kruskal finds the cheapest tree, but real networks come with side constraints that a greedy build cannot honour. Consider this graph with edge costs AB=20, BE=30, AC=10, CE=5, AD=15, CD=25, DE=40, plus two rules enforced by penalties added to the cost:

The constrained MST graph and an initial spanning tree solution
Top: the full weighted graph. Bottom: an initial spanning tree (AB, AC, AD, CE). (From the course notes.)

The two constraints (as penalties)

  • Constraint 1: link AD may be included only if link DE is also included — otherwise a penalty of 100.
  • Constraint 2: at most one of the three links AD, CD, AB may be included — penalty 100 if two of the three are selected, 200 if all three.

Without any constraint the MST costs AC(10) + CE(5) + AB(20) + AD(15) = 50 — the true global optimum. But that tree includes AD without DE (breaks Constraint 1) and includes two of {AD, AB} (Constraint 2), so its real cost with penalties is much higher. The initial solution shown scores 250. Tabu search now improves it step by step.

Generating candidates. To change a spanning tree you add one edge — which creates a cycle — and delete one edge from that cycle to restore the tree. Each add/delete pair is a candidate move; we score all of them (base cost + penalties) and pick the best admissible one.

Adding a dashed edge to the tree creates a cycle that must be broken by deleting one edge
Adding an edge (dashed) creates a cycle; to keep a valid tree you must delete one edge from that cycle. (From the course notes.)
AddDeleteCost = base + penalties
BECE75 + 100 + 100 = 275
AC70 + 100 + 100 = 270
AB60 + 100 + 0 = 160
CDAD60 + 100 = 160
AC65 + 100 + 200 = 365
DECE85 + 100 + 0 = 185
AC80 + 100 + 0 = 180
AD75 + 0 + 0 = 75  ✓ admissible

The winning move — and the tabu list

The best admissible candidate is add DE, delete AD, scoring 75 with zero penalties: DE is now in (so AD's Constraint 1 no longer applies) and only one of {AD, CD, AB} remains (Constraint 2 satisfied). This tree (AB, AC, CE, DE) becomes the new current solution. Cost 75 is a local optimum, so the search will iterate again — and crucially, if an already-visited solution reappears it is forbidden and added to the tabu list, guaranteeing the search cannot cycle back.

Exercise

Three problems, one per method. Work each on paper before revealing the solution.

1

Simulated annealing: accept or reject?

The current state has value 50. A randomly chosen neighbour has value 46, so ΔE = −4 (a downhill move). Should simulated annealing accept it? Compute the acceptance probability eΔE/T at a hot temperature T = 8 and a cool temperature T = 1, and explain what the two numbers tell you.

Because ΔE = −4 < 0 the move is not automatically accepted; it is taken only with probability eΔE/T.

  • At T = 8: e−4/8 = e−0.50.61 — a 61% chance of accepting. When hot, even a fairly bad move is likely taken.
  • At T = 1: e−4/1 = e−40.018 — under a 2% chance. When cool, the same bad move is almost always rejected.

This is the whole point of the cooling schedule: early on (hot) the search explores freely and can climb out of local optima; later (cool) it commits, behaving like greedy hill climbing. Note also that a worse move — say ΔE = −20 — would give e−2.5 ≈ 0.08 even at T = 8: the bigger the drop, the less likely the acceptance.

2

Genetic algorithm: fitness, selection & crossover

Solve 3x₁ − 2x₂ + 4x₃ + 5x₄ = 82 with genes constrained to 0 ≤ xₕ ≤ 9. Fitness is the error |3x₁ − 2x₂ + 4x₃ + 5x₄ − 82| (so 0 is a perfect solution). Using the population below: (a) verify the fitness values, (b) compute each chromosome's selection probability Fₕ/ΣF and the cumulative probabilities, and (c) do a single-point crossover (cut after gene 2) of parents E and B.

Chromosomex₁x₂x₃x₄Fitness
A453828
B378245
C76598
D942625
E215723
F380944

(a) Verify fitness — plug into |3x₁ − 2x₂ + 4x₃ + 5x₄ − 82|:

  • A: 12 − 10 + 12 + 40 = 54; |54 − 82| = 28
  • B: 9 − 14 + 32 + 10 = 37; |37 − 82| = 45
  • C: 21 − 12 + 20 + 45 = 74; |74 − 82| = 8 ✓ (fittest)
  • D: 27 − 8 + 8 + 30 = 57; |57 − 82| = 25
  • E: 6 − 2 + 20 + 35 = 59; |59 − 82| = 23
  • F: 9 − 16 + 0 + 45 = 38; |38 − 82| = 44

(b) Selection probabilities. Total fitness ΣF = 28+45+8+25+23+44 = 173. Dividing each by 173 and running the cumulative sum:

ChromosomeFₕ/ΣFCumulative
A28/173 = 0.1620.162
B45/173 = 0.2600.422
C8/173 = 0.0460.468
D25/173 = 0.1450.613
E23/173 = 0.1330.746
F44/173 = 0.2541.000

These cumulative cut-points (0.162, 0.422, 0.468, 0.613, 0.746, 1.0) are the roulette-wheel slices: a random spin lands in exactly one chromosome's interval. (Note: because fitness here is an error we want to minimise, a practical GA would select on an inverted score so that low-error chromosomes get the fat slices; the mechanics of computing the wheel are identical.)

(c) Single-point crossover of E and B, cut after gene 2:

  • E = (2, 1 | 5, 7), B = (3, 7 | 8, 2)
  • Offspring 1 = E's head + B's tail = (2, 1, 8, 2)
  • Offspring 2 = B's head + E's tail = (3, 7, 5, 7)

A subsequent mutation might then flip one gene of an offspring (e.g. the first gene) before it re-enters the population for the next round of evaluation.

3

Tabu search: pick the best admissible move

In the constrained-MST example, from the initial tree the candidate move “add DE can break its cycle by deleting CE (cost 185), AC (cost 180), or AD (cost 75). Which of the three do you choose, and why is its penalty zero? What role does the tabu list play afterwards?

Choose add DE, delete AD — cost 75, the lowest of the three (and the best admissible move in the whole candidate list).

Its penalty is zero because both constraints are now satisfied:

  • Constraint 1 (AD only if DE): we removed AD entirely, so the rule cannot be violated — no 100 penalty.
  • Constraint 2 (at most one of AD, CD, AB): with AD gone, only AB remains from that trio — one link, so no penalty.

The other two options keep AD in the tree, so they still carry the 100 penalty from Constraint 1 (hence 185 and 180). After committing to the cost-75 tree, the search continues from there; should a previously visited solution resurface as a candidate, it is declared tabu and added to the tabu list, which stops the search from cycling back to a local optimum it has already left.

Recap & Where Next

You now know

  • Local search optimises a single current state (or a small set) using an objective/fitness function — ideal when only the final configuration matters and the state space is huge.
  • Simulated annealing escapes local maxima by accepting bad moves with probability eΔE/T, cooling from exploration to exploitation; slow cooling → global optimum with probability → 1.
  • Local beam search keeps the best k nodes at each level — O(B·m) time and space, complete/optimal: no.
  • Genetic algorithms evolve a population via selection (roulette wheel, elitism, rank), crossover (single/double/uniform) and mutation.
  • Tabu search is a meta-heuristic that uses a tabu list to forbid recent moves and prevent cycling — demonstrated on a constrained minimum spanning tree built with Kruskal-style add/delete moves.

Local search builds on the systematic search of Modules 4–6, trading path-finding for the optimisation of a final configuration. Next comes Module 8: Adversarial Search & Games — searching when a second, hostile agent is making moves too. After that the syllabus turns to knowledge and reasoning — knowledge representation, logic and inference, and then machine learning — where the question shifts from "how do we search?" to "how do we represent what we know and draw conclusions from it?"

Local Search

Objectives A Different Kind of Search Simulated Annealing Local Beam Search Genetic Algorithms Tabu Search Spanning Trees & MST Exercise Recap