[pypy-svn] r23831 - pypy/dist/pypy/lib/logic/computation_space
auc at codespeak.net
auc at codespeak.net
Wed Mar 1 15:39:57 CET 2006
Author: auc
Date: Wed Mar 1 15:39:53 2006
New Revision: 23831
Modified:
pypy/dist/pypy/lib/logic/computation_space/computationspace.py
pypy/dist/pypy/lib/logic/computation_space/distributor.py
pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py
Log:
* event notification
* ...
Modified: pypy/dist/pypy/lib/logic/computation_space/computationspace.py
==============================================================================
--- pypy/dist/pypy/lib/logic/computation_space/computationspace.py (original)
+++ pypy/dist/pypy/lib/logic/computation_space/computationspace.py Wed Mar 1 15:39:53 2006
@@ -16,16 +16,20 @@
from constraint import FiniteDomain, ConsistencyFailure, \
Expression
from distributor import DefaultDistributor
+import event # NewSpace, Clone, Revise
-class Alternatives(object):
+class Alternative(object):
- def __init__(self, nb_alternatives):
- self._nbalt = nb_alternatives
+ def __init__(self, choices):
+ self._choices = choices
def __eq__(self, other):
if other is None: return False
- if not isinstance(other, Alternatives): return False
- return self._nbalt == other._nbalt
+ if not isinstance(other, Alternative): return False
+ return self._choices == other._choices
+
+ def __str__(self):
+ return "Alternatives(%s)" % self._choices
def NoProblem():
"""the empty problem, used by clone()"""
@@ -76,22 +80,22 @@
def __init__(self, problem, parent=None):
self.id = ComputationSpace._id_count
ComputationSpace._id_count += 1
+ self.status = Unknown
# consistency-preserving stuff
self.in_transaction = False
self.bind_lock = RLock()
self.var_lock = RLock()
self.distributor = DefaultDistributor(self)
- self.status = Unknown
+ # parent/children
self.parent = parent
self.children = set()
- self.changelog = []
- self.domain_history = []
# mapping from domains to variables
self.doms = {}
# set of all constraints
self.constraints = set()
# mapping from vars to constraints
self.var_const_map = {}
+ self.event_set = set()
if parent is None:
self.vars = set()
@@ -100,8 +104,7 @@
self.root = self.var('__root__')
# set up the problem
self.bind(self.root, problem(self))
- self.changelog = [var for var in self.vars]
- # check satisfiability of the space
+ self._notify(event.NewSpace)
self._init_choose_commit()
self.distributor.start()
else:
@@ -115,6 +118,7 @@
self.copy_constraints(parent)
# ...
self.status = Unknown
+ self._notify(event.Clone)
self.distributor = parent.distributor.__class__(self)
self._init_choose_commit()
@@ -143,87 +147,56 @@
self.parent = None
self.children = None
self.CHOOSE.bind(0)
+ self.STABLE.bind(0)
-## def __eq__(self, spc):
-## """space equality defined as :
-## * same set of vars with a domain
-## * same name set
-## * equal domains
-## * same set of constraints
-## * different propagators of the same type"""
-## if id(self) == id(spc): return True
-## r1 = self.vars == spc.vars
-## r2 = self.names == spc.names
-## r3 = self.constraints == spc.constraints
-## r4 = self.distributor != spc.distributor
-## r5 = self.root == spc.root
-## if not r1 and r2 and r3 and r4 and r5:
-## return False
-## # now the domains
-## it1 = [item for item in self.doms.items()
-## if item[1] != NoDom]
-## it2 = [item for item in spc.doms.items()
-## if item[1] != NoDom]
-## it1.sort()
-## it2.sort()
-## for (v1, d1), (v2, d2) in zip (it1, it2):
-## ## if d1 != d2:
-## ## print v1, d1
-## ## print v2, d2
-## ## else:
-## ## print "%s.dom == %s.dom" % (v1, v2)
-## if v1 != v2: return False
-## if d1 != d2: return False
-## if id(v1) != id(v2): return False
-## if id(d1) == id(d2): return False
-## return True
+ def __eq__(self, spc):
+ """space equality defined as :
+ * identity, or
+ * same set of vars with a domain, and
+ * same name set, and
+ * equal domains, and
+ * same set of constraints, and
+ * different propagators of the same type"""
+ if not isinstance(spc, ComputationSpace): return False
+ if id(self) == id(spc): return True
+ r1 = self.vars == spc.vars
+ r2 = self.names == spc.names
+ r3 = self.constraints != spc.constraints
+ r4 = self.distributor != spc.distributor
+ r5 = self.root == spc.root
+ if not r1 and r2 and r3 and r4 and r5:
+ return False
+ # now the domains
+ it1 = [item for item in self.doms.items()
+ if item[1] != NoDom]
+ it2 = [item for item in spc.doms.items()
+ if item[1] != NoDom]
+ it1.sort()
+ it2.sort()
+ for (v1, d1), (v2, d2) in zip (it1, it2):
+ if v1 != v2: return False
+ if d1 != d2: return False
+ if id(v1) != id(v2): return False
+ if id(d1) == id(d2): return False
+ return True
def __ne__(self, other):
return not self == other
def pretty_doms(self):
print "(-- domains --"
- for v, d in self.doms.items():
+ doms = self.doms.items()
+ doms.sort()
+ for v, d in doms:
if d != NoDom:
- print ' ', str(d)
+ print ' ', str(d.get_values())
print " -- domains --)"
- def backup_domains(self):
- print "-- backup of domains (%s) --" % self.id
- doms = []
- for v, d in self.doms.items():
- if d != NoDom:
- doms.append((v, len(d)))
- doms.sort()
- print " (", [elt[1] for elt in doms], ")"
- self.domain_history.append(doms)
-
- def print_quick_diff(self):
- ldh = len(self.domain_history)
- if ldh > 0:
- print "history size (%s) : %s" % (self.id, ldh)
- last = self.domain_history[-1]
- else:
- curr = [(item[0], len(item[1].get_values()))
- for item in self.doms.items()
- if item[1] != NoDom]
- curr.sort()
- print "(diff -- v : d 0 (%s)" % self.id
- for l in curr:
- print ' '*6, '%s : %2d' % (l[0], l[1])
- print " --)"
- return
- curr = [(item[0], len(item[1].get_values()))
- for item in self.doms.items()
- if item[1] != NoDom]
- curr.sort()
- print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, self.id)
- for l1, l2 in zip(last, curr):
- print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1])
- print " --)"
-
+
#-- Computation Space -----------------------------------------
+ #-- space helpers -----------------------------------------
+
def _make_choice_var(self):
ComputationSpace._nb_choices += 1
ch_var = self.var('__choice__'+str(self._nb_choices))
@@ -236,43 +209,37 @@
def _process(self):
"""wraps the propagator"""
- #XXX: shouldn't only the distributor call it ?
- #XXX: this is all sequential, but in the future
- # when propagators live in threads and are
- # awaken by events on variables, this might
- # completely disappear
- try:
- self.satisfy_all()
- except ConsistencyFailure:
- self.status = Failed
- else:
- if not self._distributable():
- self.status = Succeeded
+ if len(self.event_set):
+ try:
+ self.satisfy_all()
+ except ConsistencyFailure:
+ self.status = Failed
+ else:
+ if not self._distributable():
+ self.status = Succeeded
def _distributable(self):
- try:
- if self.status not in (Failed, Succeeded):
- for var in self.root.val:
- if self.dom(var).size() > 1 :
- return True
- return False
- finally: pass
- # in The Book : "the space has one thread that is
- # suspended on a choice point with two or more alternatives.
- # A space can have at most one choice point; attempting to
- # create another gives an error."
+ if self.status not in (Failed, Succeeded):
+ for var in self.root.val:
+ if self.dom(var).size() > 1 :
+ return True
+ return False
def top_level(self):
return self.parent is None
+ def _notify(self, event):
+ self.event_set.add(event)
+
+ #-- space official API ------------------------------------
+
def ask(self):
- #print "SPACE Ask() checks stability ..."
- self.STABLE.get() # that's real stability
- #print "SPACE is stable, resuming Ask()"
+ self.STABLE.get()
status = self.status in (Failed, Succeeded)
if status: return self.status
if self._distributable():
- return Alternatives(self.distributor.nb_subdomains())
+ return Alternative(self.distributor.nb_subdomains())
+
# should be unreachable
print "DOMS", [(var, self.doms[var])
for var in self.vars
@@ -280,14 +247,12 @@
raise NotImplementedError
def clone(self):
- # cloning should happen after the space is stable
+ # did you ask before ... ?
assert self.STABLE.is_bound()
spc = ComputationSpace(NoProblem, parent=self)
print "-- cloning %s to %s --" % (self.id, spc.id)
- spc.domain_history = []
- for domset in self.domain_history:
- spc.domain_history.append(domset)
- assert spc._distributable()
+ self._notify(event.Clone)
+ spc._process()
spc.distributor.start()
return spc
@@ -304,13 +269,11 @@
some_number must satisfy 1=<I=<N where N is the first arg
of the Choose call.
"""
- #print "SPACE commited to", choice
- # block future calls to Ask until the distributor
- # binds STABLE
+ # did you ask before ... ?
+ assert self.STABLE.is_bound()
old_stable_var = self.STABLE
self.STABLE = self._make_stable_var()
self._del_var(old_stable_var)
- #print "SPACE binds CHOOSE to", choice
self.bind(self.CHOOSE, choice)
def choose(self, nb_choices):
@@ -529,13 +492,25 @@
def add_distributed(self, var):
self.changelog.append(var)
+ def _init_constraint_queue(self):
+ cqueue = []
+ init_const_set = set()
+ if event.Clone in self.event_set:
+ init_const_set = self.constraints
+ elif event.NewSpace in self.event_set:
+ init_const_set = self.constraints
+ else:
+ for ev in self.event_set:
+ if isinstance(event, event.Revise):
+ init_const_set.add(self.var_const_map[ev.var])
+
+ cqueue = [(const.estimate_cost(), const)
+ for const in init_const_set]
+ return cqueue
+
def satisfy_all(self):
"""really PROPAGATE"""
- self.backup_domains()
- changelog = []
- changed = self.changelog[-1]
- const_q = [(const.estimate_cost(), const)
- for const in self.var_const_map[changed]]
+ const_q = self._init_constraint_queue()
assert const_q != []
const_q.sort()
affected_constraints = set()
@@ -557,7 +532,6 @@
if dependant_const is not const:
affected_constraints.add(dependant_const)
dom.reset_flags()
- changelog.append(var)
if entailed:
# we should also remove the constraint from
# the set of satifiable constraints
@@ -805,4 +779,44 @@
def _both_are_bound(v1, v2):
return v1._is_bound() and v2._is_bound()
-
+def diff_list(l1, l2):
+ diff = {}
+ idx = 0
+ for e1, e2 in zip(l1, l2):
+ if e1 != e2: diff[idx] = (e1, e2)
+ idx += 1
+ return diff
+
+def backup_domains(space):
+ print "-- backup of domains (%s) --" % space.id
+ doms = []
+ for v, d in space.doms.items():
+ if d != NoDom:
+ doms.append((v, len(d)))
+ doms.sort()
+ print " (", [elt[1] for elt in doms], ")"
+ return doms
+
+def print_quick_diff(space, domain_history):
+ ldh = len(domain_history)
+ if ldh > 0:
+ print "history size (%s) : %s" % (space.id, ldh)
+ last = domain_history[-1]
+ else:
+ curr = [(item[0], len(item[1].get_values()))
+ for item in space.doms.items()
+ if item[1] != NoDom]
+ curr.sort()
+ print "(diff -- v : d 0 (%s)" % space.id
+ for l in curr:
+ print ' '*6, '%s : %2d' % (l[0], l[1])
+ print " --)"
+ return
+ curr = [(item[0], len(item[1].get_values()))
+ for item in space.doms.items()
+ if item[1] != NoDom]
+ curr.sort()
+ print "(diff -- v : d%2d | d%2d (%s)" % (ldh, ldh+1, space.id)
+ for l1, l2 in zip(last, curr):
+ print ' '*6, '%s : %2d | %2d ' % (l1[0], l1[1], l2[1])
+ print " --)"
Modified: pypy/dist/pypy/lib/logic/computation_space/distributor.py
==============================================================================
--- pypy/dist/pypy/lib/logic/computation_space/distributor.py (original)
+++ pypy/dist/pypy/lib/logic/computation_space/distributor.py Wed Mar 1 15:39:53 2006
@@ -1,6 +1,7 @@
import math, random
from threading import Thread
from state import Succeeded, Distributable, Failed, Forsaken
+from event import Revise
def arrange_domains(cs, variables):
"""build a data structure from var to dom
@@ -143,11 +144,11 @@
#XXX: are the domains properly set up ?
#self.cs._process() # propagate first
#better let clone() do this call
- self.cs.STABLE.bind(True)
while self.cs._distributable():
if self.cs.status == Forsaken:
print "-- distributor (%s) ready for GC --" % self.cs.id
break
+ self.cs.STABLE.bind(True)
choice = self.cs.choose(self.nb_subdomains())
print "-- distribution & propagation (%s) --" % self.cs.id
self.distribute(choice-1)
@@ -171,7 +172,7 @@
int(math.floor((choice + 1) * nb_elts)))
self.cs.dom(variable).remove_values(values[:start])
self.cs.dom(variable).remove_values(values[end:])
- self.cs.add_distributed(variable)
+ self.cs._notify(Revise(variable))
class DichotomyDistributor(SplitDistributor):
Modified: pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py
==============================================================================
--- pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py (original)
+++ pypy/dist/pypy/lib/logic/computation_space/test_computationspace.py Wed Mar 1 15:39:53 2006
@@ -495,11 +495,11 @@
def test_ask_alternatives(self):
spc = newspace(problems.satisfiable_problem)
- assert spc.ask() == space.Alternatives(2)
+ assert spc.ask() == space.Alternative(2)
## def test_clone_and_process(self):
## spc = newspace(problems.satisfiable_problem)
-## assert spc.ask() == space.Alternatives(2)
+## assert spc.ask() == space.Alternative(2)
## new_spc = spc.clone()
## #assert spc == new_spc
## assert new_spc.parent == spc
@@ -509,7 +509,7 @@
## new_spc.add_constraint([z, y], 'z == y')
## new_spc.add_constraint([y], 'y < 2')
## new_spc._process()
-## assert spc.ask() == space.Alternatives(2)
+## assert spc.ask() == space.Alternative(2)
## assert new_spc.ask() == space.Succeeded
def test_clone(self):
@@ -524,23 +524,23 @@
def eager_and(t1, t2):
return t1 and t2
- while not (eager_and(s1.ask() == space.Succeeded,
- s2.ask() == space.Succeeded)):
- print "S1 diff : "
- s1.print_quick_diff()
- print "S2 diff : "
- s2.print_quick_diff()
+ passes = 0
+
+ while not (eager_and(s2.ask() == space.Succeeded,
+ s1.ask() == space.Succeeded)):
+ print "pass n°", passes
+ print "S1", s1.pretty_doms()
+ print "S2", s2.pretty_doms()
+ passes += 1
#assert s1 == s2
- #assert s2 == s1
- assert len(s1.domain_history) == len(s2.domain_history)
temp = s2.clone()
- assert temp.parent == s2
+ temp.ask()
+ assert temp.parent is s2
assert temp in s2.children
s2 = temp
s1.commit(1)
s2.commit(1)
- print "FOoooo..."
def test_quickdiff(self):
s = newspace(problems.conference_scheduling)
@@ -556,10 +556,10 @@
space.add_constraint([y], 'y < 2')
spc = newspace(problems.satisfiable_problem)
- assert spc.ask() == space.Alternatives(2)
+ assert spc.ask() == space.Alternative(2)
new_spc = spc.clone()
new_spc.inject(more_constraints)
- assert spc.ask() == space.Alternatives(2)
+ assert spc.ask() == space.Alternative(2)
assert new_spc.ask() == space.Succeeded
def test_merge(self):
More information about the Pypy-commit
mailing list