[pypy-svn] r25671 - in pypy/dist/pypy/objspace/constraint: . test
auc at codespeak.net
auc at codespeak.net
Mon Apr 10 18:27:40 CEST 2006
Author: auc
Date: Mon Apr 10 18:27:37 2006
New Revision: 25671
Modified:
pypy/dist/pypy/objspace/constraint/computationspace.py
pypy/dist/pypy/objspace/constraint/constraint.py
pypy/dist/pypy/objspace/constraint/domain.py
pypy/dist/pypy/objspace/constraint/test/test_computationspace.py
pypy/dist/pypy/objspace/constraint/test/test_constraint.py
pypy/dist/pypy/objspace/constraint/test/test_fd.py
Log:
constraint propagation, less wrapping
Modified: pypy/dist/pypy/objspace/constraint/computationspace.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/computationspace.py (original)
+++ pypy/dist/pypy/objspace/constraint/computationspace.py Mon Apr 10 18:27:37 2006
@@ -52,31 +52,83 @@
class W_ComputationSpace(Wrappable):
def __init__(self, obj_space):
self._space = obj_space
- self.domains = self._space.newdict({})
+ # there, var -> dom
+ self.var_doms = self._space.newdict({})
+ # constraint set
self.constraints = self._space.newdict({})
+ # var -> constraints
+ self.var_const_map = {}
+ # freshly added constraints (tell -> propagate)
+ self.to_check = {}
def w_var(self, w_name, w_domain):
assert isinstance(w_name, W_StringObject)
assert isinstance(w_domain, W_AbstractDomain)
- if w_name in self.domains.content:
+ if w_name in self.var_doms.content:
raise OperationError(self._space.w_RuntimeError,
self._space.wrap("Name already used"))
- self.domains.content[w_name] = w_domain
- return W_Variable(self._space, w_name)
+ var = W_Variable(self._space, w_name)
+ self.var_doms.content[var] = w_domain
+ return var
def w_dom(self, w_variable):
assert isinstance(w_variable, W_Variable)
- return self.domains.content[w_variable.w_name]
+ return self.var_doms.content[w_variable]
def w_tell(self, w_constraint):
assert isinstance(w_constraint, W_Constraint)
self.constraints.content[w_constraint] = self._space.w_True
+ for var in w_constraint.affected_variables():
+ self.var_const_map.setdefault(var, [])
+ self.var_const_map[var].append(w_constraint)
+ self.to_check[w_constraint] = True
+
+ def dependant_constraints(self, var):
+ return self.var_const_map[var]
+
+ def w_propagate(self):
+ return self.propagate()
+
+ def propagate(self):
+ const_q = [(const.estimate_cost_w(self), const)
+ for const in self.to_check]
+ self.to_check = {}
+ assert const_q != []
+ const_q.sort()
+ const_q.reverse() # for pop() friendlyness
+ affected_constraints = {}
+ while True:
+ if not const_q:
+ const_q = [(const.estimate_cost_w(self), const)
+ for const in affected_constraints]
+ if not const_q:
+ break
+ const_q.sort()
+ affected_constraints.clear()
+ cost, const = const_q.pop()
+ entailed = const.revise(self)
+ for var in const.affected_variables():
+ dom = self.w_dom(var)
+ if not dom.has_changed():
+ continue
+ for dependant_const in self.dependant_constraints(var):
+ if dependant_const is not const:
+ affected_constraints[dependant_const] = True
+ dom.w_reset_flags()
+ if entailed:
+ # we should also remove the constraint from
+ # the set of satifiable constraints of the space
+ if const in affected_constraints:
+ affected_constraints.remove(const)
+
+
W_ComputationSpace.typedef = typedef.TypeDef(
"W_ComputationSpace",
var = interp2app(W_ComputationSpace.w_var),
dom = interp2app(W_ComputationSpace.w_dom),
- tell = interp2app(W_ComputationSpace.w_tell))
+ tell = interp2app(W_ComputationSpace.w_tell),
+ propagate = interp2app(W_ComputationSpace.w_propagate))
def newspace(space):
Modified: pypy/dist/pypy/objspace/constraint/constraint.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/constraint.py (original)
+++ pypy/dist/pypy/objspace/constraint/constraint.py Mon Apr 10 18:27:37 2006
@@ -41,12 +41,23 @@
""" Return a list of all variables affected by this constraint """
return self._space.newlist(self._variables)
+ def affected_variables(self):
+ return self._variables
+
def w_knows_var(self, w_variable):
return self._space.newbool(variable in self._variables)
def w_estimate_cost(self, w_cs):
"""Return an estimate of the cost of the narrowing of the constraint"""
assert isinstance(w_cs, W_ComputationSpace)
+ return self._space.newint(self.estimate_cost_w(w_cs))
+
+ def w_revise(self, w_cs):
+ assert isinstance(w_cs, W_ComputationSpace)
+ return self._space.newbool(self.revise(w_cs))
+
+ def estimate_cost_w(self, w_cs):
+ assert isinstance(w_cs, W_ComputationSpace)
return reduce(operator.mul,
[w_cs.w_dom(var).size()
for var in self._variables])
@@ -70,9 +81,9 @@
# worst case complexity
self.__cost = len(w_variables.wrappeditems) * (len(w_variables.wrappeditems) - 1) / 2
- def w_estimate_cost(self, w_cs):
+ def estimate_cost_w(self, w_cs):
assert isinstance(w_cs, W_ComputationSpace)
- return self._space.newint(self.__cost)
+ return self.__cost
def test_solution(self, sol):
"""test a solution against this constraint
@@ -81,7 +92,7 @@
value_set = set(values)
return len(value_set) == len(sol)
- def w_revise(self, w_cs):
+ def revise(self, w_cs):
assert isinstance(w_cs, W_ComputationSpace)
variables = [(self._space.int_w(w_cs.w_dom(variable).w_size()),
variable, w_cs.w_dom(variable))
@@ -111,17 +122,16 @@
print "AllDistinct failed"
raise OperationError(self._space.w_RuntimeError,
self._space.wrap("Consistency Failure"))
-# raise ConsistencyFailure()
# the constraint is entailed if all domains have a size of 1
for variable in variables:
if self._space.is_true(self._space.ne(variable[2].w_size(), self._space.newint(1))):
- return self._space.newint(0)
+ return False
# Question : did we *really* completely check
# our own alldistinctness predicate ?
- return self._space.newint(1)
+ return True
W_AllDistinct.typedef = typedef.TypeDef(
"W_AllDistinct", W_AbstractConstraint.typedef,
@@ -197,10 +207,10 @@
# it's over
go_on = 0
- def w_revise(self, w_cs):
+ def revise(self, w_cs):
"""generic propagation algorithm for n-ary expressions"""
assert isinstance(w_cs, W_ComputationSpace)
- maybe_entailed = self._space.newint(1)
+ maybe_entailed = True
ffunc = self.filter_func
result_cache = self._init_result_cache()
for kwargs in self._assign_values(w_cs):
@@ -215,7 +225,7 @@
for var, val in kwargs.content.items():
result_cache.content[var].content[val] = self._space.w_True
else:
- maybe_entailed = self._space.newint(0)
+ maybe_entailed = False
try:
for varname, keep in result_cache.content.items():
@@ -233,7 +243,6 @@
pass
return maybe_entailed
-
def __repr__(self):
return '<%s>' % self.formula
@@ -304,6 +313,7 @@
"""create a new constraint of type Expression or BinaryExpression
The chosen class depends on the number of variables in the constraint"""
# encode unicode
+ return W_Expression(o_space, w_variables, w_formula)
if o_space.eq_w(o_space.len(w_variables), o_space.newint(2)):
return W_BinaryExpression(o_space, w_variables, w_formula)
else:
Modified: pypy/dist/pypy/objspace/constraint/domain.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/domain.py (original)
+++ pypy/dist/pypy/objspace/constraint/domain.py Mon Apr 10 18:27:37 2006
@@ -30,7 +30,13 @@
def w_has_changed(self):
return self._space.newbool(self.__changed)
+ def has_changed(self):
+ return self.__changed
+
def w_size(self):
+ return self._space.newint(self.size())
+
+ def size(self):
pass
def _value_removed(self):
@@ -77,12 +83,10 @@
for w_val in w_values.wrappeditems :
del self._values[w_val]
self._value_removed()
- __delitem__ = w_remove_value
- def w_size(self):
+ def size(self):
"""computes the size of a finite domain"""
- return self._space.newint(len(self._values))
- __len__ = w_size
+ return len(self._values)
def w_get_values(self):
"""return all the values in the domain
@@ -108,8 +112,10 @@
def __ne__(self, w_other):
return not self == w_other
+
# function bolted into the space to serve as constructor
def make_fd(space, w_values):
+ assert isinstance(w_values, W_ListObject)
return space.wrap(W_FiniteDomain(space, w_values))
app_make_fd = gateway.interp2app(make_fd)
Modified: pypy/dist/pypy/objspace/constraint/test/test_computationspace.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/test/test_computationspace.py (original)
+++ pypy/dist/pypy/objspace/constraint/test/test_computationspace.py Mon Apr 10 18:27:37 2006
@@ -14,16 +14,14 @@
cspace = newspace()
v = cspace.var("foo", FiniteDomain([1,2,3]))
assert str(v).startswith('<W_Variable object at')
- #FIXME: raise the good exc. type
- raises(Exception, cspace.var, "foo", FiniteDomain([1,2,3]))
-
+ v = cspace.var("foo", FiniteDomain([1,2,3]))
+ assert str(v).startswith('<W_Variable object at')
def test_dom(self):
cspace = newspace()
domain = FiniteDomain([1,2,3])
v = cspace.var("foo", domain)
assert cspace.dom(v) is domain
-
def test_tell(self):
csp = newspace()
@@ -31,3 +29,17 @@
v2 = csp.var('v2', FiniteDomain([1, 2]))
cstr = AllDistinct([v1, v2])
csp.tell(cstr)
+
+ def test_propagate(self):
+ csp = newspace()
+ x = csp.var('x', FiniteDomain([1]))
+ y = csp.var('y', FiniteDomain([1, 2]))
+ z = csp.var('z', FiniteDomain([1, 2, 3]))
+ csp.tell(make_expression([x, y], 'x<y'))
+ csp.tell(make_expression([y, z], 'y<z'))
+ csp.tell(make_expression([x, z], 'x<z'))
+ csp.propagate()
+ assert csp.dom(x) == FiniteDomain([1])
+ assert csp.dom(y) == FiniteDomain([2])
+ assert csp.dom(z) == FiniteDomain([3])
+
Modified: pypy/dist/pypy/objspace/constraint/test/test_constraint.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/test/test_constraint.py (original)
+++ pypy/dist/pypy/objspace/constraint/test/test_constraint.py Mon Apr 10 18:27:37 2006
@@ -78,3 +78,4 @@
assert cstr.revise(csp) == 0
assert csp.dom(v1).get_values() == [1]
+
Modified: pypy/dist/pypy/objspace/constraint/test/test_fd.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/test/test_fd.py (original)
+++ pypy/dist/pypy/objspace/constraint/test/test_fd.py Mon Apr 10 18:27:37 2006
@@ -1,6 +1,6 @@
from pypy.conftest import gettestobjspace
-class AppTest_FD(object):
+class AppTest_FiniteDomain(object):
def setup_class(cls):
cls.space = gettestobjspace('logic')
@@ -58,3 +58,4 @@
fd2 = FiniteDomain([2, 3, 4])
assert intersection(fd1, fd2) == FiniteDomain([2, 3])
assert intersection(fd2, fd1) == FiniteDomain([3, 2])
+
More information about the Pypy-commit
mailing list