[pypy-svn] r25496 - in pypy/dist/pypy/objspace/constraint: . test

auc at codespeak.net auc at codespeak.net
Fri Apr 7 15:24:47 CEST 2006


Author: auc
Date: Fri Apr  7 15:24:45 2006
New Revision: 25496

Modified:
   pypy/dist/pypy/objspace/constraint/computationspace.py
   pypy/dist/pypy/objspace/constraint/constraint.py
   pypy/dist/pypy/objspace/constraint/test/test_computationspace.py
   pypy/dist/pypy/objspace/constraint/test/test_constraint.py
Log:
made the constraints stateless


Modified: pypy/dist/pypy/objspace/constraint/computationspace.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/computationspace.py	(original)
+++ pypy/dist/pypy/objspace/constraint/computationspace.py	Fri Apr  7 15:24:45 2006
@@ -7,8 +7,11 @@
 
 from pypy.objspace.constraint.domain import W_AbstractDomain
 
+
 all_mms = {}
 
+#-- Variables ---------------------------
+
 class W_Variable(Wrappable):
     def __init__(self, obj_space, w_name):
         self._space = obj_space
@@ -16,10 +19,44 @@
 
 W_Variable.typedef = typedef.TypeDef("W_Variable")
 
+
+#-- Constraints -------------------------
+
+class W_Constraint(Wrappable):
+    def __init__(self, object_space):
+        self._space = object_space
+
+    def w_affected_variables(self):
+        pass
+
+    def w_is_variable_relevant(self, w_var):
+        pass
+
+    def w_estimate_cost(self, w_cs):
+        pass
+
+    def w_copy_to(self, w_computation_space):
+        pass
+
+    def w_revise(self, w_cs):
+        pass
+    
+W_Constraint.typedef = typedef.TypeDef(
+    "W_Constraint",
+    affected_variables = interp2app(W_Constraint.w_affected_variables),
+    is_variable_relevant = interp2app(W_Constraint.w_is_variable_relevant),
+    estimate_cost = interp2app(W_Constraint.w_estimate_cost),
+    copy_to = interp2app(W_Constraint.w_copy_to),
+    revise = interp2app(W_Constraint.w_revise)
+    )
+
+#-- Computation space -------------------
+
 class W_ComputationSpace(Wrappable):
     def __init__(self, obj_space):
         self._space = obj_space
         self.domains = self._space.newdict({})
+        self.constraints = self._space.newdict({})
 
     def w_var(self, w_name, w_domain):
         assert isinstance(w_name, W_StringObject)
@@ -34,10 +71,15 @@
         assert isinstance(w_variable, W_Variable)
         return self.domains.content[w_variable.name]
 
+    def w_tell(self, w_constraint):
+        assert isinstance(w_constraint, W_Constraint)
+        self.constraints.content[w_constraint] = self._space.w_True
+
 W_ComputationSpace.typedef = typedef.TypeDef(
     "W_ComputationSpace",
     var = interp2app(W_ComputationSpace.w_var),
-    dom = interp2app(W_ComputationSpace.w_dom))
+    dom = interp2app(W_ComputationSpace.w_dom),
+    tell = interp2app(W_ComputationSpace.w_tell))
 
 
 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	Fri Apr  7 15:24:45 2006
@@ -5,8 +5,9 @@
 
 from pypy.objspace.std.listobject import W_ListObject
 
-
 from pypy.objspace.constraint.computationspace import W_ComputationSpace
+from pypy.objspace.constraint.computationspace import W_Constraint
+
 
 #from variable import NoDom
 import operator
@@ -24,42 +25,12 @@
 
 #-- Constraints ------------------------------------------
 
-class W_Constraint(Wrappable):
-    def __init__(self, object_space, computation_space):
-        self._space = object_space
-        assert isinstance(computation_space, W_ComputationSpace)
-        self.cs = computation_space
-
-    def w_affected_variables(self):
-        pass
-
-    def w_is_variable_relevant(self, w_var):
-        pass
-
-    def w_estimate_cost(self):
-        pass
-
-    def w_copy_to(self, w_computation_space):
-        pass
-
-    def w_revise(self):
-        pass
-    
-W_Constraint.typedef = typedef.TypeDef(
-    "W_Constraint",
-    affected_variables = interp2app(W_Constraint.w_affected_variables),
-    is_variable_relevant = interp2app(W_Constraint.w_is_variable_relevant),
-    estimate_cost = interp2app(W_Constraint.w_estimate_cost),
-    copy_to = interp2app(W_Constraint.w_copy_to),
-    revise = interp2app(W_Constraint.w_revise)
-    )
-
 
 class W_AbstractConstraint(W_Constraint):
     
