DIT410/TIN174, Artificial Intelligence
Peter Ljunglöf
31 March, 2017
Standard search problem:
CSP is a more specific search problem:
the state is defined by variables \(X_{i}\), taking values from the domain \(\mathbf{D}_{i}\)
the goal test is a set of constraints specifying allowable combinations
of values for subsets of variables
Since CSP is more specific, it allows useful algorithms with more power than standard search algorithms
Just a few variables can describe many states:
\(n\) | binary variables can describe | \(2^{n}\) states |
---|---|---|
10 | binary variables can describe | \(2^{10}\) = 1,024 |
20 | binary variables can describe | \(2^{20}\) = 1,048,576 |
30 | binary variables can describe | \(2^{30}\) = 1,073,741,824 |
100 | binary variables can describe | \(2^{100}\) = 1,267,650,600,228,229, 401,496,703,205,376 |
Given a set of variables, assign a value to each variable that either
CSP differences to general search problems:
The path to a goal isn’t important, only the solution is.
There are no predefined starting nodes.
Often these problems are huge, with thousands of variables,
so systematically searching the space is infeasible.
For optimization problems, there are no well-defined goal nodes.
A CSP is characterized by
A set of variables \(X_{1},X_{2},\ldots,X_{n}\).
Each variable \(X_{i}\) has an associated domain \(\mathbf{D}_{i}\) of possible values.
There are hard constraints \(C_{X_i,\ldots,X_j}\) on various subsets of the variables
which specify legal combinations of values for these variables.
A solution to the CSP is an assignment of a value to each variable
that satisfies all the constraints.
Variables: | \(A, B, C, D, E\) representing starting times of various activities. (e.g., courses and their study periods) |
Domains: | \(\mathbf{D}_{A}=\mathbf{D}_{B}=\mathbf{D}_{C}=\mathbf{D}_{D}=\mathbf{D}_{E}=\{1,2,3,4\}\) |
Constraints: | \((B\neq3), (C\neq2), (A\neq B), (B\neq C), (C<D), (A=D),\) \((E<A), (E<B), (E<C), (E<D), (B\neq D)\) |
Words: ant, big, bus, car, has, book, buys, hold, lane, year, beast, ginger, search, symbol, syntax, …
Many problems can be represented in different ways as a CSP, e.g., the crossword puzzle:
Variables: | \(\mathit{WA}, NT, Q, \mathit{NSW}, V, \mathit{SA}, T\) |
Domains: | \(\mathbf{D}_{i}=\{red,green,blue\}\) |
Constraints: | adjacent regions must have different colors, i.e., \(\mathit{WA}\neq NT,\mathit{WA}\neq\mathit{SA},NT\neq\mathit{SA},NT\neq Q,\ldots\) |
Binary CSP: each constraint relates at most two variables
(note: this does not say anything about the domains)
Constraint graph: every variable is a node, every binary constraint is an arc
Variables: | \(F,T,U,W,R,O,X_{1},X_{2},X_{3}\) |
Domains: | \(\{0,1,2,3,4,5,6,7,8,9\}\) |
Constraints: | \(\mathit{Alldiff}(F,T,U,W,R,O)\), \(O+O=R+10\cdot X_{1}\), etc. |
Note: | This is not a binary CSP! The graph is a constraint hypergraph |
Variables: | \(A_1\ldots A_9,B_1,\ldots,E_5,\ldots,I_9\) |
Domains: | \(\{1,2,3,4,5,6,7,8,9\}\) |
Constraints: | \(\mathit{Alldiff}(A_1,\ldots,A_9)\), …, \(\mathit{Alldiff}(A_5,\ldots,I_5)\), …, \(\mathit{Alldiff}(D_1,\ldots,F_3)\), …, \(B_1=9\), …, \(F_6=8\), …, \(I_7=3\) |
Variables: | \(Q_1, Q_2,\ldots, Q_n\) |
Domains: | \(\{1,2,3,\ldots,n\}\) |
Constraints: | \(\mathit{Alldiff}(Q_1,Q_2,\ldots,Q_n)\), \(Q_i-Q_j \neq |i-j|\) (\(1\leq i<j\leq n\)) |
Generate the assignment space
\(\mathbf{D} = \mathbf{D}_{V_{1}}\times\mathbf{D}_{V_{2}}\times\cdots\times\mathbf{D}_{V_{n}}\)
Test each assignment with the constraints.
Example:
\(\mathbf{D}\) | = | \(\mathbf{D}_{A}\times\mathbf{D}_{B}\times\mathbf{D}_{C}\times\mathbf{D}_{D}\times\mathbf{D}_{E}\) |
= | \(\{1,2,3,4\}\times\cdots\times\{1,2,3,4\}\) | |
= | \(\{(1,1,1,1,1),(1,1,1,1,2),\ldots,(4,4,4,4,4)\}\) |
How many assignments need to be tested for \(n\) variables,
each with domain size \(d=|\mathbf{D_i}|\)?
Let’s start with the straightforward, dumb approach.
Every solution appears at depth \(n\) (assuming \(n\) variables)
\(\Longrightarrow\) we can use depth-first-search, no risk for infinite loops
Variable assignments are commutative:
It’s unnecessary work to assign \(WA\) followed by \(NT\) in one branch,
and \(NT\) followed by \(WA\) in another branch.
Instead, at each depth level, we can decide on one single variable to assign:
Depth-first search with single-variable assignments is called backtracking search:
Why not use breadth-first search?
Variables: | \(A, B, C\) |
Domains: | \(\mathbf{D}_{A}=\mathbf{D}_{B}=\mathbf{D}_{C}=\{1,2,3,4\}\) |
Constraints: | \((A<B), (B<C)\) |
The general-purpose algorithm gives rise to several questions:
Heuristics for selecting the next unassigned variable:
Minimum remaining values (MRV):
\(\Longrightarrow\) choose the variable with the fewest legal values
Degree heuristic (if there are several MRV variables):
\(\Longrightarrow\) choose the variable with most constraints on remaining variables
Heuristics for ordering the values of a selected variable:
Forward checking propagates information from assigned to
unassigned
variables,
but doesn’t detect all failures early:
NT and SA cannot both be blue!
The simplest form of propagation is to make each arc consistent:
\(X\rightarrow Y\) is arc consistent iff:
for every value \(x\) of \(X\), there is some allowed value \(y\) in \(Y\)
Different variants of constistency:
A variable is node-consistent if all values in its domain satisfy
its own unary constraints,
a variable is arc-consistent if every value in its domain satisfies
the variable’s binary constraints,
Generalised arc-consistency is the same, but for \(n\)-ary constraints,
Path consistency is arc-consistency, but for 3 variables at the same time.
\(k\)-consistency is arc-consistency, but for \(k\) variables,
…and there are consistency checks for several global constraints,
such as \(\mathit{Alldiff}\) and \(\mathit{Atmost}\).
A network is \(X\)-consistent if every variable is \(X\)-consistent with every other variable.
Variables: | \(A, B, C, D, E\) representing starting times of various activities. |
Domains: | \(\mathbf{D}_{A}=\mathbf{D}_{B}=\mathbf{D}_{C}=\mathbf{D}_{D}=\mathbf{D}_{E} = \{1,2,3,4\}\) |
Constraints: | \((B\neq3), (C\neq2), (A\neq B), (B\neq C), (C<D), (A=D),\) \((E<A), (E<B), (E<C), (E<D), (B\neq D)\) |
Is this example node consistent?
\(\mathbf{D}_{B}=\{1,2,3,4\}\) is not node consistent,
since \(B=3\) violates the constraint \(B\neq3\)
\(\Longrightarrow\) reduce the domain \(\mathbf{D}_{B}=\{1,2,4\}\)
\(\mathbf{D}_{C}=\{1,2,3,4\}\) is not node consistent,
since \(C=2\) violates the constraint \(C\neq2\)
\(\Longrightarrow\) reduce the domain \(\mathbf{D}_{C}=\{1,3,4\}\)
If we reduce the domains for \(B\) and \(C\), then the constraint graph is node consistent.
Keep a set of arcs to be considered: pick one arc \((X,Y)\) at the time and make it consistent (i.e., make \(X\) arc consistent to \(Y\)).
When an arc has been made arc consistent, does it ever need to be checked again?
Three possible outcomes when all arcs are made arc consistent:
(Is there a solution?)
The variables and constraints are in the constraint graph:
Assume the initial domains are \(\mathbf{D}_{A}=\mathbf{D}_{B}=\mathbf{D}_{C}=\{1,2,3,4\}\)
How will the domains look like after making the graph arc consistent?
What if some domains have more than one element after AC?
We can always resort to backtracking search:
Do we need to restart AC from scratch?
What if some domains are very big?
Instead of assigning every possible value to a variable, we can split its domain
Split one of the domains, then recursively solve each half, i.e.:
It is often good to split a domain in half, i.e.: