Constraint Satisfaction: Variables, Domains, and Backtracking
Define CSPs formally, implement backtracking search from first principles, and understand how AC-3 arc consistency prunes the search space before the solver ever makes a single assignment.
- Estimated time
- ~14 min
- Difficulty
- intermediate
- Sources
- 4 sources
A Sudoku grid with 30 clues contains roughly 10²⁵ ways to fill the blank cells — yet a competent solver finds the unique answer in milliseconds. The trick is not speed; it is refusing to explore most of that space at all.
The Puzzle as a Model
Sudoku, class scheduling, circuit layout, and protein folding all share the same skeleton: you have a set of unknowns, each with a finite range of legal values, and a set of rules that link the unknowns together. This abstract skeleton is a Constraint Satisfaction Problem (CSP).
Before we name the parts formally, pick up the smallest version: a 4×4 Sudoku. Each of the 16 cells is an unknown. Each cell’s legal values are {1, 2, 3, 4}. Every row, column, and 2×2 box must contain each digit exactly once. Those row/column/box rules are the constraints.
Map colouring as a CSP
Australia has six territories. Each must be painted one of three colours (Red, Green, Blue). No two neighbouring territories can share a colour. Unknowns: one per territory. Domains: {Red, Green, Blue} each. Constraints: one “differs from” rule per shared border.
A triple (X, D, C) where X = {X₁, …, Xₙ} is a finite set of variables; D = {D₁, …, Dₙ} is a set of domains, each Dᵢ a finite set of values for Xᵢ; and C is a set of constraints, each constraint specifying which combinations of values are legal for a subset of variables.
A solution is an assignment of a value from each variable’s domain such that every constraint is satisfied simultaneously.
[Artificial Intelligence: A Modern Approach (4th ed.)]The CSP frame matters because it strips away the specifics of any one puzzle and exposes the algorithm underneath. Every solver — from a naive brute-force to Google’s CP-SAT — manipulates these three objects: variables, domains, constraints.
Check your understanding
In the Australia map-colouring CSP, what is the domain of the variable 'Western Australia'?
Assigning Variables — and What Happens to Their Neighbours
The moment you fix one variable’s value, some values for neighbouring variables become illegal. This is local constraint propagation: no search yet, just implication-following.
The widget below puts you in charge of a three-territory colouring (West, Center, East). All three share borders. Assign West to a colour and watch which values survive in Center’s and East’s domains.
Common misconception
Constraint propagation is just bookkeeping — the real work is the search.
What's actually true
Propagation is the work. In industrial solvers, aggressive propagation (looking ahead many steps) eliminates the vast majority of the search tree before any branching occurs. The ratio is often 10 000:1 — one propagation step rules out ten thousand search nodes.
[Artificial Intelligence: A Modern Approach (4th ed.)]Check your understanding
You assign West = Red in the three-territory CSP. Which value is immediately eliminated from Center's domain?
Backtracking Search
Once you understand domains and propagation, the search algorithm is natural. Backtracking is depth-first search with one extra rule: if the current partial assignment violates a constraint (or empties any domain), stop immediately and undo the last assignment.
The algorithm in plain English:
- Pick an unassigned variable.
- Try each value in its domain.
- If the assignment is consistent with all constraints so far, recurse.
- If recursion succeeds, return the solution.
- If every value leads to failure — backtrack: undo this assignment and try the next value for the previous variable.
Show the pseudocode
def backtrack(assignment, csp):
if len(assignment) == len(csp.variables):
return assignment # all variables assigned — success
var = select_unassigned(csp, assignment)
for value in csp.domains[var]:
if consistent(var, value, assignment, csp):
assignment[var] = value
result = backtrack(assignment, csp)
if result is not None:
return result
del assignment[var] # undo — backtrack
return None # no value worked — failure The 4-Queens problem (place four queens on a 4×4 chessboard so no two attack each other) is a classic CSP. Step through the actual search the algorithm performs:
The critical observation: backtracking does not undo one step at a time after reaching a dead end — it precisely undoes the last decision that could still be varied. This is why it is exponentially faster than exhaustive enumeration, which would try every complete assignment.
The number of backtracks can still be exponential in the worst case. For random 3-SAT problems near the satisfiability phase transition, even the best backtracking solvers struggle. This is why the next layer — constraint propagation before and during search — matters so much.
[Hard and Easy Distributions of SAT Problems]Check your understanding
In the 4-Queens backtracking trace, the algorithm placed queens at Row 0 Col 0 and Row 1 Col 2, then found no valid column for Row 2. What does it do next?
Arc Consistency and AC-3
Backtracking finds solutions, but it wastes time discovering dead ends it could have predicted. Arc consistency (AC) is a pre-processing pass (and an interleaved-during-search pass) that removes values provably incapable of participating in any solution.
A variable Xᵢ is arc-consistent with respect to Xⱼ if, for every value in Dᵢ, there exists at least one value in Dⱼ that satisfies the constraint between them. If a value in Dᵢ has no such “support” in Dⱼ, it can be deleted: no solution will ever use it.
Maintain a queue of arcs (Xᵢ, Xⱼ). For each arc, remove from Dᵢ any value with no support in Dⱼ. If Dᵢ shrank, re-add all arcs (Xₖ, Xᵢ) to the queue (other variables that constrain Xᵢ may also lose support). Repeat until the queue is empty or some domain becomes empty (infeasibility).
The widget below runs AC-3 on a three-variable numeric CSP — X, Y, Z each starting with domain {1, 2, 3}, constrained by X < Y and Y < Z. Step through each arc processing to watch domains collapse down to a single value apiece. No search is needed at all.
Show the time complexity of AC-3
If each domain has at most values and there are constraints (arcs), AC-3 runs in time. Each arc can be re-added to the queue at most times (once per value removal from the head variable); each arc-check takes . In practice this bound is loose — most arcs need far fewer passes.
Check your understanding
After AC-3 finishes on the X < Y < Z problem with initial domains {1,2,3}, what are the final domains?
Where the Model Breaks Down
CSPs are expressive — almost any combinatorial puzzle fits the frame. But three limits matter:
Exponential worst case. Even with AC-3, backtracking can still visit exponentially many nodes on adversarially-constructed problems (e.g., random k-SAT near the phase transition). Arc consistency alone does not guarantee polynomial search time.
Global constraints are outside the basic model. The CSP framework as described handles binary constraints (between two variables). Constraints like “all different” or “the sum equals 100” span many variables. Efficient propagation algorithms for these — called global constraint propagators — are built into industrial solvers (CP-SAT, Choco, MiniZinc) but are not captured by basic AC-3.
Soft constraints are invisible. A hard CSP asks: find any solution. Real scheduling problems ask: find the best solution when some constraints can be violated at a cost. That extension — Constraint Optimisation Problems (COPs) — requires objective functions, branch-and-bound, or LP relaxations layered on top.
| Hard CSP | COP (Optimisation) | |
|---|---|---|
| Goal | Find any satisfying assignment | Find the assignment with minimum cost |
| Soft constraints | Not supported — all constraints hard | Expressible as penalty terms |
| Typical algorithm | Backtracking + AC-3 | Branch & bound + LP relaxation |
| CP-SAT role | Feasibility mode | Optimisation mode (Minimize/Maximize) |
Check your understanding
A teacher scheduling problem requires that 'at most 3 classes run simultaneously.' Is this a binary constraint?
Check your understandingQ 1 / 5
Which component of a CSP specifies the range of legal values for a single variable?