-    def __init__(self, object_space, c_space, w_variables):
+    def __init__(self, object_space, w_variables):
         """variables is a list of variables which appear in the formula"""
-        W_Constraint.__init__(self, object_space, c_space)
+        W_Constraint.__init__(self, object_space)
         assert isinstance(w_variables, W_ListObject)
         assert self._space.is_true(self._space.gt(self._space.len(w_variables), self._space.newint(1)))
         self._names_to_vars = {}
@@ -74,13 +45,12 @@
     def w_is_variable_relevant(self, w_variable):
         return variable in self._variables
 
-    def w_estimate_cost(self):
+    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 reduce(operator.mul,
-                      [self.cs.w_dom(var).size() for var in self._variables])
-
-    def copy_to(self, space):
-        return self.__class__(space, self._variables)
+                      [w_cs.w_dom(var).size()
+                       for var in self._variables])
 
     def __eq__(self, other): #FIXME and parent
         if not isinstance(other, self.__class__): return False
@@ -93,61 +63,8 @@
     copy_to = interp2app(W_AbstractConstraint.w_copy_to),
     revise = interp2app(W_AbstractConstraint.w_revise)
 ) 
-class W_BasicConstraint(W_Constraint):
-    """A BasicConstraint, which is never queued by the Repository
-    A BasicConstraint affects only one variable, and will be entailed
-    on the first call to narrow()"""
-    
-    def __init__(self, object_space, variable, reference, operator):
-        """variables is a list of variables on which
-        the constraint is applied"""
-        W_Constraint.__init__(self, object_space)
-        self._variable = variable
-        self._reference = reference
-        self._operator = operator
-
-    def __repr__(self):
-        return '<%s %s %s>'% (self.__class__, self._variable, self._reference)
-
-    def w_copy_to(self, w_computation_space):
-        raise NotImplementedError
-
-    def w_is_variable_relevant(self, w_variable):
-        return variable == self._variable
-
-    def w_estimate_cost(self):
-        return self._space.newint(0) # get in the first place in the queue
-    
-    def w_affected_variables(self):
-        return [self._variable]
-    
-    def getVariable(self):
-        return self._variable
-        
-    def w_revise(self, w_domains):
-        domain = domains[self._variable]
-        operator = self._operator
-        ref = self._reference
-        try:
-            for val in domain.get_values() :
-                if not operator(val, ref) :
-                    domain.remove_value(val)
-        except ConsistencyFailure:
-            raise ConsistencyFailure('inconsistency while applying %s' % \
-                                     repr(self))
-        return 1
 
-    def __eq__(self, other):
-        raise NotImplementedError
 
-W_BasicConstraint.typedef = typedef.TypeDef(
-    "W_BasicConstraint",
-    affected_variables = interp2app(W_BasicConstraint.w_affected_variables),
-    is_variable_relevant = interp2app(W_BasicConstraint.w_is_variable_relevant),
-    estimate_cost = interp2app(W_BasicConstraint.w_estimate_cost),
-    copy_to = interp2app(W_BasicConstraint.w_copy_to),
-    revise = interp2app(W_BasicConstraint.w_revise)
-    )
 
 def make_lambda_head(vars):
     var_ids = ','.join([var.name for var in vars])
@@ -162,8 +79,8 @@
 class W_AllDistinct(W_AbstractConstraint):
     """Contraint: all values must be distinct"""
 
-    def __init__(self, object_space, w_c_space, w_variables):
-        W_AbstractConstraint.__init__(self, object_space, w_c_space, w_variables)
+    def __init__(self, object_space, w_variables):
+        W_AbstractConstraint.__init__(self, object_space, w_variables)
         assert len(w_variables.wrappeditems)>1
         # worst case complexity
         self.__cost = len(w_variables.wrappeditems) * (len(w_variables.wrappeditems) - 1) / 2
@@ -171,10 +88,8 @@
     def w__repr__(self):
         return self._space.newstring('<AllDistinct %s>' % str(self._variables))
 
