Part IV · trunk C · constraint programming and SAT · spine
Which variable next, which value first, when to give up and start again — and how destroy-and-repair turns an exact engine into a heuristic that scales.
needs 18~1¾ h slides + 2½ h lablab: uv run co lab 19
19 · overview
Variable and value ordering: first-fail, dom/wdeg, impact, activity; symmetry.
Runtime distributions, and why they justify randomisation and restarts.
Luby's universal schedule; what to remember across restarts.
Destroy and repair with the propagator as the repair engine.
Words with a dotted underline are glossary terms: click one for its definition. G lists every term in the unit, N shows the notes. Optional extra: interactive figures, linked from the slides they support by a small ▸ chip; skip them freely.
section 1
Fail first; succeed first.
19 · heuristics
Variables: fail first (Haralick & Elliott 1980). Branch where a dead end is most likely, so it is found near the root.
Values: succeed first. Try the value most likely to lead to a solution. It matters only for satisfiable subtrees; for proofs, every value is tried anyway.
14 easy three-valued variables in a chain, plus 5 variables that must all differ over 4 values. first-fail branches on the chain (smaller domains): more than 20 000 nodes, unfinished. dom/wdeg learns from the first failures that the ≠ clique is where they come from: under 500 nodes to prove infeasibility.
On QCP, where all constraints look alike, dom/wdeg is worse than randomised first-fail (lab then). Heuristics are instance-family bets.
19 · heuristics · example
Four variables on a cycle of $\ne$ constraints: $c_1: x \ne y$, $c_2: y \ne z$, $c_3: z \ne w$, $c_4: x \ne w$. Domains: $x, y \in \{0,1,2\}$, $z, w \in \{0,1\}$. Every weight starts at 1.
Score $= |D| / \text{wdeg}$, where wdeg adds the weights of the variable's constraints. Branch on the smallest score (ties: lowest index).
At the start plain first-fail and dom/wdeg agree: $z$, the smallest domain. After failures in $c_1$, the two variables of $c_1$ get cheaper to pick, and by the second failure $x$ wins outright. The variables far from the failures, $z$ and $w$, never move.
| moment | weight of $c_1$ | $x$ | $y$ | $z$ | $w$ | branch on |
|---|---|---|---|---|---|---|
| start | 1 | 3/2 | 3/2 | 2/2 | 2/2 | $z$ |
| $c_1$ fails once | 2 | 3/3 | 3/3 | 2/2 | 2/2 | $x$ (4-way tie) |
| twice | 3 | 3/4 | 3/4 | 2/2 | 2/2 | $x$ |
| three times | 4 | 3/5 | 3/5 | 2/2 | 2/2 | $x$ |
Three failures turn a variable with a larger domain into the preferred branch: search moves to where the conflicts are.
section 2
Most runs are fast. A few never end.
19 · heavy tails
Lab then: quasigroup completion, order 12, 55% holes, 100 seeds of randomised first-fail, nodes to a solution (its runtime distribution):
16–31 ███████████████████████████████████ 51
32–63 ████████████████ 24
64–127 ████████ 12
128–255 █████ 8
512–1023 █ 2
cap 3000 ██ 3
Median 31, p90 174, and 3 runs never finished within 3 000 nodes. The only difference between runs is tie-breaking.
Backtracking search on many CSP and SAT families has runtimes with Pareto-like tails, a heavy tail: $P(T > t) \sim C t^{-\alpha}$, often with $\alpha < 1$, which means infinite mean in the limit.
Cause: an early mistake puts search in a subtree with no solution that it must exhaust. Its size is exponential in how early the mistake happened.
A heavy tail makes the mean a poor summary and a single run a lottery ticket. It also points to the fix: don't wait.
section 3
Cut the tail off.
19 · restarts
You don't know the right cutoff. The Luby sequence tries every power of two, and spends about the same total effort on each, so whichever cutoff was right, it is used often enough. Nothing that doesn't know the distribution does much better.
precise statement in the notes (N)
Geometric schedules ($c \cdot r^i$) are the common alternative. SAT solvers now also restart adaptively, when recent conflicts look worse than average (Audemard & Simon 2012).
Lab then, 100 seeds, base 30:
| instance | strategy | mean | median | max |
|---|---|---|---|---|
| heavy (55%) | plain | 153.6 | 31 | 3 000 cap |
| Luby | 52.1 | 49.5 | 202 | |
| light (58%) | plain | 48.7 | 35 | 668 |
| Luby | 92.3 | 93 | 217 |
A restart cuts the tail, and with it the (capped) mean, but only where there is a tail to cut: without one, restarts hurt. On the light instance they double the mean. Corrected after unit 28: the median difference on the heavy instance is within its bootstrap interval.
19 · restarts · example
| run $i$ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| luby($i$) | 1 | 1 | 2 | 1 | 1 | 2 | 4 | 1 | 1 | 2 | 1 | 1 | 2 | 4 | 8 |
| cutoff (base 30) | 30 | 30 | 60 | 30 | 30 | 60 | 120 | 30 | 30 | 60 | 30 | 30 | 60 | 120 | 240 |
| total so far | 30 | 60 | 120 | 150 | 180 | 240 | 360 | 390 | 420 | 480 | 510 | 540 | 600 | 720 | 960 |
How it grows: the first $2^k - 1$ terms are two copies of the first $2^{k-1} - 1$ terms, then $2^{k-1}$. Runs 1–7 repeat as runs 8–14, then 8 appears.
On the heavy instance, half the runs finish within 31 nodes. A cutoff of 30 or 60 catches those, and twelve of the first fifteen runs have one of those cutoffs.
The rare long runs never get to run long: the biggest cutoff in 960 nodes of work is 240, where plain search once spent over 3 000.
Each cutoff size gets about equal total effort: runs of 30 use 240 nodes, runs of 60 use 240, runs of 120 use 240, and the single 240.
19 · restarts
A decision nogood such as "$x_1 = 3 \wedge x_4 = 1$ fails" is weak: it mentions decisions, not reasons. The strong form records why it failed, the propagators and removed values responsible. That's clause learning, the core of CDCL SAT solvers (unit 20), and lazy clause generation brings it to CP (unit 21). (How search uses reasons to skip subtrees, and why it stays complete: unit 19b.)
Lab then's 3-colouring in unit 17 was that difference: 120 334 nodes without learning, 3 106 branches with.
section 4
The exact engine, as a heuristic's inner loop.
19 · LNS
Large neighbourhood search: Shaw (1998) introduced it for vehicle routing with CP repair. ALNS (Ropke & Pisinger 2006) chooses among several destroy operators adaptively.
Lab then, random job-shops, 22 500 nodes each, makespan:
| instance | greedy | LNS | branch-and-bound |
|---|---|---|---|
| 8 × 4 | 54 | 49 | 57 |
| 10 × 5 | 72 | 66 | 77 |
| 12 × 6 | 117 | 78 | 84 |
Branch-and-bound spends its budget at the bottom of one subtree. LNS spends it around a good schedule, where the improvements are.
19 · LNS · example
| job | operations (machine, duration) |
|---|---|
| J0 | M1 5, then M0 2, then M2 4 |
| J1 | M2 3, then M0 2, then M1 2 |
| J2 | M0 1, then M2 4, then M1 5 |
Destroy: free job J1. On every machine, J0 and J2 keep their order: M0 J2 before J0, M1 J0 before J2, M2 J2 before J0.
Repair: search where J1 goes, with makespan $\le 15$. Propagation places it in the gaps: M0 at 3–5, M1 at 5–7. J2's last operation moves up to 7–12.
Makespan 16 → 12, which brute force confirms is optimal.
Outline colour is the job; J1, red, is the freed job. In the greedy schedule J1 waits for M0 until time 7, which pushes J2's M1 operation to 11–16.
19 · LNS
Several workers in parallel: different search strategies, restarts, and many LNS workers (random, graph-based, relaxation-induced, scheduling-specific) sharing one incumbent.
Lab then, 30 × 15 job-shop (durations 1–99), 10 s:
| configuration | makespan | bound |
|---|---|---|
| 8 workers, LNS on | 1837–1851 | 1828 |
| 8 workers, LNS off | 1852 | 1828 |
| 1 worker | 2047–2049 | 1828 |
The LNS switch is within run-to-run noise here. The portfolio (8 workers against 1) is the big effect.
A local search engine with a CP core: a first solution, then guided local search over routing neighbourhoods.
| n | unit 10 LP bound | routing, 5 s | gap |
|---|---|---|---|
| 12 | 422.0 | 442 | 4.5% |
| 16 | 478.2 | 483 | 1.0% |
| 20 | 662.0 | 680 | 2.6% |
The LP bound from unit 10 certifies how good the heuristic solution is.
19 · lab
uv run co test 19
uv run co then 19 # histograms · LNS vs B&B · CP-SAT portfolio · OR-Tools routing
19 · checkpoint
Gomes et al., J. Automated Reasoning 24 (2000).
Luby, Sinclair & Zuckerman, IPL 47 (1993).
Boussemart et al., ECAI 2004.
Shaw, CP 1998.
19b backjumping and why search is complete · 20 SAT and CDCL: learning from conflicts · 21 lazy clause generation · 26 local search and metaheuristics.