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

auc at codespeak.net auc at codespeak.net
Tue Aug 8 15:23:34 CEST 2006


Author: auc
Date: Tue Aug  8 15:23:30 2006
New Revision: 31161

Modified:
   pypy/dist/pypy/objspace/cclp/scheduler.py
   pypy/dist/pypy/objspace/cclp/space.py
   pypy/dist/pypy/objspace/cclp/types.py
   pypy/dist/pypy/objspace/cclp/variable.py
   pypy/dist/pypy/objspace/constraint/domain.py
   pypy/dist/pypy/objspace/constraint/test/test_fd.py
   pypy/dist/pypy/objspace/logic.py
   pypy/dist/pypy/objspace/test/test_logicobjspace.py
Log:
many fixes, constraint vars, domain_of, ....


Modified: pypy/dist/pypy/objspace/cclp/scheduler.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/scheduler.py	(original)
+++ pypy/dist/pypy/objspace/cclp/scheduler.py	Tue Aug  8 15:23:30 2006
@@ -9,8 +9,6 @@
 
 #-- Singleton scheduler ------------------------------------------------
 
-class FunnyBoat: pass
-
 class Scheduler(object):
 
     def __init__(self, space):
@@ -89,7 +87,7 @@
                 import traceback
                 traceback.print_exc()
             self.display_head()
-        thread._next = thread._prev = FunnyBoat
+        thread._next = thread._prev = None
         # cspace/threads account mgmt
         if thread._cspace is not None:
             count = self.dec_live_thread_count(thread._cspace)
@@ -99,12 +97,14 @@
     #-- cspace helper
 
     def is_stable(self, cspace):
-        if not self._per_space_live_threads.has_key(cspace):
+        assert isinstance(cspace, W_CSpace)
+        if cspace not in self._per_space_live_threads.keys():
             #XXX meaning ?
             return True
         return self._per_space_live_threads[cspace] == 0
 
     def wait_stable(self, cspace):
+        assert isinstance(cspace, W_CSpace)
         if self.is_stable(cspace):
             return
         curr = ClonableCoroutine.w_getcurrent(self.space)
@@ -120,11 +120,13 @@
 
     #-- cspace -> thread_count helpers
     def inc_live_thread_count(self, cspace):
+        assert isinstance(cspace, W_CSpace)
         count = self._per_space_live_threads.get(cspace, 0) + 1
         self._per_space_live_threads[cspace]  = count
         return count
 
     def dec_live_thread_count(self, cspace):
+        assert isinstance(cspace, W_CSpace)
         count = self._per_space_live_threads[cspace] -1
         assert count >= 0
         self._per_space_live_threads[cspace] = count 

Modified: pypy/dist/pypy/objspace/cclp/space.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/space.py	(original)
+++ pypy/dist/pypy/objspace/cclp/space.py	Tue Aug  8 15:23:30 2006
@@ -47,18 +47,20 @@
 
     def __init__(self, space, thread, parent=None):
         assert isinstance(thread, ClonableCoroutine)
-        assert (parent is None) or isinstance(parent, CSpace)
+        assert (parent is None) or isinstance(parent, W_CSpace)
         self.space = space # the object space ;-)
         self.parent = parent
         self.main_thread = thread
         # choice mgmt
         self._choice = newvar(space)
         self._committed = newvar(space)
+        # constraint store ...
+        
 
     def w_ask(self):
         scheduler[0].wait_stable(self)
         self.space.wait(self._choice)
-        return self.space.newint(self._choice)
+        return self._choice
 
     def choose(self, n):
         assert n > 1
@@ -74,10 +76,13 @@
     def w_commit(self, w_n):
         assert self.space.is_true(self.space.is_bound(self._choice))
         assert 0 < self.space.int_w(w_n)
-        assert self.space.int_w(w_n) <= self._choice
+        assert self.space.int_w(w_n) <= self._choice.w_bound_to
         self.space.bind(self._committed, w_n)
         self._choice = newvar(self.space)
