[pypy-svn] r22450 - pypy/dist/pypy/lib/logic
auc at codespeak.net
auc at codespeak.net
Thu Jan 19 17:11:56 CET 2006
Author: auc
Date: Thu Jan 19 17:11:54 2006
New Revision: 22450
Modified:
pypy/dist/pypy/lib/logic/test_unification.py
pypy/dist/pypy/lib/logic/unification.py
Log:
unify made atomic
Modified: pypy/dist/pypy/lib/logic/test_unification.py
==============================================================================
--- pypy/dist/pypy/lib/logic/test_unification.py (original)
+++ pypy/dist/pypy/lib/logic/test_unification.py Thu Jan 19 17:11:54 2006
@@ -60,6 +60,10 @@
u.bind(x, [42, z])
u.bind(y, [z, 44])
raises(u.UnificationFailure, u.unify, x, y)
+ # check store consistency
+ assert x.val == [42, z]
+ assert y.val == [z, 44]
+ assert z.val == u.EqSet([z])
def test_unify_failure2(self):
x,y,z,w = (u.var('x'), u.var('y'),
@@ -68,6 +72,11 @@
u.bind(y, [w, 44])
u.bind(z, w)
raises(u.UnificationFailure, u.unify, x, y)
+ # check store consistency
+ assert x.val == [42, z]
+ assert y.val == [w, 44]
+ assert z.val == u.EqSet([z,w])
+ assert w.val == u.EqSet([z,w])
def test_unify_circular(self):
x, y, z, w, a, b = (u.var('x'), u.var('y'),
@@ -82,4 +91,12 @@
u.bind(a, {1:42, 2:b})
u.bind(b, {1:a, 2:42})
raises(u.UnificationFailure, u.unify, a, b)
+ # check store consistency
+ assert x.val == [y]
+ assert y.val == [x]
+ assert z.val == [1, w]
+ assert w.val == [z, 2]
+ assert a.val == {1:42, 2:b}
+ assert b.val == {1:a, 2:42}
+
Modified: pypy/dist/pypy/lib/logic/unification.py
==============================================================================
--- pypy/dist/pypy/lib/logic/unification.py (original)
+++ pypy/dist/pypy/lib/logic/unification.py Thu Jan 19 17:11:54 2006
@@ -3,8 +3,9 @@
# crude and buggy ...
#TODO :
-# * ensure that the store is intact after a failure
-# (make unify atomic)
+# * turn Var into some dataflow-ish thing
+# * ensure that the store supports concurrent access
+# (using the implicit blocking provided by dataflow vars)
# * provide a way to copy the store to a fresh one
# (clone operator)
# After reading more of the "book", I see some more ops
@@ -12,7 +13,7 @@
# space ...
#----------- Variables ----------------------------------
-class EqSet(frozenset):
+class EqSet(set):
"""An equivalence set for variables"""
pass
@@ -25,23 +26,33 @@
self.name = name
self.store = store
# top-level 'commited' binding
- self.val = NoValue
+ self._val = NoValue
# when updated in a 'transaction', keep track
# of our initial value (for abort cases)
self.previous = None
+ self.changed = False
- def begin(self):
- self.previous = self.val
+ def is_bound(self):
+ return not isinstance(self.val, EqSet) \
+ and self.val != NoValue
def commit(self):
- self.previous = None
+ self.changed = False
def abort(self):
self.val = self.previous
+ self.changed = False
- def is_bound(self):
- return not isinstance(self.val, EqSet) \
- and self.val != NoValue
+ def set_val(self, val):
+ if self.store.in_transaction:
+ if not self.changed:
+ self.previous = self._val
+ self.changed = True
+ print "in transaction, %s <- %s" % (self.name, val)
+ self._val = val
+ def get_val(self):
+ return self._val
+ val = property(get_val, set_val)
def __str__(self):
if self.is_bound():
@@ -106,8 +117,6 @@
def __init__(self):
# set of all known vars
self.vars = set()
- # the transaction flag helps manage the change-list
- # for variables
self.in_transaction = False
def add_unbound(self, var):
@@ -154,13 +163,29 @@
print "unbound variables binding : %s %s" % (eqs1, eqs2)
if eqs1 == eqs2: return
# merge two equisets into one
- neweqs = eqs1 | eqs2
+ eqs1 |= eqs2
# let's reassign everybody to neweqs
- self._bind(neweqs, neweqs)
+ self._bind(eqs1, eqs1)
#-- UNIFY ------------------------------------------
def unify(self, x, y):
+ self.in_transaction = True
+ try:
+ try:
+ self._really_unify(x, y)
+ for var in self.vars:
+ if var.changed:
+ var.commit()
+ except:
+ for var in self.vars:
+ if var.changed:
+ var.abort()
+ raise
+ finally:
+ self.in_transaction = False
+
+ def _really_unify(self, x, y):
#FIXME in case of failure, the store state is not
# properly restored ...
print "unify %s with %s" % (x,y)
@@ -169,10 +194,10 @@
if not x in self.vars:
if not y in self.vars:
if x != y: raise UnificationFailure(x, y)
- return self._unify_var_val(y, x)
- if not y in self.vars:
- return self._unify_var_val(x, y)
- if _both_are_bound(x, y):
+ self._unify_var_val(y, x)
+ elif not y in self.vars:
+ self._unify_var_val(x, y)
+ elif _both_are_bound(x, y):
self._unify_bound(x,y)
elif x.isbound():
self.bind(x,y)
@@ -180,7 +205,7 @@
self.bind(y,x)
def _unify_var_val(self, x, y):
- if x.is_bound(): raise UnificationFailure(x ,y)
+ if x.is_bound(): raise UnificationFailure(x, y)
if x != y:
self.bind(x, y)
@@ -199,14 +224,14 @@
vx, vy = (x.val, y.val)
idx, top = (0, len(vx))
while (idx < top):
- self.unify(vx[idx], vy[idx])
+ self._really_unify(vx[idx], vy[idx])
idx += 1
def _unify_mapping(self, x, y):
print "unify mappings %s %s" % (x, y)
vx, vy = (x.val, y.val)
for xk in vx.keys():
- self.unify(vx[xk], vy[xk])
+ self._really_unify(vx[xk], vy[xk])
#-- Unifiability checks---------------------------------------
#--
More information about the Pypy-commit
mailing list