Part IV · trunk C · constraint programming and SAT · spine

17

Constraint satisfaction and propagation

Variables, domains, constraints — and no relaxation. Remove what cannot be part of a solution, search over what remains, undo, repeat.

needs 00~1½ h slides + 3 h lablab: uv run co lab 17

17 · overview

The route

1 · the formalism

CSPs, and how "prune" differs from "relax and bound".

2 · consistency

Node, arc, path, k; AC-3 and AC-4; bounds vs domain consistency; what each costs.

3 · the engine

Propagators, the fixpoint, idempotence, trailing.

4 · search

The CP loop, first-fail, and the two numbers that describe everything.

getting around

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

The formalism

Feasibility first; an objective, if any, is just another constraint.

17 · formalism

Constraint satisfaction problems

CSP

Variables $x_1, \dots, x_n$, finite domains $D_i$, and constraints $C_j \subseteq D_{i_1} \times \cdots \times D_{i_k}$ over subsets of the variables. A solution assigns every variable a value from its domain so that every constraint holds.

  • Constraints are arbitrary relations: "≠", "all different", "this table of allowed tuples", "count of 3s equals $x_3$". No linearity and no convexity.
  • Often no objective at all. With one, minimise by adding "objective < best" after each solution and continuing.
  • Deciding satisfiability is NP-complete: 3-colouring is a CSP.
MIP (Part II)CP (Part IV)
core moverelax, then boundprune domains
strength fromtight LP relaxationsstrong propagators
proves optimality bydual bound meets incumbentexhausting the tree
easy for itweighted sums, flows, coveringalldifferent, scheduling, puzzles
hard for itbig-M disjunctions, permutationsweak bounds on sums

Neither dominates, which is why unit 21's hybrid exists.

section 2

Consistency

How much local reasoning, at what price.

17 · consistency

A ladder of consistency levels

  • Node: every value satisfies the unary constraints.
  • Arc (AC): for each binary constraint on $(x, y)$, every $a \in D_x$ has a support $b \in D_y$.
  • Path: every consistent pair extends to any third variable.
  • $k$-consistency: every consistent assignment to $k - 1$ variables extends to any $k$-th. Strong $n$-consistency means backtrack-free search.

Higher levels prune more and cost exponentially more: $k$-consistency takes $O(n^k d^k)$ time.

algorithmtimeidea
AC-3 (Mackworth 1977)$O(e d^3)$queue of arcs; revise
AC-4 (Mohr & Henderson 1986)$O(e d^2)$support counters
AC-2001 (Bessière & Régin)$O(e d^2)$AC-3 plus "last support" pointers
path consistency$O(n^3 d^3)$rarely used
Freuder 1982

If the constraint graph is a tree, arc consistency alone makes search backtrack-free. More generally, width $w$ plus strong $(w+1)$-consistency suffices, which is unit 16's treewidth again.

17 · consistency · example

AC-3, revise by revise

$x, y, z \in \{1, 2, 3\}$ with $x < y$ and $y < z$. Four arcs, one per direction: $(x,y)$, $(y,x)$, $(y,z)$, $(z,y)$. The queue starts with all four.

#revisedomain before → afterpush
1$x$ against $y$$x$: 123 → 12
2$y$ against $x$$y$: 123 → 23$(x,y)$
3$y$ against $z$$y$: 23 → 2
4$z$ against $y$$z$: 123 → 3$(y,z)$
5$x$ against $y$$x$: 12 → 1$(y,x)$
6$y$ against $z$$y$: 2 → 2
7$y$ against $x$$y$: 2 → 2
reading the trace

Revise 1: $x = 3$ has no $y$ above it: gone. Revise 2: $y = 1$ has no $x$ below it: gone. Because $y$ shrank, the arc that reads $y$ to prune $x$ goes back on the queue.

Revise 5 uses the news from revise 3 ($y = 2$): $x = 2$ lost its support.

After 7 revise calls the queue is empty: $x = 1$, $y = 2$, $z = 3$, solved without search.

This constraint graph is a path, a tree, so Freuder's theorem already promised no search would be needed.

17 · consistency

Arc consistent, yet unsatisfiable

{0,1}{0,1}{0,1} ≠≠≠

Every value has a support on every edge, so nothing is pruned. No 2-colouring exists.

Arc consistency is local. It checks one constraint at a time and never looks at a cycle. Each propagator is sound (it never removes a solution), and the fixpoint is sound, but it is not complete.

4×4 sudoku, from the lab

1 . . .
. . 3 .
. 4 . .
. . . 2

133 NotEqual propagations reach a fixpoint where every cell is a singleton: solved without search. Inkala's 9×9 "hardest sudoku" needs 3 598 nodes.

Search fills the gap between "consistent" and "solved". Stronger propagation shrinks the tree, at a price per node.

17 · consistency

Bounds consistency vs domain consistency

domain (generalised arc) consistency

Every value in every domain belongs to some satisfying tuple of the constraint.

bounds consistency

Only the min and max of each domain need supports, often with the others relaxed to intervals. Interior holes are ignored.

On a linear constraint $\sum a_i x_i \le b$, reasoning from bounds costs $O(n)$. Domain consistency on an equality $\sum a_i x_i = b$ is NP-hard: it contains subset sum.

Lab step 3's LinearLe removes every value $a$ of $x_i$ with

$$a_i\, a > b - \sum_{j \ne i} \min_{v \in D_j} a_j v$$

For a single inequality this is exactly domain consistency, since the others' best values are always available. The test checks it against brute-force supports. LinearEq, as two inequalities, is only bounds-like, and the test only asks it to be sound.

The general design question of Part IV: how strong a propagator, for what cost per call?

17 · consistency · example

One equation with a hole

$x + y = 6$, with $D_x = \{1, 2, 3, 4, 5\}$ and $D_y = \{1, 2, 4, 5\}$: $y$ has a hole at 3.

bounds reasoning, as the lab's LinearEq

$x \le 6 - \min y = 5$ and $x \ge 6 - \max y = 1$. Same for $y$. Nothing is removed.

domain consistency
$x$12345
needs $y =$5 ✓4 ✓3 ✗2 ✓1 ✓

$x = 3$ has no support: domain consistency removes it. Bounds consistency can't see a hole in the middle.

an inequality is different

Same domains, $x + y \le 3$. Each variable's best partner is the other's minimum, 1, so $x \le 2$ and $y \le 2$: $D_x = \{1,2\}$, $D_y = \{1,2\}$.

Every remaining value has a support (its partner at 1), so this is already domain consistent: for one inequality, bounds reasoning is exact.

For the equation, checking every value means solving "is there $y$ with $a + y = 6$?"; with many variables that question is subset sum, hence NP-hard.

section 3

The engine

Propagators, a queue, and a trail.

17 · engine

Propagators and the fixpoint

A propagator for constraint $C$ is a function $p : D \to D$ with

  • contracting: $p(D) \subseteq D$;
  • monotone: $D \subseteq D'$ implies $p(D) \subseteq p(D')$;
  • sound: it never removes a solution of $C$, and it rejects any fully fixed assignment that violates $C$.

Run all propagators until none changes anything. The result is the greatest common fixpoint, independent of the order (Apt 1999).

the lab's engine
  • prune(dom) is pure: it reads domains and returns narrowings. Only the engine writes.
  • Watch lists: when a variable changes, wake only the propagators on it.
  • A propagator that narrows its own variables is re-queued: LinearEq and Count aren't idempotent.
  • Every call counts as one propagation.

Real engines add priorities (cheap propagators first), events (fixed / bounds changed / any change), and idempotence flags (Schulte & Stuckey 2008).

17 · engine

Trailing, copying, or recomputing

Search needs the domains of the parent node back when a branch fails. Three options (Schulte 1999):

  • Trailing: log each change on a trail and undo back to a mark. Cheap when few domains change per node. Used by most CP systems, and by the lab's imperative engine.
  • Copying: snapshot the whole store at each node. Simple, and it suits parallel search. Used by Gecode.
  • Recomputation: store only the decisions and replay them. It trades time for memory.
the functional reference

Immutable domain tuples passed down the recursion: copying, with structural sharing. No trail, because backtracking is returning. The same node and propagation counts as the trailing engine, 3–10× slower in Python.

Trailing is what in-place mutation costs you: every write must be undoable. Copying is what immutability costs you: every write allocates.

17 · engine · example

A trail, written and undone

$x, y, z \in \{1,2,3\}$ with $x \ne y$ and $y \ne z$. The trail stores (variable, old domain) before every change.

eventtrail after itdomains $x, y, z$
mark $m_0$ = 0empty123, 123, 123
decide $x = 1$$(x, 123)$1, 123, 123
propagate $x \ne y$$\dots, (y, 123)$1, 23, 123
mark $m_1$ = 2
decide $y = 2$$\dots, (y, 23)$1, 2, 123
propagate $y \ne z$$\dots, (z, 123)$1, 2, 13
undo to m₁: back to one decision

Pop entries 4 and 3: restore $z = 123$, then $y = 23$. Trail length 2. Domains: $x = 1$, $y = \{2, 3\}$, $z = \{1,2,3\}$, exactly as after the first propagation.

undo to m₀: back to the root

Pop the remaining two: $y = 123$, $x = 123$. Empty trail, original domains.

Undo pops in reverse order, so $y$ is restored to 23 before being restored to 123. Search needs only the marks: "the branch $y = 2$ failed" is undo(m₁), then try $y \ne 2$.

section 4

Search

Propagate, branch, repeat.

17 · search

The CP loop, and its two numbers

The CP search loop:

  1. Propagate to a fixpoint. If a domain is empty: failure, backtrack.
  2. If every variable is fixed: a solution.
  3. Choose a variable (first-fail: smallest domain) and a value $a$. Branch $x = a$, then $x \ne a$.

"Fail first": pick the variable most likely to fail, so dead ends are found near the root, where they cut the most.

the diagnostic vocabulary

Nodes measure search effort; a better heuristic or stronger propagation reduces them. Propagations measure inference effort; stronger propagation increases them per node. Units 18–21 each move one against the other.

Lab then, same models in both solvers:

modelnodesyour sCP-SAT branchesCP-SAT s
queens 11, all 2 68048 9507.52226 3308.60
queens 60, one8621.6138 6812.37
sudoku (Inkala), all3 5981.306 5380.12
3-colour G(200, 4.4/n), unsat120 33426.53 1060.16
3-colour G(300, 4.4/n), unsatlimit67.717 9370.27

On queens the Python engine keeps pace. On unsatisfiable colouring CP-SAT needs 40× fewer branches, because it learns from each failure (units 20–21).

17 · lab

Lab 17 — what you build

about 3 hours · uv run co lab 17
  1. A trailed domain store.
  2. AC-3.
  3. Propagators (Binary, NotEqual, LinearLe, LinearEq, Count) and the fixpoint.
  4. First-fail and depth-first search with nodes, failures, propagations.
  5. Models: n-queens, sudoku, map colouring, magic series.
uv run co test 17
uv run co then 17     # the same models in CP-SAT

17 · checkpoint

Done when

checkpoint
  • All five lab steps are ✓.
  • You can trace your propagator's fixpoint by hand on a 4×4 sudoku, and explain why arc consistency does not imply satisfiability (the triangle).
  • You can say what nodes and propagations measure, and why one usually rises when the other falls.

Reading

Rossi, van Beek & Walsh (eds.), Handbook of CP, ch. 3–4.
Mackworth, Artificial Intelligence 8 (1977).
Freuder, JACM 29 (1982): backtrack-free search.
Schulte & Stuckey, TOPLAS 31 (2008).

Next

18 global constraints: alldifferent by matching, cumulative · 19 search heuristics, restarts, LNS · 20 SAT and CDCL.