The Core Idea
Constraint propagation is one of those ideas that, once understood, changes how you think about problem-solving. At its heart, it’s about making inferences — deducing what must be true given what you already know.
Consider a Sudoku puzzle. When you place a 5 in a cell, you immediately know that no other cell in the same row, column, or box can contain a 5. That’s constraint propagation in action.
Arc Consistency
The most common form of constraint propagation is arc consistency (AC-3). For every pair of constrained variables , we ensure that every value in ‘s domain has at least one compatible value in ‘s domain.
def ac3(csp):
queue = list(csp.arcs())
while queue:
(xi, xj) = queue.pop(0)
if revise(csp, xi, xj):
if len(csp.domains[xi]) == 0:
return False
for xk in csp.neighbors(xi) - {xj}:
queue.append((xk, xi))
return True
AC-3 runs in time where is the number of arcs and is the maximum domain size. For most practical problems, this is far cheaper than brute-force search.
Lessons for Software Design
What does this teach us about building software? Several things:
- Propagate constraints early — validate inputs at system boundaries
- Reduce the search space — eliminate impossible states before exploring
- Make implicit constraints explicit — document assumptions as assertions
See also: distributed-scheduler for how these ideas apply to job scheduling, and unix-philosophy for the principle of doing one thing well.
The Connection to Type Systems
Type systems are essentially constraint propagation engines. When you write:
The type checker propagates constraints from usage sites back to definitions, narrowing the set of valid programs.