Part 0 · the ground floor · spine
What a combinatorial problem is, the nine you will meet all course, and the one tool that lets you believe your own code.
needs nothing~1¼ h slides + 2 h lablab: uv run co lab 00
00 · overview
Problem vs instance. A feasible set described implicitly. Decision, optimization, counting.
Knapsack, set cover, assignment, bin packing, colouring, max-cut, TSP, job-shop, vertex cover.
Test every algorithm against an oracle. Ask what would prove an answer optimal, not just what the answer is.
Roadmap: definitions → the nine → spaces and symmetry → certificates → the oracle and the harness → the wall.
Words with a dotted underline are glossary terms: click one for its definition. G lists every term in the unit, N shows the notes. One small graph, the running example, comes back on most slides; a solid underline like that one shows it on hover. Optional extra: interactive figures, linked from the slides they support by a small ▸ chip; skip them freely.
section 1
Finite, but only in the least useful sense of the word.
00 · definitions
An optimization problem is a set of instances. An instance is a pair $(F, c)$: a feasible set $F$ and an objective $c : F \to \mathbb{R}$. We want $x^* \in F$ with $c(x^*) \le c(x)$ for all $x \in F$ (or $\ge$, for maximization).
$F$ is finite, and given implicitly: a simple, enumerable space $S$ and constraints, $\;F = \{x \in S : x \text{ satisfies the constraints}\}$.
Example. Vertex cover: an instance is a graph $G=(V,E)$. The space is $S = \{0,1\}^V$, the constraints are $x_u + x_v \ge 1$ for every $uv \in E$, and the objective is $c(x) = \sum_v x_v$, to be minimized. In words: pick the fewest vertices so that every edge touches one of them. The next slide does it on one graph.
00 · definitions · example
A triangle $0,1,2$ with one extra edge to vertex $3$. Four edges: $01,\ 02,\ 12,\ 23$. A candidate is $x \in \{0,1\}^4$, the vertices it picks.
| candidate $x$ | picks | uncovered edges | $c(x)$ |
|---|---|---|---|
| $(0,1,1,0)$ | $\{1, 2\}$ | none ✓ | 2 |
| $(1,1,0,1)$ | $\{0, 1, 3\}$ | none ✓ | 3 |
| $(0,0,1,1)$ | $\{2, 3\}$ | $01$ ✗ | — |
| $(0,0,1,0)$ | $\{2\}$ | $01$ ✗ | — |
Feasibility is checking every edge. $\{2,3\}$ misses edge $01$, so it is not in $F$ and its size doesn't matter. Of all $2^4 = 16$ candidates, 7 are covers, and the smallest have 2 vertices.
The space $S$ is all 16 candidates. The feasible set $F$ is the 7 covers. Nobody wrote $F$ down: the four edge constraints describe it.
Filled: the cover $\{1,2\}$. Every edge has a filled end.
00 · definitions
| space | size | at $n = 50$ |
|---|---|---|
| subsets, $\{0,1\}^n$ | $2^n$ | $1.1 \times 10^{15}$ |
| set partitions | Bell $B_n$ | $1.9 \times 10^{47}$ |
| tours from a fixed city | $(n-1)!$ | $6.1 \times 10^{62}$ |
Enumerating is always correct and almost always useless.
The running example has $2^4 = 16$ candidates. Each vertex added doubles that: a graph with 50 vertices has the number in the first row.
Almost always useless, but it is not worthless: for $n \lesssim 20$ it is the only solver whose correctness you can see by reading it.
At a billion candidates a second, $2^{50}$ takes 13 days. $(50-1)!$ takes about $10^{46}$ years.
00 · definitions
| version | asks | on the running example, $k = 2$ |
|---|---|---|
| decision | is there $x \in F$ with $c(x) \le k$? | is there a cover with at most 2 vertices? yes (with $k = 1$: no) |
| evaluation | what is $\min_{x\in F} c(x)$? | the smallest cover has 2 vertices |
| search / optimization | find an $x^*$ achieving it | here is one: $\{1, 2\}$ |
| counting | how many $x \in F$ have $c(x) \le k$? | 2 covers: $\{1, 2\}$ and $\{0, 2\}$ |
For integer objectives of polynomial bit size, the first three are equally hard, up to polynomial factors. Counting can be much harder.
Decision to evaluation: ask $k = 0, 1, 2, \dots$ and stop at the first yes. Evaluation to search: delete vertex 0 and its edges. The rest ($12$, $23$) needs 1, one less than 2, so some best cover uses 0. Keep it and repeat on the rest.
section 2
Each one is the textbook example of at least one technique later in the course.
00 · the nine
subsets orderings partitions schedules
00 · the nine
what an oracle needs
def feasible(G, x):
return all(x[u] or x[v]
for u, v in G.edges)
def objective(G, x):
return sum(x)
Parts I–II
$$\begin{aligned}\min\ & \textstyle\sum_{v} x_v \\ \text{s.t. } & x_u + x_v \ge 1 \quad \forall uv \in E \\ & x \in \{0,1\}^V\end{aligned}$$Part IV
x = [model.NewBoolVar(f"x{v}")
for v in V]
for u, v in E:
model.AddBoolOr(x[u], x[v])
model.Minimize(sum(x))
Same feasible set, three languages. What differs is what a solver can infer from the description without enumerating.
00 · spaces
Bin packing, $n$ items. Two spaces, the same feasible packings:
| space | size | $n = 10$ |
|---|---|---|
| every map item → bin | $n^n$ | 10 000 000 000 |
| set partitions | $B_n$ | 115 975 |
The first space counts every relabelling of the bins as a new packing. The second counts each packing once: 86 000× fewer.
$a_0 = 0,\quad a_i \le 1 + \max(a_0,\dots,a_{i-1})$
$a_i$ is item $i$'s bin. Bins are opened in order, so each partition of $\{0,\dots,n-1\}$ has exactly one string. The next slide lists them for $n = 3$.
This is symmetry breaking. Later it is the biggest single lever on real MIP and CP models (units 05, 27).
00 · spaces · example
Every restricted growth string for $n = 3$, and the set partition it names. Read $a_i$ as "item $i$ goes in bin $a_i$".
| string | bins | why it is allowed |
|---|---|---|
000 | $\{0,1,2\}$ | never opens a new bin |
001 | $\{0,1\}\ \{2\}$ | item 2 opens bin 1 |
010 | $\{0,2\}\ \{1\}$ | item 1 opens bin 1 |
011 | $\{0\}\ \{1,2\}$ | item 1 opens bin 1 |
012 | $\{0\}\ \{1\}\ \{2\}$ | each item opens the next bin |
Not allowed: 002 skips bin 1, and 100 starts at bin 1. Both are relabellings of strings already in the table (001, and 011). That is the symmetry being removed.
Items of size $3, 2, 1$; bins of capacity $4$.
| string | bin loads | bins |
|---|---|---|
000 | $6$ ✗ | — |
001 | $5,\ 1$ ✗ | — |
010 | $4,\ 2$ ✓ | 2 |
011 | $3,\ 3$ ✓ | 2 |
012 | $3,\ 2,\ 1$ ✓ | 3 |
Five candidates, three feasible, optimum 2 bins. The "every map item → bin" space would have checked $3^3 = 27$.
section 3
"Here is the answer" and "here is why nothing is better" are different objects.
00 · certificates
Exhibit $x \in F$ with $c(x) = k$.
Anyone checks it by evaluating the constraints and the objective. For all nine problems that takes polynomial time. This is exactly what puts the decision versions in NP.
Show that no $x \in F$ has $c(x) < k$.
Enumeration proves it, but the proof is exponentially long. Is there a short proof? For NP-hard problems, in general, it is believed there is not: that is NP ≠ coNP.
At most 2: hand over $\{1, 2\}$; checking it is four edge lookups. At least 2: enumeration checks all 16 candidates and finds no cover of size 0 or 1. That works at 4 vertices, not at 50. The next two slides replace it with two edges.
For particular instances, and for whole problem classes, short lower-bound proofs do exist. Finding them is most of the course.
00 · certificates
If $M$ is a matching (edges sharing no endpoint) and $C$ a vertex cover in the same graph, then $|C| \ge |M|$.
Each matched edge needs one of its own endpoints in the cover. Matched edges share no endpoints, so no cover vertex can serve two of them: the cover needs $|M|$ different vertices.
So a cover and a matching of the same size prove each other optimal. This is the matching lower bound, the course's first instance of weak duality.
A path on four vertices. Filled vertices: a cover of size 2. Thick edges: a matching of size 2. Each proves the other optimal.
00 · certificates · example
Claim: the smallest cover of the running example has 2 vertices. The certificate is a cover $C = \{1,2\}$ and a matching $M = \{01, 23\}$.
| check | on the example | |
|---|---|---|
| 1. every edge of $M$ is an edge of $G$ | $01$ ✓, $23$ ✓ | ✓ |
| 2. edges of $M$ share no endpoint | endpoints $0,1,2,3$: all different | ✓ |
| 3. $C$ covers every edge | $01{:}\,1$ · $02{:}\,2$ · $12{:}\,1,2$ · $23{:}\,2$ | ✓ |
| 4. sizes agree | $|C| = 2 = |M|$ | ✓ |
What follows: check 3 says the optimum is at most 2. Checks 1–2 and the lemma say every cover has at least 2. So 2 is optimal, and nobody enumerated anything.
A wrong certificate fails a check. $M = \{01, 12\}$ fails check 2 (vertex 1 twice), and rightly: one vertex, 1, touches both edges.
Filled: the cover. Thick: the matching. Each thick edge has its own filled end.
00 · certificates
On a triangle, the largest matching has 1 edge, and the smallest cover needs 2 vertices. No matching certifies the optimum. This duality gap is real.
Delete the running example's edge $23$ and you are here: the matching loses its second edge, the cover still needs 2.
In a bipartite graph, $\max |M| = \min |C|$. The certificate always exists.
The triangle is the smallest odd cycle, and odd cycles are exactly what bipartite graphs lack. That coincidence is where polyhedral combinatorics starts (units 06, 15).
Any edge is a maximum matching (1). Any two vertices form a minimum cover (2).
section 4
Slow, obviously correct, and the reference every later lab is checked against.
00 · oracle
def brute_force(problem):
best = best_x = None
feasible = examined = 0
for x in problem.space():
examined += 1
if not problem.is_feasible(x):
continue
feasible += 1
v = problem.objective(x)
if best is None or better(v, best, problem.sense):
best, best_x = v, x
return Result(best, best_x, feasible, examined)
Where people slip: initializing best to 0 or ∞
(wrong for one sense), and reporting a value on infeasible instances.
Obviously correct: it is the definition of the optimum, executed.
Self-certifying: examined == space.size() is the lower-bound proof.
Generic: one function for all nine problems, because every problem has the same problem interface.
examined=16, feasible=7, value 2 at (0, 1, 1, 0): the cover $\{1, 2\}$. It keeps the first best it meets, so the tie $\{0, 2\}$, found later, is not reported.
00 · oracle
Smallest first. The first failure is the smallest counterexample the sweep contains, and so the easiest one to draw.
Feasibility checked separately. A "better than optimal" answer is always an infeasible one.
Ratio mode. For approximation algorithms, pass ratio=2 and check a guarantee, not equality.
00 · oracle
"Take the vertex covering the most uncovered edges." (max-degree greedy)
On this spider it takes the centre (degree 3). The three leg-ends are then disjoint edges, and each costs one more vertex: 4.
The middle row covers everything with 3, and the three thick edges are a matching of size 3, so 3 is provably optimal.
No graph with fewer vertices makes max-degree greedy fail whatever the tie-breaking. In lab step 5 you write the heuristic, and the harness has to find a case like this on its own.
00 · oracle
Pure-Python brute force, reference machine, extrapolated from µs per candidate:
| space | 1 minute | 1 hour | 1 year |
|---|---|---|---|
| $2^n$ — vertex cover | 25 | 31 | 44 |
| $(n-1)!$ — TSP | 11 | 13 | 16 |
| $B_n$ — bin packing | 12 | 15 | 19 |
A year of computing buys five more TSP cities than a minute does. That limit is the wall.
Tests against brute force use $n \le 12$ for subset spaces, $n \le 8$ for tours and partitions. Anything larger needs a certificate or a trusted solver.
00 · lab
uv run co test 00 # after each step: · not started ✗ failing ✓ done
uv run co then 00 # find your wall
00 · checkpoint
Papadimitriou & Steiglitz, Combinatorial Optimization, ch. 1.
Korte & Vygen, Combinatorial Optimization, §1.1–1.3 (optional).
Any of three roots: 01 polyhedra (LP trunk), 13 matroids (combinatorial trunk), 17 propagation (constraint trunk).