Solving constraint satisfaction problems

Constraint Satisfaction Problem (CSP)
Defined by a set of variables, set of domains for each variable and set of constraints for each variables
Variables(X) :
A finite set of variablesX = {x1,x2,x3...}
Domains(D) :
D = {D1,D2,D3,...}
WhereDi
is set of possible values for variablexi
. That isxi ∈ Di
.Constraints(C) :
A set of constraints C={c1,c2,…,cm} where each constraintcj
involves a subset of variablesXj ⊆ X
and specifies a relationRj
that must be satisfied. The relation RjRj defines the set of allowable tuples of values for the variables inXj
.
A solution to a CSP is an assignment of values to all variables x1,x2,…,xn such that : xi ∈ Di for all i ∈ {1,2,…,n} and All constraints cj ∈ C are satisfied.
CSP as a Graph
Nodes: Each variable in the CSP is represented as a node (or vertex) in the graph.
Edges: An edge is drawn between two nodes (variables) if there is a direct constraint between them.
Example:
Constraints:
X ≠ Y
Y < Z
X > 1
Graph Representation:
Nodes: X, Y, Z
Edges:
X -- Y (due to the constraint X ≠ Y)
Y -- Z (due to the constraint Y < Z)
Node consistency
- Node consistency is achieved when, for every variable, each value in its domain is consistent with the variable’s unary constraints.
- To make a variable
x
node consistent : from the domain of variablex
, remove a valuev
that doesn’t satisfy the constraint (length in case of crossword)
Arc Consistency
x
is arc consistent withy
when every value in the domain ofx
has a possible value in the domain ofy
that does not cause a conflict. (A conflict in the context of the crossword puzzle is a square for which two variables disagree on what character value it should take on.)- To make
x
arc consistent withy
, remove any value from the domain ofx
that does not have a corresponding possible value in the domain ofy
. The domain ofy
should be left unmodified.
AC3 Algorithm
Maintains a queue
of arcs to process.
- To implement AC3,
revise
(make a variable x arc consistent with another variable y) each arc in the queue one at a time. Any time you make a change to a domain, though, you may need to add additional arcs to your queue to ensure that other arcs stay consistent. - When trying to enforce arc consistency , we remove all values from domain, it is impossible to solve the problem
Crossword as a CSP
Each variable(word) in a crossword is represented by 4 values:
{
i : coordinate of square of starting row
j : coordinate of square of starting column
length : some number
direction : down or across
}
Domain : Initially the domain for each variable is set of all words in corpus.
Unary constraints : length
Binary constraints : intersecting/overlapping letter with neighbour words(variables)
Code Implemetation
enforce_node_consistency:
- remove values from domain of a variable if it doesnt satisfy unary constraint (length of variable)
revise :
- To make
x
arc consistent withy
, remove any value from the domain ofx
that does not have a corresponding possible value in the domain ofy
. - for every value in domain of
X
, check if it has possible values inY
, if not remove that value fromX
ac3 :
- Maintain queue of arcs
- enforce arc consistency using
revise
function - when a domain of a variable is changed to enforce arc consistency, other arcs may be affected. so add other arcs in the queue
function AC-3(csp):
queue = all arcs in csp
while queue non-empty:
(X, Y) = DEQUEUE(queue)
if REVISE(csp, X, Y):
if size of X.domain == 0:
return false
for each Z in X.neighbors - {Y}:
ENQUEUE(queue, (Z, X))
return true
assignment_complete :
- An
assignment
is a dictionary where the keys areVariable
objects and the values are strings representing the words those variables will take on. - An
assignment
is complete if every crossword variable is assigned to a value (regardless of what that value is).
consistent :
- An
assignment
is consistent if it satisfies all of the constraints of the problem: that is to say, all values are distinct, every value is the correct length, and there are no conflicts between neighboring variables.
order_domain_values :
- returns a list of all of the values in the domain of
var
, ordered according to theleast-constraining values
heuristic. - if assigning var to a particular value results in eliminating
n
possible choices for neighboring variables, you should order your results in ascending order ofn
. In other words, we should choose a value for a given variable that keeps more options for other variables. - any variable present in assignment already has a value, and therefore shouldn’t be counted when computing the number of values ruled out for neighboring unassigned variables.
- Arbitrary choice of unassigned variable may also produce correct crossword.
select_unassigned_variable :
returns single
Variable
in the crossword puzzle not yet assigned , By usingMinimum remaining value
heuristic and thendegree
heuristic.Minimum remaining value: Select a unassigned
Variable
such that the variable has fewest values in its domain. This is done to quickly eliminate a branch of possible options.
This may sound counterintuitive toorder_domain_values
which tried to select a least constraining value But we are talking about different things here. Theorder_domain_values
tries to select avalue
for a specificVariable
to keep the other variables with more choices, whileMinimum remaining value
selects aVariable
(notValue
) that prunes the unnecessary solution space quickly.Degree : If there is tie between variables by having same number of values in the domains, select the variable that has most neighbours. This is done because , by choosing such variable, it is likely to rule out more choices for other variables.
If it is still tie, choose arbitrary variable.Arbitrary choice of unassigned variable will also be correct for generating crossword, this is just for optimization
backtrack :
- Given a partial
assignment
dictionary , returns a complete satisfactoryassignment
if possible. - Interleaving search with inference (as by maintaining arc consistency every time you make a new assignment) makes it more efficient
backtrack starts with a assignment and recursively calls itself by passing the updated assignment
disctionary with newly added assignment.
function BACKTRACK(assignment, csp):
if assignment complete:
return assignment
var = SELECT-UNASSIGNED-VAR(assignment, csp)
for value in DOMAIN-VALUES(var, assignment, csp):
if value consistent with assignment:
add {var = value} to assignment
result = BACKTRACK(assignment, csp)
if result ≠ failure:
return result
remove {var = value} from assignment
return failure
remove {var = value} from assignment
, is where backtracking actually occurs as we return to previous state of assignment.
Optimimzed Backtracing Search
When we assign a value to a variable , we can check arc consistency on other nodes(variable) to quickly find out values other nodes could take. this inference procedure makes the algorithm more efficient as we do not need to solely assign values in the search(backtrack) process, but also can infer other values.
whenever we assign a value to a variable we check if other inferences can be made. those inferences are added to the assignment.
inferences = INFERENCE(assignment, csp)
add inferences to assignment
If later , that choice of value results in failure, we remove not only the value but also the inferences made from that value in the assignment
remove {var = value} and inferences from assignment
function BACKTRACK(assignment, csp):
if assignment complete:
return assignment
var = SELECT-UNASSIGNED-VAR(assignment, csp)
for value in DOMAIN-VALUES(var, assignment, csp):
if value consistent with assignment:
add {var = value} to assignment
inferences = INFERENCE(assignment, csp)
if inferences ≠ failure:
add inferences to assignment
result = BACKTRACK(assignment, csp)
if result ≠ failure:
return result
remove {var = value} and inferences from assignment
return failure