Artificial Intelligence and Machine Learning · Lecture 06 of 16

Constraint satisfaction · Part 2

Domain splitting and local search

Recall the choices, rules and filtering from Part 1. Then finish systematic search with domain splitting and explore local search.

01Recap, then split remaining choices
02Repair assignments with local search
03Escape local minima with annealing
Part 1 recap · 1 of 6

A CSP describes choices and rules

CSP means constraint satisfaction problem. We want to choose values that obey every rule.

Variables: what we choose

X₁, X₂, X₃

Three named choices. Each variable will receive one number.

Domains: allowed choices

{0,1,2}

Each variable starts with these options. dom(X) means “the domain of X”.

Constraints: the rules

(X₁ < 2)
∧ (X₂ > 0)
∧ (X₃ < X₁)

∧ means AND: a solution must satisfy all three rules.

Capital X names a variable; lowercase x can name one of its values. Braces {…} enclose a set of available options.

Part 1 recap · 2 of 6

Combining conditions: ∧ means AND, ∨ means OR

A connective combines true/false statements. Here each X₁, X₂, X₃ has domain {0,1,2}.

∧ · AND: all conditions must hold

(X₁ < 2) ∧ (X₂ > 0)
∧ (X₃ < X₁)

This is the running CSP: satisfy all three rules together.

(1,0,0): false overall.
The middle rule fails; the others hold.

∨ · OR: at least one must hold

(X₁ = 1) ∨ (X₂ = 2)

An illustrative OR constraint.
Either part may hold; both may hold too.

(1,0,0): true overall.
The left part holds, so this OR holds.

A CSP requires an AND across its constraints. An individual constraint may contain OR. The OR example is a separate illustration, not an extra rule in the running CSP.

Part 1 recap · 3 of 6

Having values is different from having a solution

An assignment chooses values. A solution is a total assignment that satisfies every constraint.

Partial: choices are missing

X₁1
X₂?
X₃?

A={X₁=1} is a partial context. X₂ and X₃ are unassigned.

X₁<2 is true; the other rules are pending.

Total and valid: a solution

X₁1
X₂2
X₃0

Every variable has a value, and every rule holds:

(1<2) ∧ (2>0) ∧ (0<1): true.

Total but invalid: not a solution

X₁0
X₂1
X₃0

All values are allowed, but X₃<X₁ becomes 0<0, which is false.

We write a total assignment as a tuple, such as (1,2,0), in the fixed order X₁, X₂, X₃. “?” means unassigned; it is not a domain value.

Part 1 recap · 4 of 6

Part 1 used three ways to avoid wasted work

1 · Generate and test

Choose all three values, then check every rule.

3³ = 27Complete candidates before filtering.

2 · DFS / backtracking

Depth-first search (DFS) builds a partial assignment. Test a rule once all variables it uses have values.

X₁ = 2 → rejectX₁<2 already fails; skip all completions of this branch.

3 · Constraint propagation / GAC

Filter the domains: remove values that cannot satisfy a rule with any allowed partners.

Delete X₁ = 0No allowed X₃ is smaller than 0.

Backtracking rejects choices already made. Propagation reasons about choices still available, before completing an assignment.

Part 1 recap · 5 of 6

Recap: generalized arc consistency (GAC)

GAC filters domains: remove a value when it has no satisfying partners for a rule. Example: X₃ < X₁, both domains {0,1,2}.

X₁ = 1 has a partner

X₃ = 0 → 0 < 1

This satisfying pair is a support, also called a witness. Keep X₁=1 for this rule.

X₁ = 0 has no partner

0, 1, 2: none is below 0

No possible X₃ makes the rule true. Remove X₁=0 from its domain.

After a deletion, affected checks return to the worklist E. Repeat until E is empty or a domain is empty.

Part 1 recap · 6 of 6

After GAC, one choice is still open

VariableInitial domainAfter GAC
X₁{0,1,2}{1}
X₂{0,1,2}{1,2}
X₃{0,1,2}{0}

What is settled here?

X₁=1 ∧ X₃=0 are fixed. X₂=1 ∨ X₂=2 is still a choice.

What comes next?

Try the X₂ alternatives in separate branches. Propagate again inside each branch.