-        
+
+
+    def tell(self, w_constraint):
+        pass
 
 W_CSpace.typedef = typedef.TypeDef("W_CSpace",
     ask = gateway.interp2app(W_CSpace.w_ask),
@@ -86,13 +91,6 @@
 
 
 
-##     def is_top_level(self):
-##         return self.parent is None
-
-##     def current_space():
-##         #XXX return w_getcurrent().cspace
-##         pass
-
 
 ##     def clone(self):
 ##         if self.is_top_level():
@@ -105,20 +103,3 @@
 ##             tclone.cspace = new
 ##             new.threads[tclone] = True
 
-##     def choose(self, n):
-##         if self.is_top_level():
-##             raise OperationError(self.space.w_RuntimeError,
-##                                  self.space.wrap("Choose"+forbidden_boilerplate))
-
-##     def ask(self):
-##         if self.is_top_level():
-##             raise OperationError(self.space.w_RuntimeError,
-##                                  self.space.wrap("Ask"+forbidden_boilerplate))
-##         #XXX basically hang until a call to choose, then return n
-
-##     def commit(self, n):
-##         if self.is_top_level():
-##             raise OperationError(self.space.w_RuntimeError,
-##                                  self.space.wrap("Commit"+forbidden_boilerplate))
-##         # ensure 0 < n < chosen n
-##         # ...

Modified: pypy/dist/pypy/objspace/cclp/types.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/types.py	(original)
+++ pypy/dist/pypy/objspace/cclp/types.py	Tue Aug  8 15:23:30 2006
@@ -1,6 +1,7 @@
-from pypy.interpreter import baseobjspace, typedef
+from pypy.interpreter import baseobjspace, gateway, typedef
 
 from pypy.objspace.cclp.misc import w, ClonableCoroutine
+from pypy.objspace.constraint.domain import W_FiniteDomain
 
 W_Root = baseobjspace.W_Root
 
@@ -20,6 +21,7 @@
                             prettyfy_id(id(w_self)))
     __str__ = __repr__
 
+
 class W_Future(W_Var):
     "a read-only-by-its-consummer variant of logic. var"
     def __init__(w_self, space):
@@ -27,6 +29,18 @@
         w_self._client = ClonableCoroutine.w_getcurrent(space)
         w("FUT", str(w_self))
 
+
+class W_CVar(W_Var):
+    def __init__(w_self, space, w_dom):
+        assert isinstance(w_dom, W_FiniteDomain)
+        W_Var.__init__(w_self, space)
+        w_self.w_dom = w_dom
+
+def domain_of(space, w_v):
+    assert isinstance(w_v, W_CVar)
+    return w_v.w_dom
+app_domain_of = gateway.interp2app(domain_of)
+
 #-- Exception types ----------------------------------------
 
 class W_FailedValue(W_Root):
@@ -36,50 +50,6 @@
     def __init__(w_self, exc):
         w_self.exc = exc
 
-#-- Something to hold the ring of coros --------------------------------
-
-## class Triple(object):
-
-##     def __init__(self, thread):
-##         assert isinstance(thread, ClonableCoroutine)
-##         self._thread = thread
-##         self._prev = self._next = self
-
-##     def get_next(self):
-##         return self._next
-
-##     def get_prev(self):
-##         return self._prev
-
-##     def set_next(self, triple):
-##         assert isinstance(triple, Triple)
-##         self._next = triple
-
-##     def set_prev(self, triple):
-##         assert isinstance(triple, Triple)
-##         self._prev = triple
-
-##     next = property(get_next, set_next)
-##     prev = property(get_prev, set_prev)
-
-##     def insert_before(self, triple):
-##         assert isinstance(triple, Triple)
-##         before = self.prev
-##         # ...
-##         before.next = triple
-##         triple.prev = before
-##         # ...
-##         self.prev = triple
-##         triple.next = self
-
-##     def __str__(self):
-##         curr = self
-##         out = ['[', str(id(self._thread))]
-##         while curr != self:
-##             curr = self.next
-##             out.append(str(id(curr._thread)))
-##         return ''.join(out)
-
 #-- Misc ---------------------------------------------------
 
 def deref(space, w_var):

