[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