-    def w_copy_to(self, w_computation_space):
-        return self.__class__(space, self._variables)
-
-    def w_estimate_cost(self):
+    def w_estimate_cost(self, w_cs):
+        assert isinstance(w_cs, W_ComputationSpace)
         return self._space.newint(self.__cost)
 
     def test_solution(self, sol):
@@ -184,9 +99,10 @@
         value_set = set(values)
         return len(value_set) == len(sol)
 
-    def w_revise(self):
-        variables = [(self._space.int_w(self.cs.w_dom(variable).w_size()),
-                      variable, self.cs.w_dom(variable))
+    def w_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))
                      for variable in self._variables.wrappeditems]
         
         variables.sort()
@@ -233,8 +149,8 @@
     )
 
 # function bolted into the space to serve as constructor
-def make_alldistinct(objectspace, w_computationspace, w_variables):
-    return objectspace.wrap(W_AllDistinct(objectspace, w_computationspace, w_variables))
+def make_alldistinct(objectspace, w_variables):
+    return objectspace.wrap(W_AllDistinct(objectspace, w_variables))
 app_make_alldistinct = gateway.interp2app(make_alldistinct)
 
 class W_Expression(W_AbstractConstraint):
@@ -275,11 +191,11 @@
         return result_cache
 
 
-    def _assign_values(self):
+    def _assign_values(self, w_cs):
         variables = []
         kwargs = {}
         for variable in self._variables:
-            domain = self.cs.w_dom(variable)
+            domain = w_cs.w_dom(variable)
             values = domain.w_get_values()
             variables.append((domain.w_size(), [variable, values, 0, len(values)]))
             kwargs[variable.name] = values[0]
@@ -302,13 +218,13 @@
                 # it's over
                 go_on = 0
         
-    def revise(self):
-        # removed domain arg. (auc, ale)
+    def revise(self, w_cs):
         """generic propagation algorithm for n-ary expressions"""
+        assert isinstance(w_cs, W_ComputationSpace)
         maybe_entailed = 1
         ffunc = self.filterFunc
         result_cache = self._init_result_cache()
-        for kwargs in self._assign_values():
+        for kwargs in self._assign_values(w_cs):
             if maybe_entailed:
                 for var, val in kwargs.iteritems():
                     if val not in result_cache[var]:
@@ -323,7 +239,7 @@
                 
         try:
             for var, keep in result_cache.iteritems():
-                domain = self.cs.w_dom(self._names_to_vars[var])
+                domain = w_cs.w_dom(self._names_to_vars[var])
                 domain.remove_values([val for val in domain if val not in keep])
                 
         except ConsistencyFailure:
@@ -349,6 +265,7 @@
                                         W_AbstractConstraint.typedef)
 
 