Modified: pypy/dist/pypy/objspace/cclp/variable.py
==============================================================================
--- pypy/dist/pypy/objspace/cclp/variable.py	(original)
+++ pypy/dist/pypy/objspace/cclp/variable.py	Tue Aug  8 15:23:30 2006
@@ -6,8 +6,9 @@
 
 from pypy.objspace.cclp.misc import w, v, ClonableCoroutine
 from pypy.objspace.cclp.global_state import scheduler
-from pypy.objspace.cclp.types import deref, W_Var, W_Future, W_FailedValue
+from pypy.objspace.cclp.types import deref, W_Var, W_CVar, W_Future, W_FailedValue
 
+from pypy.objspace.constraint.domain import W_FiniteDomain
 
 W_Root = baseobjspace.W_Root
 all_mms = {}
@@ -18,6 +19,14 @@
     return w_v
 app_newvar = gateway.interp2app(newvar)
 
+def domain(space, w_values):
+    assert isinstance(w_values, W_ListObject)
+    w_dom = W_FiniteDomain(space, w_values)
+    w_var = W_CVar(space, w_dom)
+    w("CVAR", str(w_var))
+    return w_var
+app_domain = gateway.interp2app(domain)
+    
 #-- Wait -------------------------------------------------
 
 def wait__Root(space, w_obj):
@@ -110,7 +119,7 @@
 all_mms['is_bound'] = is_bound_mm
 
 
-def alias_of(space, w_var1, w_var2): # FIXME: appears to block
+def alias_of(space, w_var1, w_var2):
     assert isinstance(w_var1, W_Var)
     assert isinstance(w_var2, W_Var)
     assert space.is_true(space.is_free(w_var1))
@@ -118,9 +127,9 @@
     w_curr = w_var1
     while 1:
         w_next = w_curr.w_bound_to
-        if space.is_true(space.is_nb_(w_next, w_var2)):
+        if w_next is w_var2:
             return space.newbool(True)
-        if space.is_true(space.is_nb_(w_next, w_var1)):
+        if w_next is w_var1:
             break
         w_curr = w_next
     return space.newbool(False)
@@ -140,11 +149,11 @@
         w_curr = w_next
 
 
-def raise_unification_failure(space):
+def raise_unification_failure(space, comment="Unification failure"):
     """raises a specific exception for bind/unify
        should fail the current comp. space at some point"""
     raise OperationError(space.w_UnificationError,
-                         space.wrap("Unification failure"))
+                         space.wrap(comment))
 
 # to signal a future binding exception
 def raise_future_binding(space):
@@ -170,19 +179,26 @@
     #w("var val", str(id(w_var)))
     # 3. var and value
     if space.is_true(space.is_free(w_var)):
-        return _assign(space, w_var, w_obj)
+        return _assign_aliases(space, w_var, w_obj)
     if space.is_true(space.eq(w_var.w_bound_to, w_obj)):
         return
     raise OperationError(space.w_RebindingError,
                          space.wrap("Cannot bind twice but two identical values"))
 
-
 def bind__Future_Root(space, w_fut, w_obj):
     #v("future val", str(id(w_fut)))
     if w_fut._client == ClonableCoroutine.w_getcurrent(space):
         raise_future_binding(space)
     return bind__Var_Root(space, w_fut, w_obj) # call-next-method ?
 
+def bind__CVar_Root(space, w_cvar, w_obj):
+    #XXX we should (want to) be able to test membership
+    #    in a wrapped against wrappeds into a non-wrapped dict
+    if [True for elt in w_cvar.w_dom._values
+        if space.is_true(space.eq(w_obj, elt))]:
+        return bind__Var_Root(space, w_cvar, w_obj)
+    raise_unification_failure(space, "value not in variable domain")
+
 def bind__Var_Var(space, w_v1, w_v2):
     #w("var var")
     if space.is_true(space.is_bound(w_v1)):
@@ -192,10 +208,10 @@
                          deref(space, w_v1),
                          deref(space, w_v2))
         # 2. a (obj unbound, var bound)
-        return _assign(space, w_v2, deref(space, w_v1))
+        return _assign_aliases(space, w_v2, deref(space, w_v1))
     elif space.is_true(space.is_bound(w_v2)):
         # 2. b (var unbound, obj bound)
-        return _assign(space, w_v1, deref(space, w_v2))
+        return _assign_aliases(space, w_v1, deref(space, w_v2))
     else: # 1. both are unbound
         return _alias(space, w_v1, w_v2)
 
@@ -205,6 +221,24 @@
         raise_future_binding(space)
     return bind__Var_Var(space, w_fut, w_var)
 
+def bind__CVar_CVar(space, w_cvar1, w_cvar2):
+    w_inter_dom = space.intersection(w_cvar1.w_dom, w_cvar2.w_dom)
+    if w_inter_dom.__len__() > 0:
+        if w_inter_dom.__len__() == 1:
+            w_value = w_inter_dom.get_values()[0]
+            _assign_aliases(space, w_cvar1, w_value)
+            _assign_aliases(space, w_cvar2, w_value)
+        else:
+            w_cvar1.w_dom = w_cvar2.w_dom = w_inter_dom
+            _alias(space, w_cvar1, w_cvar2)
+    else:
+        raise_unification_failure(space, "incompatible domains")
+
+def bind__CVar_Var(space, w_cvar, w_var):
+    if space.is_true(space.is_bound(w_var)):
+        return bind__CVar_Root(space, w_cvar, w_var)
+    return bind__Var_Var(space, w_cvar, w_var)
+
 def bind__Var_Future(space, w_var, w_fut): 
     if space.is_true(space.is_bound(w_fut)): #XXX write a test for me !
         return bind__Var_Root(space, w_var, deref(space, w_fut))
@@ -218,16 +252,19 @@
 bind_mm.register(bind__Future_Root, W_Future, W_Root)
 bind_mm.register(bind__Future_Var, W_Future, W_Var)
 bind_mm.register(bind__Var_Future, W_Var, W_Future)
+bind_mm.register(bind__CVar_CVar, W_CVar, W_CVar)
+bind_mm.register(bind__CVar_Root, W_CVar, W_Root)
+bind_mm.register(bind__CVar_Var, W_CVar, W_Var)
 all_mms['bind'] = bind_mm
 
-def _assign(space, w_var, w_val):
+def _assign_aliases(space, w_var, w_val):
     w("  :assign")
     assert isinstance(w_var, W_Var)
     assert isinstance(w_val, W_Root)
     w_curr = w_var
     while 1:
         w_next = w_curr.w_bound_to
-        w_curr.w_bound_to = w_val
+        _assign(space, w_curr, w_val)
         # notify the blocked threads
         scheduler[0].unblock_on(w_curr)
         if space.is_true(space.is_nb_(w_next, w_var)):
@@ -236,6 +273,14 @@
         w_curr = w_next
     w("  :assigned")
     return space.w_None
+
+def _assign(space, w_var, w_val):
+    assert isinstance(w_var, W_Var)
+    if isinstance(w_var, W_CVar):
+        if not w_val in w_var.w_dom._values:
+            raise_unification_failure(space, "assignment out of domain")
+    w_var.w_bound_to = w_val
+
     
 def _alias(space, w_v1, w_v2):
     """appends one var to the alias chain of another

Modified: pypy/dist/pypy/objspace/constraint/domain.py
==============================================================================
--- pypy/dist/pypy/objspace/constraint/domain.py	(original)
+++ pypy/dist/pypy/objspace/constraint/domain.py	Tue Aug  8 15:23:30 2006
@@ -91,6 +91,7 @@
     def size(self):
         """computes the size of a finite domain"""
         return len(self._values)
+    __len__ = size
     
     def w_get_values(self):
         """return all the values in the domain
