Constraints
$X_1 < X_2$
Such a constraint will take two variables as argument and makes sure that the former one takes a value less than the latter one in any solution.
$(1,2)$ and $(2,5)$ satisfy the constraint,
$(2,2)$ and $(5,3)$ do not.
We will first create a class to declare the behaviour of this constraint:
class LessThan:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
We can impose that $X_1$ is strictly less than $X_2$:
variables = {"x1": {1, 2, 3},
"x2": {1, 2, 3}}
c1 = LessThan("x1", "x2") # means that x1 < x2 should hold
What can such a constraint do?
In CP, we remove
The basic behaviour of a constraint is to remove from the variable domain those values that cannot be extended to any solution
(according to its own contract)
We will create an empty function called filter
as follow:
def filter(self,variables):
pass
The 2 rules of $X_1 < X_2$
1. removing from $X_1$ values greater or equal to the largest value in $X_2$,
2. removing from $X_2$ values smaller or equal to the smallest value in $X_1$.
Otherwise, in both cases, we could break the contract established between the 2 variables.
$X_1 = \{1,2,3,4\}$, $X_2 = \{1,2,3,4\}$ and $X_1 < X_2$
Then
- 4 is removed from $X_1$
- 1 is removed from $X_2$
In other words:
- $max(X_2)$ and larger are removed from $X_1$
- $min(X_1)$ and smaller are removed from $X_2$
Deal with dead ends
We can tell that the constraint should return :
True
: if some values were filteredFalse
: if a domain becomes emptyNone
: if nothing was filtered
LessThan
filtering algorithm
class LessThan:
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
def filter(self, variables):
"""
Filter the domain of the variables declared in 'vars'.
The method directly modifies the entries of 'vars'.
It returns True if some values were filtered,
False if a domain becomes empty,
None otherwise.
"""
pass
>>🥛<<
LessThan
filtering algorithm
def filter(self, variables):
cd1 = variables[self.v1] # get current domain of "x1"
cd2 = variables[self.v2] # get current domain of "x2"
# filtering according to the 1st rule
nd1 = {v for v in cd1 if v < max(cd2)}
if len(nd1) == 0: # "x1" becomes empty...
return False
# filtering according to the 2nd rule
nd2 = {v for v in cd2 if v > min(cd1)}
if len(nd2) == 0: # "x2" becomes empty...
return False
variables[self.v1] = nd1 # update the domain of "x1"
variables[self.v2] = nd2 # update the domain of "x2"
modif = cd1 > nd1 or cd2 > nd2 # reduction of a domain
return modif or None
Does that work?
# declare a CSP
variables = {"x1": {1, 2, 3},
"x2": {1, 2, 3}}
c1 = LessThan("x1", "x2")
# call the filtering algorithm
modif = c1.filter(variables)
# check everything works fine
assert variables["x1"] == {1, 2}
assert variables["x2"] == {2, 3}
assert modif == True