In general: an empty domain means failure; all singleton domains after GAC give a solution; remaining choices leave the result unresolved. A singleton is a set with one value.

Constraint satisfaction · Part 2 · Reconnect before continuing

Two ways to continue after propagation

Domain splitting

Split a remaining domain. Propagate each branch and explore all alternatives.

domains → branches → solutions

Local search

Change one value at a time. Reduce conflicts, and sometimes move sideways or uphill.

candidate → moves → no conflicts

Systematic search can prove impossibility when exhaustive. A bounded local-search run may simply finish without finding a solution.

02 · Search after propagation

Split the choices, then propagate each branch

After GAC: (X₁=1) ∧ ((X₂=1) ∨ (X₂=2)) ∧ (X₃=0). Split the OR into two branches; keep every original constraint in both.

dom(X₂) = {1,2}dom(X₂) = {1}dom(X₂) = {2}Solution (1,1,0)Solution (1,2,0)

The parts must be nonempty, disjoint and cover the original domain. Copy the domains, run GAC in each branch, and explore both.

Mathematical definition · Constraint satisfaction

A split is a partition of one domain

Keep every choice exactly once

D₁ ∪ D₂ = dom₀(X)
(D₁ ∩ D₂ = ∅)
∧ (D₁≠∅) ∧ (D₂≠∅)

dom₀ is the domain mapping after GAC; D₁ and D₂ are the two parts.

Make independent branch mappings

VariableBranch j, with j=1 or 2
The selected Xdomⱼ(X)=Dⱼ
Any other Y≠Xdomⱼ(Y)=dom₀(Y)

Example: {1,2,3,4} splits into {1,2} and {3,4}.

∪ = union; ∩ = intersection; ∅ = empty set; ∧ = AND. All conditions must hold: the parts cover the domain, do not overlap, and are nonempty.

Mathematical definition · Constraint satisfaction

Consistency solver: propagate, then recurse

Input: variables 𝓧 with their domains, constraints 𝓒, and pending checks E. Result: a set of solutions.

procedure Con_Solve(𝓧, 𝓒, E)
dom₀ = GAC(𝓧, 𝓒, E)
if ∃X∈𝓧, dom₀(X)=∅ then
return ∅
else if ∀X∈𝓧, |dom₀(X)|=1 then
return {{X=x | X∈𝓧, x∈dom₀(X)}}
else
select X such that |dom₀(X)|>1
partition dom₀(X) into D₁ and D₂
(∀Y≠X, dom₁(Y)=dom₀(Y)) ∧ dom₁(X)=D₁
(∀Y≠X, dom₂(Y)=dom₀(Y)) ∧ dom₂(X)=D₂
E′ = {(Z,c′) | Z≠X, {X,Z}⊆scope(c′)}
return Con_Solve(𝓧[dom₁],𝓒,E′) ∪ Con_Solve(𝓧[dom₂],𝓒,E′)
end if
end procedure

𝓧: variables with current domains.
𝓒: constraints · X,Y,Z: variables.
x: a value · D₁,D₂: the two parts.

dom₀: after GAC · dom₁,dom₂: branch domains.
domⱼ(X): X’s values in branch j (1 or 2).
𝓧[domⱼ]: same variables, using domains domⱼ.

E: pending (variable,rule) checks.
E′: affected checks · c′: a constraint.
scope(c′): variables used by that constraint.

∃: some · ∀: every · ∈: belongs to · ⊆: subset · ∧: AND · ∪: union · ∅: empty set · |…|: number of values.

{… | …}: items meeting all the conditions · {{…}}: a set containing one assignment. “=” stores a result on lines 2, 10–12; tests compare values.

Interactive lab · Constraint satisfaction

Turn the remaining choices into a search tree

Predict the running example’s two X₂ branches, then step. Select the contradiction: GAC leaves nonempty domains, but splitting eventually rejects every branch.

Local search

Local search starts complete and repairs errors

a is a complete candidate. Its conflict score h(a) counts the rules it violates.
Rules: (X₁ < 2) ∧ (X₂ > 0) ∧ (X₃ < X₁).

Backtracking: build a context

X11
X2?
X3?

Assign missing values; reject a branch when an evaluable rule fails.

Local search: repair candidate a

X10
X21
X30

Only X₃ < X₁ fails: h(a)=1.
Change X₁ to 1: (1,1,0) has score 0.

Goal: h(a)=0. No rule is broken, so a is a solution. A positive score means the candidate still needs repair.

Local search · Reading map

Local search: the methods we will study

Keep one total candidate. Each method changes how we choose its next move.

MethodThe question it answers
Generic searchWhat does the shared loop do?
Random samplingWhat if we just try fresh candidates?
Random walkWhat if we change one value at random?
Iterative best improvement (IBI)What if the conflict score guides us?
Simulated annealingWhen should we accept a worse move?

First define candidates, neighbors and scores. Then change one policy at a time; compare them in the final lab.

Generic search

A neighbor changes one variable

Keep a complete candidate; choose one allowed change. This defines the local-search neighborhood.

Current candidate a

(X₁,X₂,X₃) = (0,1,0)Rules: (X₁ < 2) ∧ (X₂ > 0) ∧ (X₃ < X₁).

h(a) = 1: only X₃ < X₁ fails.

Two neighboring candidates

ChangeCandidateConflicts h(a)
X₁ to 1(1,1,0)0
X₂ to 0(0,0,0)2

A policy decides which neighbor to propose and whether to accept it. Random walk, best improvement and annealing use different policies on the same neighborhood.

Generic search

Count one conflict for each violated edge

conflictAredBgreenCredDblue

Graph-coloring model

Variables: vertices A, B, C, D.

Domain: {red, green, blue}.

Rule: joined vertices must differ.

h(a) = 1A=C=red: only A≠C fails.
(A≠B) ∧ (B≠C) ∧ (C≠D) ∧ (D≠A) ∧ (A≠C)

Assignment shown: a = {A=red, B=green, C=red, D=blue}.

The ∧ symbols mean AND: all five rules must hold. Here only A≠C fails, so h(a)=1.

Generic search

Count conflicts with h(a)

h is an evaluation function: it scores a complete candidate a by counting the constraints it violates.

Count the broken rules

a = (0,1,0)
RuleBroken?Add
X₁ < 2No: 0 < 20
X₂ > 0No: 1 > 00
X₃ < X₁Yes: 0 < 0 is false1

Read the result

h(a) = 1

One broken rule means one conflict.

Lower is better. A score of zero means every constraint holds.

Use h(a) for this conflict score throughout local search.

Score a candidate by adding 1 for each violated rule and 0 for each satisfied rule.

Generic search

General local search: read the algorithm

Input: variables 𝓧 and constraints 𝓒. Goal: a complete assignment that satisfies every constraint.

procedure Local_search(𝓧, 𝓒)
repeat
for X ∈ 𝓧 do
a[X] = rand(dom(X))
end for
while ¬stop() ∧ ∃c∈𝓒, ε(a[scope(c)],c)=0 do
Y = select_var(𝓧)
y = select_val(dom(Y))
a[Y] = y
end while
if ∀c∈𝓒, ε(a[scope(c)],c)=1 then
return a
end if
until terminate()
return ∅
end procedure

𝓧: variables · 𝓒: constraints.
X,Y: variables · y: a value.
a: complete candidate; a[Y]: Y’s value.

dom(Y): allowed values of Y.
scope(c): variables used by rule c.
ε(a[scope(c)],c): 1 if c holds, 0 if it fails.

∈: belongs to · ¬: NOT · ∧: AND.
∃: at least one · ∀: every.
∅: no solution returned by this run.

stop(): end this attempt · terminate(): end the whole search · rand: random choice. “=” stores a value on lines 4, 7–9; the rule tests compare with 0 or 1.

Try it · Generic search

Try the shared loop: start, change, check

All four vertices start red. Press Next: which vertex changes, and how many conflicts remain? Every state is a complete candidate.

Random sampling

Random sampling: start again each time

Draw a complete candidate, test it, then discard it if a rule fails.

1 · SampleChoose every variable’s value from its domain.
2 · TestCheck all constraints.
Zero conflicts? Return the solution.
3 · RepeatIf it fails, draw a fresh complete candidate.

Example: two independent draws

(0,1,0) → (1,2,0)