@@ -136,9 +137,9 @@
 
 def intersection__FiniteDomain_FiniteDomain(space, w_fd1, w_fd2):
     w_v1 = w_fd1._values
-    w_res = [w_v for w_v in w_fd2._values
+    res = [w_v for w_v in w_fd2._values
              if w_v in w_v1]
-    return make_fd(space, space.newlist(w_res))
+    return make_fd(space, space.newlist(res))
 
 intersection_mm = StdObjSpaceMultiMethod('intersection', 2)
 intersection_mm.register(intersection__FiniteDomain_FiniteDomain,

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	Tue Aug  8 15:23:30 2006
@@ -2,7 +2,6 @@
 from py.test import skip
 
 class AppTest_FiniteDomain(object):
-    skip("currently unplugged")
     
     def setup_class(cls):
         cls.space = gettestobjspace('logic', usemodules=('_stackless', ))

Modified: pypy/dist/pypy/objspace/logic.py
==============================================================================
--- pypy/dist/pypy/objspace/logic.py	(original)
+++ pypy/dist/pypy/objspace/logic.py	Tue Aug  8 15:23:30 2006
@@ -27,17 +27,19 @@
 
 from pypy.objspace.cclp.variable import app_newvar, wait, app_wait, app_wait_needed, \
      app_is_aliased, app_is_free, app_is_bound, app_alias_of, alias_of, app_bind, \
-     app_unify, W_Var, W_Future, all_mms as variable_mms
+     app_unify, W_Var, W_CVar, W_Future, app_domain, all_mms as variable_mms
+
+from pypy.objspace.cclp.types import app_domain_of
 
 all_mms.update(variable_mms)
 
 #-- CONSTRAINTS ----------------------------------------------
 
 ## #------ domains ------------------
-## from pypy.objspace.constraint import domain 
-## all_mms.update(domain.all_mms)
+from pypy.objspace.constraint import domain 
+all_mms.update(domain.all_mms)
 
-## W_FiniteDomain = domain.W_FiniteDomain
+W_FiniteDomain = domain.W_FiniteDomain
 
 ## #-------- computationspace --------
 ## from pypy.objspace.constraint import computationspace
@@ -192,8 +194,9 @@
     # multimethods hack
     space.model.typeorder[W_Var] = [(W_Var, None), (W_Root, None)] # None means no conversion
     space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None)]
+    space.model.typeorder[W_CVar] = [(W_CVar, None), (W_Var, None)]
     space.model.typeorder[W_CSpace] = [(W_CSpace, None), (baseobjspace.Wrappable, None)]
-##     space.model.typeorder[W_FiniteDomain] = [(W_FiniteDomain, None), (W_Root, None)] 
+    space.model.typeorder[W_FiniteDomain] = [(W_FiniteDomain, None), (W_Root, None)] 
 
 
     for name in all_mms.keys():
@@ -211,13 +214,12 @@
         setattr(space, name, boundmethod)  # store into 'space' instance
     # /multimethods hack
 
-    # XXXprovide a UnificationError exception
-    # patching the table in-place?  
-    #space.ExceptionTable.append('UnificationError')
-    #space.ExceptionTable.sort() # hmmm
-
     space.setitem(space.builtin.w_dict, space.wrap('newvar'),
                   space.wrap(app_newvar))