+# completely unported
 class BinaryExpression(W_Expression):
     """A binary constraint represented as a python expression
 
@@ -431,6 +348,65 @@
             return Expression(vars, formula)
 
 
+
+
+
+
+
+
+# have a look at this later ... (really needed ?)
+class W_BasicConstraint(W_Constraint):
+    """A BasicConstraint, which is never queued by the Repository
+    A BasicConstraint affects only one variable, and will be entailed
+    on the first call to narrow()"""
+    
+    def __init__(self, object_space, variable, reference, operator):
+        """variables is a list of variables on which
+        the constraint is applied"""
+        W_Constraint.__init__(self, object_space)
+        self._variable = variable
+        self._reference = reference
+        self._operator = operator
+
+    def __repr__(self):
+        return '<%s %s %s>'% (self.__class__, self._variable, self._reference)
+
+    def w_is_variable_relevant(self, w_variable):
+        return variable == self._variable
+
+    def w_estimate_cost(self):
+        return self._space.newint(0) # get in the first place in the queue
+    
+    def w_affected_variables(self):
+        return [self._variable]
+    
+    def getVariable(self):
+        return self._variable
+        
+    def w_revise(self, w_domains):
+        domain = domains[self._variable]
+        operator = self._operator
+        ref = self._reference
+        try:
+            for val in domain.get_values() :
+                if not operator(val, ref) :
+                    domain.remove_value(val)
+        except ConsistencyFailure:
+            raise ConsistencyFailure('inconsistency while applying %s' % \
+                                     repr(self))
+        return 1
+
+    def __eq__(self, other):
+        raise NotImplementedError
+
+W_BasicConstraint.typedef = typedef.TypeDef(
+    "W_BasicConstraint",
+    affected_variables = interp2app(W_BasicConstraint.w_affected_variables),
+    is_variable_relevant = interp2app(W_BasicConstraint.w_is_variable_relevant),
+    estimate_cost = interp2app(W_BasicConstraint.w_estimate_cost),
+    copy_to = interp2app(W_BasicConstraint.w_copy_to),
+    revise = interp2app(W_BasicConstraint.w_revise)
+    )
 class W_Equals(W_BasicConstraint):
     """A basic constraint variable == constant value"""
     def __init__(self, variable, reference):

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	Fri Apr  7 15:24:45 2006
@@ -25,4 +25,9 @@
         assert cspace.dom(v) is domain
         
 
-
+    def test_tell(self):
+        csp = newspace()
+        v1 = csp.var('v1', FiniteDomain([1, 2]))
+        v2 = csp.var('v2', FiniteDomain([1, 2]))
+        cstr = AllDistinct([v1, v2])
+        csp.tell(cstr)

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	Fri Apr  7 15:24:45 2006
@@ -10,7 +10,7 @@
         cspace = newspace()
         v1 = cspace.var('v1', FiniteDomain([1,2]))
         v2 = cspace.var('v2', FiniteDomain([1,2]))
-        cstr = AllDistinct(cspace, [v1, v2])
+        cstr = AllDistinct([v1, v2])
         variables = cstr.affected_variables()
         assert variables is not None
         assert len(variables) == 2
@@ -21,38 +21,41 @@
         csp = newspace()
         v1 = csp.var('v1', FiniteDomain([1, 2]))
         v2 = csp.var('v2', FiniteDomain([1, 2]))
-        cstr = AllDistinct(csp, [v1, v2])
-        assert cstr.estimate_cost() == 1
+        cstr = AllDistinct([v1, v2])
+        assert cstr.estimate_cost(csp) == 1
 
     def notest_repr(self):
         csp = newspace()
         v1 = csp.var('v1', FiniteDomain([1, 2]))
         v2 = csp.var('v2', FiniteDomain([1, 2]))
-        cstr = AllDistinct(csp, [v1, v2])
+        cstr = AllDistinct([v1, v2])
         print cstr
 
     def test_revise(self):
         csp = newspace()
         v1 = csp.var('v1', FiniteDomain([1, 2]))
         v2 = csp.var('v2', FiniteDomain([1, 2]))
-        cstr = AllDistinct(csp, [v1, v2])
-        assert cstr.revise() == 0 # not entailed
+        cstr = AllDistinct([v1, v2])
+        assert cstr.revise(csp) == 0 # not entailed
 
         v3 = csp.var('v3', FiniteDomain([1]))
         v4 = csp.var('v4', FiniteDomain([2]))
-        cstr = AllDistinct(csp, [v3, v4])
-        assert cstr.revise() == 1 # entailed
+        cstr = AllDistinct([v3, v4])
+        assert cstr.revise(csp) == 1 # entailed
 
         v5 = csp.var('v5', FiniteDomain([1]))
         v6 = csp.var('v6', FiniteDomain([1]))
-        cstr = AllDistinct(csp, [v5, v6])
-        raises(Exception, cstr.revise)
-
-        cstr = AllDistinct(csp, [v1, v5])
-        assert cstr.revise() == 1
-        assert csp.dom(v1).get_values() == [2]
+        cstr = AllDistinct([v5, v6])
+        raises(Exception, cstr.revise, csp)
 
         v7 = csp.var('v7', FiniteDomain([1, 2]))
         v8 = csp.var('v8', FiniteDomain([1, 2]))
-        cstr = AllDistinct(csp,   [v2, v7, v8])
-        raises(Exception, cstr.revise)
+        cstr = AllDistinct([v2, v7, v8])
+        raises(Exception, cstr.revise, csp)
+
+        v9 = csp.var('v9', FiniteDomain([1]))
+        v10= csp.var('v10', FiniteDomain([1,2]))
+        cstr = AllDistinct([v9, v10])
+        assert cstr.revise(csp) == 1
+        assert csp.dom(v10).get_values() == [2]
+



More information about the Pypy-commit mailing list