Order: X₁,X₂,X₃. First draw fails X₃<X₁; second draw satisfies all three rules.

In the generic loop

stop() = true

Skip the inner repair loop. Each attempt only samples and tests.

No information from the failed candidate guides the next draw. A finite number of draws can miss every solution.

Try it · Random sampling

Try random sampling: replace the whole candidate

Press Next to draw a fresh coloring. All four values are sampled again; the score may rise or fall. Reset and try another seed.

Random walk

Random walk: change one value at random

Keep the current candidate. Pick a variable and a new allowed value at random.

One step can make things worse

(0,1,0) → (0,0,0)Change X₂ from 1 to 0.

Conflicts: 1 → 2.
X₂>0 now fails too. Random walk still keeps the move.

How this differs from sampling

Sampling: replace the whole candidate.

Walk: retain the other values and change just one.

stop() = falseIdeal walk; practical runs use a step budget.

Random walk ignores whether the score improves. Next, IBI uses that score to choose a move.

Try it · Random walk

Try random walk: change just one variable

Press Next and compare the colors. Exactly one vertex changes; the move is kept even if its conflict score does not improve.

Iterative best improvement · Most-improving step

Iterative best improvement (IBI)

Count violated rules: (X₁ < 2) ∧ (X₂ > 0) ∧ (X₃ < X₁). Lower is better; zero means a solution.

Score the current candidate

a = (0,1,0)
h(a) = 1

a is the total assignment, in order X₁,X₂,X₃. h(a) counts violated constraints.

Most-improving step: compare neighbors

Some one-value changesConflicts
X₁→1: (1,1,0)0 ✓
X₁→2: (2,1,0)1
X₂→0: (0,0,0)2

Check all allowed changes; choose a neighbor with the lowest score.

Strict IBI: repeat only while the best neighbor has a lower score. No lower neighbor? Stop this attempt; a solution may still exist elsewhere.

Iterative best improvement · Tabu variant

IBI variant: tabu search remembers recent changes

Choose a good allowed move, but temporarily avoid variables changed very recently.

Before the next move

Recent changes: [X₁, X₃]Oldest → newest · tenure t = 2 steps

X₁ and X₃ are temporarily tabu (blocked). X₂ is available.

After changing X₂

Recent changes: [X₃, X₂]Drop X₁; remember X₂.

X₁ becomes available again. The memory delays an immediate reversal.

The memory delays an immediate reversal. Here t=2 means “avoid the last two changed variables”. Tabu may take an equal or worse move to keep searching.

Iterative best improvement · Plateau

IBI: why strict improvement can stop

Strict IBI accepts only lower scores. On this graph it stops at one conflict, even though a two-move route reaches zero.

Try strict improvement → sideways B to blue → strict improvement again. A sideways move keeps h(a)=1 but opens a move to h(a)=0.

Iterative best improvement · Escape strategies

IBI escape strategies: restart or take a random step

Random restart: begin elsewhere

stuck candidate → fresh sample

Replace every value, then try improvement again from the new starting point.

Random step: keep exploring nearby

1 conflict → 1 conflict → 0

Occasionally replace a greedy move with a random local change, even if the score does not fall.

Next: simulated annealing controls the acceptance of worse moves using temperature.

Try it · Iterative best improvement

Try IBI: see where strict improvement stops

Press Next: strict improvement stops at one conflict. Compare Tabu, or choose All red to see a successful improving run.

Simulated annealing

Compare one proposal at two temperatures

In both panels, the current candidate has 1 conflict. We propose a candidate with 2 conflicts.

Current: h(a)=1 → Proposed: h(a′)=2

High temperature: more willing to explore

The worse proposal has a higher chance of being accepted.

If accepted → 2 conflicts

Replace the current candidate with the proposed one.

Low temperature: more selective

The same proposal has a higher chance of being rejected.

If rejected → keep 1 conflict

Keep the current candidate; try another proposal.

Temperature changes the chance of accepting the proposal. It does not change its conflict count. Both decisions remain possible.

Simulated annealing

Simulated annealing: accepting a worse move

Accept better or equal candidates. Sometimes accept a worse one to escape a trap. Use h(a) to compare their conflict scores.

Measure the score change

Δh = h(a′) − h(a)a: current assignment · a′: proposed assignment

Δh ≤ 0: accept a better or equal move.

For a worse move, Δh > 0

p = exp(−Δh / T)p: acceptance probability · T: positive temperature

Draw u uniformly from [0,1). Accept if u < p.

T = 4T = 0.5p = 0.607p = 0.01801Test draw u = 0.5: accept when u < p

Here Δh=2. A positive T makes this worse move possible; cooling makes it less likely. The prime ′ marks the proposed assignment.

Simulated annealing

Keep the move fixed and change its temperature

Set Δh=2 and u=0.5. Compare T=4 with T=0.5. Then try Δh=0: an equal-score move is always accepted. p is the acceptance probability; u is the test draw.

Simulated annealing

Cooling: explore first, then become more selective

An annealing schedule is simply the rule used to lower temperature during a run.

Early: warmer

More exploration

Worse moves are easier to accept, helping search leave a trap.

Later: cooler

More selective

The same worse move is less likely to be accepted.

The lab lowers temperature a little after each step. Cooling too fast can leave search stuck; a finite run can still miss a solution.

Interactive lab · Constraint satisfaction

Try annealing, then compare the five policies

Annealing starts selected. Press Next to see accepted and rejected moves. Then reset and compare policies on the same start. A seed repeats the same random choices.

Putting it together

Choose the method by the answer you need

MethodWorks onWhat a completed run establishes
Generate-and-testTotal assignmentsAll solutions if every candidate is tested.
BacktrackingPartial assignmentsAll solutions if every branch is explored.
GAC aloneDomains and supportsPruned domains; sometimes inconclusive.
GAC + splittingRestricted-domain branchesAll solutions, or none, if exhaustive.
Local searchOne changing total assignmentA solution at h(a)=0; otherwise inconclusive.

Exhaustive claims assume finite domains and sound checks. Finding one solution can justify success before exhaustive completion.

Check your understanding

Predict first, then verify

1. With X₁=1 only, which rules are checkable?Open example ↗
2.2. What domains remain after GAC, and what is still undecided? Open example ↗
3. Why can the equality/equality/inequality CSP survive GAC?Open example ↗
4. For Δh=2, compare acceptance at T=4 and T=0.5.Open example ↗

Explain what the result proves. A correct number without the right conclusion can still be misleading.

Check your understanding

The answers—and what they mean

1 · Only a complete scope can be tested

X₁ < 2 is true.
X₂ > 0 and X₃ < X₁ are pending.

2 · Domains still describe choices

dom(X₁)={1}
dom(X₂)={1,2}
dom(X₃)={0}
X₂ has two choices; each yields a solution.

3 · Local witnesses can disagree

Each rule has support separately. But the equalities force X₁=X₃, violating X₁≠X₃.

4 · Cooling rejects more worse moves

Δh=2:
T=4 → p≈0.607
T=0.5 → p≈0.018

Write dom(X₂)={1,2} for a set of choices. Write X₂=1 when a specific value has actually been selected.

Lecture 06 · Takeaways

Build systematically—or repair a candidate

Systematic path

ModelVariables, domains, rules.
PruneRemove unsupported values.
BranchSplit and explore remaining choices.

Exhaustive finite search: solutions or a proof of none.

Local path

StartA total candidate.
MoveChange values by a policy.
CheckCount conflicts after moving.

h(a)=0: a solution. Budget spent: unresolved.

The key distinction: “no solution exists” requires a proof; “this run found no solution” is only a report of a run.

Further reading

Continue exploring

Read the fuller explanation

This pack’s handout ↗

Definitions, worked deductions and the assumptions behind each result.

Further reading: Poole & Mackworth, Artificial Intelligence: Foundations of Computational Agents, Chapter 4.

Lecture 06 · Wrap-up

Check that you can justify a solver’s result

SplitWhy must the parts cover the domain without overlap?
RepairWhy can strict improvement stop with h(a)>0?
AnnealWhat do Δh, T, p and u each mean?

Use a concrete example, then state whether the result is a solution, a proof of impossibility, or still unresolved.

Continue learning
AIML · Lecture 06 · Constraint satisfaction · Part 2
Course home