+    space.setitem(space.builtin.w_dict, space.wrap('domain'),
+                  space.wrap(app_domain))
+    space.setitem(space.builtin.w_dict, space.wrap('domain_of'),
+                  space.wrap(app_domain_of))
     space.setitem(space.builtin.w_dict, space.wrap('is_free'),
                   space.wrap(app_is_free))
     space.setitem(space.builtin.w_dict, space.wrap('is_bound'),
@@ -234,10 +236,10 @@
 ##     space.setitem(space.builtin.w_dict, space.wrap('newspace'),
 ##                  space.wrap(computationspace.app_newspace))
 ##     #-- domain -------
-##     space.setitem(space.builtin.w_dict, space.wrap('FiniteDomain'),
-##                  space.wrap(domain.app_make_fd))
-##     space.setitem(space.builtin.w_dict, space.wrap('intersection'),
-##                  space.wrap(domain.app_intersection))
+    space.setitem(space.builtin.w_dict, space.wrap('FiniteDomain'),
+                 space.wrap(domain.app_make_fd))
+    space.setitem(space.builtin.w_dict, space.wrap('intersection'),
+                 space.wrap(domain.app_intersection))
 ##     #-- constraint ----
 ##     space.setitem(space.builtin.w_dict, space.wrap('make_expression'),
 ##                  space.wrap(constraint.app_make_expression))

Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py
==============================================================================
--- pypy/dist/pypy/objspace/test/test_logicobjspace.py	(original)
+++ pypy/dist/pypy/objspace/test/test_logicobjspace.py	Tue Aug  8 15:23:30 2006
@@ -621,6 +621,55 @@
         assert len(sched_all()['threads']) == 1
         
 
+class AppTest_CompSpace(object):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace('logic', usemodules=("_stackless",))
+
+    def test_cvar(self):
+
+        d = domain([1, 2, 4])
+
+        raises(UnificationError, bind, d, 42)
+        bind(d, 2)
+        assert d == 2
+
+        class Foo(object):
+            pass
+
+        f = Foo()
+        d = domain([Foo(), f, Foo()])
+        raises(UnificationError, bind, d, Foo())
+        bind(d, f)
+        assert d == f
+
+        d1 = domain([1, 2, 3])
+        d2 = domain([2, 3, 4])
+        d3 = domain([5, 6])
+        raises(UnificationError, unify, d1, d3)
+        unify(d1, d2)
+        assert alias_of(d1, d2)
+        assert domain_of(d1) == domain_of(d2) == FiniteDomain([2, 3])
+
+        d1 = domain([1, 2, 3])
+        d4 = domain([3, 4])
+        unify(d1, d4)
+        assert d1 == d4 == 3
+
+        d1 = domain([1, 2])
+        x = newvar()
+        unify(d1, x)
+        assert alias_of(x, d1)
+        raises(UnificationError, unify, x, 42)
+
+        d1 = domain([1, 2])
+        x = newvar()
+        unify(d1, x)
+        assert alias_of(x, d1)
+        unify(x, 2)
+        assert d1 == x == 2
+        #XXX and a bunch of app-level functions
+        #raises(TypeError, domain_of, x)
 
     def test_newspace_ask_wait(self):
 
@@ -660,19 +709,35 @@
         assert X == 2
 
 
-    def test_ask_choose(self):
+    def test_more_ask_choose(self):
 
-        def chooser(X):
-            choice = choose(3)
-            unify(X, choice)
+        def chooser(vec, X):
+            for v in vec:
+                choice = choose(v)
+                assert choice == v
+            unify(X, 'done')
 
         def asker(cspace):
-            choices = cspace.ask()
-            cspace.commit(2)
+            while 1:
+                choices = cspace.ask()
+                if choices == 1: # success !
+                    break
+                cspace.commit(choices)
 
+        # choices >= 1
+        v = range(2, 9)
         X = newvar()
-
-        s = newspace(chooser, X)
+        s = newspace(chooser, v, X)
         stacklet(asker, s)
+
         schedule()
-        assert X == 2
+
+        assert len(sched_all()['asking']) == 1
+        assert sched_all()['space_accounting'][0][1] == 0 
+
+        assert X == 'done'
+        schedule()
+        assert len(sched_all()['threads']) == 1
+
+
+    



More information about the Pypy-commit mailing list