3.5

Arc Consistency

AC-3 algorithm, edge consistency, variable elimination.

Arc Consistency -- Brief ☧

Deep version -> | Back to Lattices ->


Q: "Beloved, believe not every spirit, but try the spirits whether

they are of God" (1 John 4:1). In constraint solving, how do we "test"

whether a value in a domain is truly viable -- not just looks possible

but actually is possible?

A: We check whether it has a support. A support means: for this

value, there exists at least one compatible value in every neighboring

variable. A value without support is a false spirit -- it appears possible

in isolation, but if you pick it, you'll hit a dead end because nothing

in the connected variables can work with it.

Q: That's a bit abstract. Can you walk me through a real scenario?

A: Of course. Three servants need to be assigned to three tasks, and

each servant can only do certain tasks:

Martha: {cooking, serving}
Mary:   {teaching, serving}
Lazarus:{cooking}

Rule: each servant gets a different task.

Now let's "try the spirits." Start with Lazarus -- he can ONLY cook.

That's his one option. So cooking is taken. Now ask: can Martha still

cook? No, because Lazarus must cook. Remove "cooking" from Martha:

Lazarus: {cooking}   -- only option, forced
  -> Remove "cooking" from Martha
Martha:  {serving}   -- only option left, forced
  -> Remove "serving" from Mary
Mary:    {teaching}  -- only option left, forced

All assigned! Arc consistency solved it completely.

Each time we removed a value, it was because that value had lost its

support -- there was no consistent way to use it.

Q: You keep saying "arc." What exactly is an arc here?

A: An arc is an edge in the constraint graph -- a line connecting

two variables that share a constraint. Martha and Lazarus share the

"different tasks" constraint, so there's an arc between them.

"Arc consistent" means: for every value in one variable's domain,

there exists at least one compatible value along every arc to a

neighboring variable.

AC-3: The Classic Algorithm

The standard algorithm for enforcing arc consistency is called AC-3.

It works like this:

1. Put all arcs in a queue
2. Pick an arc (A, B)
3. For each value in A's domain:
     If no value in B's domain is compatible, remove it from A
4. If A's domain changed, re-queue all arcs involving A
5. Repeat until the queue is empty (fixpoint!)

Notice that step 5 is a fixpoint check -- we keep going until

nothing changes. The queue tracks which arcs still need revisiting.

PropertyValue
Time complexityO(ed³) for e arcs, d domain size
Space complexityO(e + nd)
CompletenessNecessary but not sufficient (may need search too)

What should you take away from these complexity numbers? The O(ed³) time

complexity tells us that AC-3 is polynomial -- it will always finish in

reasonable time, even for large problems. The "d³" factor comes from the

three nested operations: for each arc (e), we check each value in one

domain (d), and for each value we scan the other domain for support (d),

and we might need to repeat when domains change (d). On our FPGA, the

inner loop (scanning for support) is replaced by a single AND operation

on bitmask domains, which effectively makes the per-arc cost O(1) instead

of O(d²). This is a massive speedup for large domain sizes.

However, AC-3 is necessary but not sufficient. It prunes many impossible

values cheaply, but sometimes the remaining possibilities still contain

hidden conflicts that only show up when you commit to a specific choice.

That is why real solvers combine arc consistency with backtracking

search -- AC-3 shrinks the search space, and backtracking explores what

remains.

Learn more about AC-3, MAC, and our constraint propagation

Related: Propagators | SAT/SMT | Backtracking


Soli Deo Gloria

Self-Check 1/3

AC-3 processes _____ between variable pairs.