Replaced references to depricated Set and ImmutableSet classes with set and frozenset types
This commit is contained in:
parent
74386c1710
commit
fac2609def
|
@ -13,16 +13,22 @@ from graph import Graph
|
|||
from method import Method, MethodGraph
|
||||
from diagnostic import diag_print
|
||||
from notify import Notifier
|
||||
from sets import Set, ImmutableSet
|
||||
from multimethod import MultiVariable, MultiMethod
|
||||
from cluster import *
|
||||
from configuration import Configuration
|
||||
from gmatch import gmatch
|
||||
from method import OrMethod
|
||||
|
||||
# Basic methods
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# ----------Method classes used by ClusterSolver -------------
|
||||
# -----------------------------------------------------------
|
||||
|
||||
class ClusterMethod(MultiMethod):
|
||||
"""A derive is a method such that a single ouput cluster is a
|
||||
subconsraint of a single input cluster."""
|
||||
"""A method that determines a single output cluster from a ser of input clusters.
|
||||
Subclasses should ensure that the output cluster satisfies all the constraints
|
||||
in the input clusters.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.consistent = None
|
||||
|
@ -144,33 +150,89 @@ class SelectionMethod(MultiMethod):
|
|||
def __str__(self):
|
||||
return "SelectionMethod#%d(%s & %s ->%s)"%(id(self),str(self._inputs[0]), str(self._constraints), str(self._outputs[0]))
|
||||
|
||||
# --------------------------------------
|
||||
# helper functions for pattern matching
|
||||
# --------------------------------------
|
||||
|
||||
def pattern2graph(pattern):
|
||||
"""convert pattern to pattern graph"""
|
||||
pgraph = Graph()
|
||||
pgraph.add_vertex("point")
|
||||
pgraph.add_vertex("distance")
|
||||
pgraph.add_vertex("rigid")
|
||||
pgraph.add_vertex("balloon")
|
||||
pgraph.add_vertex("hedgehog")
|
||||
for clpattern in pattern:
|
||||
(pattype, patname, patvars) = clpattern
|
||||
pgraph.add_edge(pattype, patname)
|
||||
for var in patvars:
|
||||
pgraph.add_edge(patname, var)
|
||||
if pattype == "hedgehog":
|
||||
pgraph.add_edge("cvar"+"#"+patname, patvars[0])
|
||||
pgraph.add_edge(patname, "cvar"+"#"+patname)
|
||||
#diag_print("pattern graph:"+str(pgraph),"match");
|
||||
return pgraph
|
||||
|
||||
def reference2graph(nlet):
|
||||
"""convert nlet to reference graph"""
|
||||
rgraph = Graph()
|
||||
rgraph.add_vertex("point")
|
||||
rgraph.add_vertex("distance")
|
||||
rgraph.add_vertex("rigid")
|
||||
rgraph.add_vertex("balloon")
|
||||
rgraph.add_vertex("hedgehog")
|
||||
for cluster in nlet:
|
||||
for var in cluster.vars:
|
||||
rgraph.add_edge(cluster, var)
|
||||
if isinstance(cluster, Rigid):
|
||||
rgraph.add_edge("rigid", cluster)
|
||||
if len(cluster.vars) == 1:
|
||||
rgraph.add_edge("point", cluster)
|
||||
elif len(cluster.vars) == 2:
|
||||
rgraph.add_edge("distance", cluster)
|
||||
if isinstance(cluster, Balloon):
|
||||
rgraph.add_edge("balloon", cluster)
|
||||
if isinstance(cluster, Hedgehog):
|
||||
rgraph.add_edge("hedgehog", cluster)
|
||||
rgraph.add_edge("cvar"+"#"+str(id(cluster)), cluster.cvar)
|
||||
rgraph.add_edge(cluster, "cvar"+"#"+str(id(cluster)))
|
||||
#diag_print("reference graph:"+str(rgraph),"match");
|
||||
return rgraph
|
||||
|
||||
def rootname(cluster):
|
||||
return "root#"+str(id(cluster))
|
||||
|
||||
|
||||
def is_information_increasing(method):
|
||||
infinc = True
|
||||
connected = Set()
|
||||
output = method.outputs()[0]
|
||||
for cluster in method.input_clusters():
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(output):
|
||||
infinc = False
|
||||
break
|
||||
return infinc
|
||||
|
||||
# ---------- main class --------------
|
||||
# --------------------------------------------------
|
||||
# ---------- ClusterSolver main class --------------
|
||||
# --------------------------------------------------
|
||||
|
||||
class ClusterSolver(Notifier):
|
||||
"""Constraints are Clusers: Rigids, Hedgehogs and Balloons.
|
||||
After adding each cluster, the solver tries to merge
|
||||
clusters, adding new clusters and methods between clusters.
|
||||
"""
|
||||
Finds a generic solution for problems formulated by Clusters.
|
||||
|
||||
Cluster are added and removed using the add and remove methods.
|
||||
After adding each Cluster, the solver tries to merge it with
|
||||
others, resulting in new Clusters.
|
||||
|
||||
The generic solution is a directed acyclic graph of Clusters and Methods.
|
||||
Particilar problems and solutions are represented by a Configuration
|
||||
for each cluster.
|
||||
|
||||
For each Cluster a set of Configurations can be set using the
|
||||
set method. Configurations are propagated via Methods and can
|
||||
be retrieved with the get method.
|
||||
"""
|
||||
|
||||
# ------- PUBLIC METHODS --------
|
||||
|
||||
def __init__(self, dimension):
|
||||
def __init__(self, dimension, methodclasses):
|
||||
"""Create a new empty solver"""
|
||||
# init superclasses
|
||||
Notifier.__init__(self)
|
||||
# store arguments
|
||||
self.dimension = dimension
|
||||
self.methodclasses = methodclasses
|
||||
# init instance vars
|
||||
self._graph = Graph()
|
||||
self._graph.add_vertex("_root")
|
||||
|
@ -190,6 +252,9 @@ class ClusterSolver(Notifier):
|
|||
self._mg.set(self._prototype_selection_var, True)
|
||||
# store map of selection_constraints to SelectionMethod (or None)
|
||||
self._selection_method = {}
|
||||
# store root cluster (will be assigned when first cluster added)
|
||||
self.rootcluster = None
|
||||
|
||||
|
||||
def variables(self):
|
||||
"""get list of variables"""
|
||||
|
@ -251,14 +316,28 @@ class ClusterSolver(Notifier):
|
|||
"""Return a set of configurations associated with a cluster"""
|
||||
return self._mg.get(cluster)
|
||||
|
||||
def set_root(self, rigid):
|
||||
"""Make given rigid cluster the root cluster
|
||||
def set_root(self, cluster):
|
||||
"""Set root cluster, used for positionig and orienting the solutions"""
|
||||
diag_print("set root "+str(self.rootcluster), "clsolver")
|
||||
if self.rootcluster != None:
|
||||
oldrootvar = rootname(self.rootcluster)
|
||||
self._mg.set(oldrootvar, False)
|
||||
newrootvar = rootname(cluster)
|
||||
self._mg.set(newrootvar, True)
|
||||
self.rootcluster = cluster
|
||||
|
||||
arguments:
|
||||
cluster: A Rigid
|
||||
"""
|
||||
self._graph.rem_vertex("_root")
|
||||
self._graph.add_edge("_root", rigid)
|
||||
def get_root(self):
|
||||
"""returns current root cluster or None"""
|
||||
return self.rootcluster
|
||||
|
||||
##def set_root(self, rigid):
|
||||
## """Make given rigid cluster the root cluster
|
||||
##
|
||||
## arguments:
|
||||
## cluster: A Rigid
|
||||
## """
|
||||
## self._graph.rem_vertex("_root")
|
||||
## self._graph.add_edge("_root", rigid)
|
||||
|
||||
def find_dependend(self, object):
|
||||
"""Return a list of objects that depend on given object directly."""
|
||||
|
@ -354,6 +433,7 @@ class ClusterSolver(Notifier):
|
|||
self._add_to_group("_variables", var)
|
||||
|
||||
def _add_cluster(self, cluster):
|
||||
# add in appriate way for type
|
||||
if isinstance(cluster, Rigid):
|
||||
self._add_rigid(cluster)
|
||||
elif isinstance(cluster, Hedgehog):
|
||||
|
@ -362,6 +442,16 @@ class ClusterSolver(Notifier):
|
|||
self._add_balloon(cluster)
|
||||
else:
|
||||
raise StandardError, "unsupported type", type(cluster)
|
||||
# add root-variable if needed with default value False
|
||||
root = rootname(cluster)
|
||||
if not self._mg.contains(root):
|
||||
self._mg.add_variable(root, False)
|
||||
self._mg.set(root, False)
|
||||
# add root-variable to dependency graph
|
||||
self._add_dependency(cluster, root)
|
||||
# if there is no root cluster, this one will be it
|
||||
if self.get_root() == None:
|
||||
self.set_root(cluster)
|
||||
|
||||
def _add_rigid(self, newcluster):
|
||||
"""add a rigid cluster if not already in system"""
|
||||
|
@ -374,9 +464,6 @@ class ClusterSolver(Notifier):
|
|||
for var in newcluster.vars:
|
||||
self._add_variable(var)
|
||||
self._add_dependency(var, newcluster)
|
||||
# if there is no root cluster, this one will be it
|
||||
if len(self._graph.outgoing_vertices("_root")) == 0:
|
||||
self._graph.add_edge("_root", newcluster)
|
||||
# add to top level
|
||||
self._add_top_level(newcluster)
|
||||
# add to methodgraph
|
||||
|
@ -472,9 +559,9 @@ class ClusterSolver(Notifier):
|
|||
def _add_prototype_selector(self, merge):
|
||||
incluster = merge.outputs()[0]
|
||||
constraints = merge.prototype_constraints()
|
||||
vars = Set()
|
||||
vars = set()
|
||||
for con in constraints:
|
||||
vars.union_update(con.variables())
|
||||
vars.update(con.variables())
|
||||
selclusters = []
|
||||
for var in vars:
|
||||
clusters = self._graph.outgoing_vertices(var)
|
||||
|
@ -562,14 +649,140 @@ class ClusterSolver(Notifier):
|
|||
#end def
|
||||
|
||||
def _search(self, newcluster):
|
||||
raise StandardError, "Not implemented. ClusterSolver is an abstract class, please use ClusterSolver2D or ClusterSolver3D"
|
||||
diag_print("search from: "+str(newcluster),"clsolver")
|
||||
# find all toplevel clusters connected to newcluster via one or more variables
|
||||
connected = set()
|
||||
for var in newcluster.vars:
|
||||
dependend = self.find_dependend(var)
|
||||
dependend = filter(lambda x: self.is_top_level(x), dependend)
|
||||
connected.update(dependend)
|
||||
diag_print("search: connected clusters="+str(connected),"clsolver")
|
||||
# try applying methods
|
||||
if self._try_method(connected):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _try_method(self, nlet):
|
||||
"""finds a possible rewrite rule applications on given set of clusters, applies it
|
||||
and returns True iff successfull
|
||||
"""
|
||||
refgraph = reference2graph(nlet)
|
||||
for methodclass in self.methodclasses:
|
||||
matches = gmatch(methodclass.patterngraph, refgraph)
|
||||
if len(matches) > 0:
|
||||
diag_print("number of matches = "+str(len(matches)), "clsolver")
|
||||
for s in matches:
|
||||
# diag_print("try match: "+str(s),"clsolver")
|
||||
method = apply(methodclass, [s])
|
||||
succes = self._add_method_complete(method)
|
||||
if succes:
|
||||
#raw_input()
|
||||
#print "press key"
|
||||
return True
|
||||
# end for match
|
||||
# end for method
|
||||
return False
|
||||
|
||||
|
||||
def _add_method_complete(self, merge):
|
||||
# diag_print("add_method_complete "+str(merge), "clsolver")
|
||||
# check that method has one output
|
||||
if len(merge.outputs()) != 1:
|
||||
raise StandardError, "merge number of outputs != 1"
|
||||
output = merge.outputs()[0]
|
||||
|
||||
# check that the method is information increasing (infinc)
|
||||
infinc = True
|
||||
connected = set()
|
||||
for var in output.vars:
|
||||
dependend = self.find_dependend(var)
|
||||
dependend = filter(lambda x: self.is_top_level(x), dependend)
|
||||
connected.update(dependend)
|
||||
#for cluster in merge.input_clusters():
|
||||
# if cluster in connected:
|
||||
# connected.remove(cluster)
|
||||
|
||||
# NOTE 07-11-2007 (while writing the paper): this implementation of information increasing may not be correct. We may need to check that the total sum of the information in the overlapping clusters is equal to the information in the output.
|
||||
|
||||
for cluster in connected:
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(output):
|
||||
infinc = False
|
||||
break
|
||||
diag_print("information increasing:"+str(infinc),"clsolver")
|
||||
|
||||
# check if method reduces number of clusters (reduc)
|
||||
nremove = 0
|
||||
for cluster in merge.input_clusters():
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(cluster):
|
||||
# will be removed from toplevel
|
||||
nremove += 1
|
||||
reduc = (nremove > 1)
|
||||
diag_print("reduce # clusters:"+str(reduc),"clsolver")
|
||||
|
||||
# check if the method is redundant
|
||||
if not infinc and not reduc:
|
||||
diag_print("method is redundant","clsolver")
|
||||
return False
|
||||
|
||||
# check consistency and local/global overconstrained
|
||||
consistent = True
|
||||
local_oc = False
|
||||
for i1 in range(0, len(merge.input_clusters())):
|
||||
for i2 in range(i1+1, len(merge.input_clusters())):
|
||||
c1 = merge.input_clusters()[i1]
|
||||
c2 = merge.input_clusters()[i2]
|
||||
if num_constraints(c1.intersection(c2)) != 0:
|
||||
local_oc = True
|
||||
consistent = consistent and self._is_consistent_pair(c1, c2)
|
||||
merge.consistent = consistent
|
||||
merge.overconstrained = local_oc
|
||||
# global overconstrained? (store in output cluster)
|
||||
overconstrained = not consistent
|
||||
for cluster in merge.input_clusters():
|
||||
overconstrained = overconstrained or cluster.overconstrained
|
||||
output.overconstrained = overconstrained
|
||||
# add to graph
|
||||
self._add_cluster(output)
|
||||
self._add_method(merge)
|
||||
# remove input clusters from top_level
|
||||
merge.restore_toplevel = [] # make restore list in method
|
||||
for cluster in merge.input_clusters():
|
||||
# do not remove rigids from toplevel if method does not consider root
|
||||
if isinstance(cluster, Rigid):
|
||||
if hasattr(merge,"noremove") and merge.noremove == True:
|
||||
continue
|
||||
# remove input clusters when all its constraints are in output cluster
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(cluster):
|
||||
diag_print("remove from top-level: "+str(cluster),"clsolver")
|
||||
self._rem_top_level(cluster)
|
||||
merge.restore_toplevel.append(cluster)
|
||||
else:
|
||||
diag_print("keep top-level: "+str(cluster),"clsolver")
|
||||
# add method to determine root-variable
|
||||
self._add_root_method(merge.input_clusters(),merge.outputs()[0])
|
||||
# add solution selection methods
|
||||
output2 = self._add_prototype_selector(merge)
|
||||
output3 = self._add_solution_selector(output2)
|
||||
return True
|
||||
|
||||
def _add_root_method(self,inclusters,outcluster):
|
||||
inroots = []
|
||||
for cluster in inclusters:
|
||||
inroots.append(rootname(cluster))
|
||||
outroot = rootname(outcluster)
|
||||
method = OrMethod(inroots, outroot)
|
||||
# add method
|
||||
self._add_method(method)
|
||||
# make sure its deleted when cluster is deleted
|
||||
self._add_dependency(outcluster, method)
|
||||
|
||||
|
||||
# -- removing objects
|
||||
|
||||
def _remove(self, object):
|
||||
# find all indirectly dependend objects
|
||||
todelete = [object]+self._find_descendend(object)
|
||||
torestore = Set()
|
||||
torestore = set()
|
||||
# remove all objects
|
||||
for item in todelete:
|
||||
# if merge removed items from toplevel then add them back to top level
|
||||
|
@ -605,38 +818,36 @@ class ClusterSolver(Notifier):
|
|||
self._process_new()
|
||||
|
||||
|
||||
# --- root selection
|
||||
|
||||
def _contains_root(self, input_cluster):
|
||||
"""returns True iff input_cluster is root cluster or was determined by
|
||||
merging with the root cluster."""
|
||||
|
||||
# start from root cluster. Follow merges upwards until:
|
||||
# - input cluster found -> True
|
||||
# - no more merges -> False
|
||||
|
||||
if len(self._graph.outgoing_vertices("_root")) > 1:
|
||||
raise StandardError, "more than one root cluster"
|
||||
if len(self._graph.outgoing_vertices("_root")) == 1:
|
||||
cluster = self._graph.outgoing_vertices("_root")[0]
|
||||
else:
|
||||
cluster = None
|
||||
while (cluster != None):
|
||||
if cluster is input_cluster:
|
||||
return True
|
||||
fr = self._graph.outgoing_vertices(cluster)
|
||||
me = filter(lambda x: isinstance(x, Merge), fr)
|
||||
me = filter(lambda x: cluster in x.outputs(), me)
|
||||
if len(me) > 1:
|
||||
raise StandardError, "root cluster merged more than once"
|
||||
elif len(me) == 0:
|
||||
cluster = None
|
||||
elif len(me[0].outputs()) != 1:
|
||||
raise StandardError, "a merge with number of outputs != 1"
|
||||
else:
|
||||
cluster = me[0].outputs()[0]
|
||||
#while
|
||||
return False
|
||||
##def _contains_root(self, input_cluster):
|
||||
## """returns True iff input_cluster is root cluster or was determined by
|
||||
## merging with the root cluster."""
|
||||
##
|
||||
## # start from root cluster. Follow merges upwards until:
|
||||
## # - input cluster found -> True
|
||||
## # - no more merges -> False
|
||||
##
|
||||
## if len(self._graph.outgoing_vertices("_root")) > 1:
|
||||
## raise StandardError, "more than one root cluster"
|
||||
## if len(self._graph.outgoing_vertices("_root")) == 1:
|
||||
## cluster = self._graph.outgoing_vertices("_root")[0]
|
||||
## else:
|
||||
## cluster = None
|
||||
## while (cluster != None):
|
||||
## if cluster is input_cluster:
|
||||
## return True
|
||||
## fr = self._graph.outgoing_vertices(cluster)
|
||||
## me = filter(lambda x: isinstance(x, Merge), fr)
|
||||
## me = filter(lambda x: cluster in x.outputs(), me)
|
||||
## if len(me) > 1:
|
||||
## raise StandardError, "root cluster merged more than once"
|
||||
## elif len(me) == 0:
|
||||
## cluster = None
|
||||
## elif len(me[0].outputs()) != 1:
|
||||
## raise StandardError, "a merge with number of outputs != 1"
|
||||
## else:
|
||||
## cluster = me[0].outputs()[0]
|
||||
## #while
|
||||
## return False
|
||||
#def
|
||||
|
||||
# ---- consistency
|
||||
|
@ -848,7 +1059,7 @@ class ClusterSolver(Notifier):
|
|||
## dependend.append(obj)
|
||||
## candidates = filter(lambda x: self._contains_distance(x, distance), dependend)
|
||||
## # determine sources, i.e. clusters created from clusters that do not contain the distance
|
||||
## sources = Set()
|
||||
## sources = set()
|
||||
## for c1 in candidates:
|
||||
## methods = filter(lambda v: isinstance(v, Method), self._graph.ingoing_vertices(c1))
|
||||
## if len(methods) == 0:
|
||||
|
@ -868,7 +1079,7 @@ class ClusterSolver(Notifier):
|
|||
## for source in sources:
|
||||
## diag_print(str(source), "clsolver")
|
||||
## # filter sources for dependencies
|
||||
## #unfiltered = Set(sources)
|
||||
## #unfiltered = set(sources)
|
||||
## #for s1 in unfiltered:
|
||||
## # if s1 not in sources: continue
|
||||
## # descendants = self._find_descendants(s1)
|
||||
|
@ -889,7 +1100,7 @@ class ClusterSolver(Notifier):
|
|||
## dependend.append(obj)
|
||||
## candidates = filter(lambda x: self._contains_angle(x, angle), dependend)
|
||||
## # determine sources, i.e. clusters created from clusters that do not contain the angle
|
||||
## sources = Set()
|
||||
## sources = set()
|
||||
## for c1 in candidates:
|
||||
## methods = filter(lambda v: isinstance(v, Method), self._graph.ingoing_vertices(c1))
|
||||
## if len(methods) == 0:
|
||||
|
@ -912,8 +1123,8 @@ class ClusterSolver(Notifier):
|
|||
|
||||
##def _roots(self,object):
|
||||
## front = [object]
|
||||
## result = Set()
|
||||
## done = Set()
|
||||
## result = set()
|
||||
## done = set()
|
||||
## while len(front) > 0:
|
||||
## x = front.pop()
|
||||
## if x not in done:
|
||||
|
@ -930,14 +1141,14 @@ class ClusterSolver(Notifier):
|
|||
|
||||
##def _all_sources_constraint_in_cluster(self, constraint, cluster):
|
||||
## if not self._contains_constraint(cluster, constraint):
|
||||
## return Set()
|
||||
## return set()
|
||||
## elif self._is_atomic(cluster):
|
||||
## return Set([cluster])
|
||||
## return set([cluster])
|
||||
## else:
|
||||
## method = self._determining_method(cluster)
|
||||
## sources = Set()
|
||||
## sources = set()
|
||||
## for inp in method.input_clusters():
|
||||
## sources.union_update(self._all_sources_constraint_in_cluster(constraint, inp))
|
||||
## sources.update(self._all_sources_constraint_in_cluster(constraint, inp))
|
||||
## return sources
|
||||
|
||||
# class ClusterSolver
|
||||
|
|
|
@ -1,251 +1,21 @@
|
|||
"""A generic 3D geometric constraint solver"""
|
||||
|
||||
from clsolver import *
|
||||
from sets import Set
|
||||
from diagnostic import diag_print, diag_select
|
||||
from selconstr import *
|
||||
from intersections import *
|
||||
from configuration import Configuration
|
||||
from cluster import *
|
||||
from map import Map
|
||||
from gmatch import gmatch
|
||||
from method import OrMethod
|
||||
|
||||
def pattern2graph(pattern):
|
||||
"""convert pattern to pattern graph"""
|
||||
pgraph = Graph()
|
||||
pgraph.add_vertex("point")
|
||||
pgraph.add_vertex("distance")
|
||||
pgraph.add_vertex("rigid")
|
||||
pgraph.add_vertex("balloon")
|
||||
pgraph.add_vertex("hedgehog")
|
||||
for clpattern in pattern:
|
||||
(pattype, patname, patvars) = clpattern
|
||||
pgraph.add_edge(pattype, patname)
|
||||
for var in patvars:
|
||||
pgraph.add_edge(patname, var)
|
||||
if pattype == "hedgehog":
|
||||
pgraph.add_edge("cvar"+"#"+patname, patvars[0])
|
||||
pgraph.add_edge(patname, "cvar"+"#"+patname)
|
||||
#diag_print("pattern graph:"+str(pgraph),"match");
|
||||
return pgraph
|
||||
|
||||
def reference2graph(nlet):
|
||||
"""convert nlet to reference graph"""
|
||||
rgraph = Graph()
|
||||
rgraph.add_vertex("point")
|
||||
rgraph.add_vertex("distance")
|
||||
rgraph.add_vertex("rigid")
|
||||
rgraph.add_vertex("balloon")
|
||||
rgraph.add_vertex("hedgehog")
|
||||
for cluster in nlet:
|
||||
for var in cluster.vars:
|
||||
rgraph.add_edge(cluster, var)
|
||||
if isinstance(cluster, Rigid):
|
||||
rgraph.add_edge("rigid", cluster)
|
||||
if len(cluster.vars) == 1:
|
||||
rgraph.add_edge("point", cluster)
|
||||
elif len(cluster.vars) == 2:
|
||||
rgraph.add_edge("distance", cluster)
|
||||
if isinstance(cluster, Balloon):
|
||||
rgraph.add_edge("balloon", cluster)
|
||||
if isinstance(cluster, Hedgehog):
|
||||
rgraph.add_edge("hedgehog", cluster)
|
||||
rgraph.add_edge("cvar"+"#"+str(id(cluster)), cluster.cvar)
|
||||
rgraph.add_edge(cluster, "cvar"+"#"+str(id(cluster)))
|
||||
#diag_print("reference graph:"+str(rgraph),"match");
|
||||
return rgraph
|
||||
|
||||
def rootname(cluster):
|
||||
return "root#"+str(id(cluster))
|
||||
|
||||
|
||||
class ClusterSolver3D(ClusterSolver):
|
||||
"""A generic 3D geometric constraint solver.
|
||||
|
||||
Finds a generic solution for problems formulated by cluster-constraints.
|
||||
|
||||
Constraints are Clusers: Rigids, Hedgehogs and Balloons.
|
||||
Cluster are added and removed using the add and remove methods.
|
||||
After adding each Cluster, the solver tries to merge it with
|
||||
other clusters, resulting in new Clusters and Methods.
|
||||
|
||||
The generic solution is a directed acyclic graph of Clusters and Methods.
|
||||
Particilar problems and solutions are represented by a Configuration
|
||||
for each cluster.
|
||||
|
||||
For each Cluster a set of Configurations can be set using the
|
||||
set method. Configurations are propagated via Methods and can
|
||||
be retrieved with the get method.
|
||||
"""
|
||||
|
||||
# ------- PUBLIC METHODS --------
|
||||
"""A generic 3D geometric constraint solver. See ClusterSolver for details."""
|
||||
# ------- PUBLIC METHODS --------
|
||||
|
||||
def __init__(self):
|
||||
"""Instantiate a ClusterSolver3D"""
|
||||
ClusterSolver.__init__(self, 3)
|
||||
self.rootcluster = None
|
||||
ClusterSolver.__init__(self, 3, [MergePR, MergeDR, MergeRR, MergeSR, DeriveTTD, DeriveDDD, DeriveADD, DeriveDAD, DeriveAA])
|
||||
|
||||
# overriding ClusterSolver.set_root
|
||||
def set_root(self, cluster):
|
||||
"""Set root cluster, used for positionig and orienting the solutions"""
|
||||
diag_print("set root "+str(self.rootcluster), "clsolver3D")
|
||||
if self.rootcluster != None:
|
||||
oldrootvar = rootname(self.rootcluster)
|
||||
self._mg.set(oldrootvar, False)
|
||||
newrootvar = rootname(cluster)
|
||||
self._mg.set(newrootvar, True)
|
||||
self.rootcluster = cluster
|
||||
|
||||
|
||||
# ------------ INTERNALLY USED METHODS --------
|
||||
|
||||
|
||||
# --------------
|
||||
# search methods
|
||||
# --------------
|
||||
|
||||
def _search(self, newcluster):
|
||||
diag_print("search from: "+str(newcluster),"clsolver3D")
|
||||
# find all toplevel clusters connected to newcluster via one or more variables
|
||||
connected = Set()
|
||||
for var in newcluster.vars:
|
||||
dependend = self.find_dependend(var)
|
||||
dependend = filter(lambda x: self.is_top_level(x), dependend)
|
||||
connected.union_update(dependend)
|
||||
diag_print("search: connected clusters="+str(connected),"clsolver3D")
|
||||
# try applying methods
|
||||
if self._try_method(connected):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _try_method(self, nlet):
|
||||
"""finds a possible rewrite rule applications on given set of clusters, applies it
|
||||
and returns True iff successfull
|
||||
"""
|
||||
refgraph = reference2graph(nlet)
|
||||
for methodclass in [MergePR, MergeDR, MergeRR, MergeSR, DeriveTTD, DeriveDDD, DeriveADD, DeriveDAD, DeriveAA]:
|
||||
matches = gmatch(methodclass.patterngraph, refgraph)
|
||||
if len(matches) > 0:
|
||||
diag_print("number of matches = "+str(len(matches)), "clsolver3D")
|
||||
for s in matches:
|
||||
# diag_print("try match: "+str(s),"clsolver3D")
|
||||
method = apply(methodclass, [s])
|
||||
succes = self._add_method_complete(method)
|
||||
if succes:
|
||||
#raw_input()
|
||||
#print "press key"
|
||||
return True
|
||||
# end for match
|
||||
# end for method
|
||||
return False
|
||||
|
||||
|
||||
def _add_method_complete(self, merge):
|
||||
# diag_print("add_method_complete "+str(merge), "clsolver3D")
|
||||
# check that method has one output
|
||||
if len(merge.outputs()) != 1:
|
||||
raise StandardError, "merge number of outputs != 1"
|
||||
output = merge.outputs()[0]
|
||||
|
||||
# check that the method is information increasing (infinc)
|
||||
infinc = True
|
||||
connected = Set()
|
||||
for var in output.vars:
|
||||
dependend = self.find_dependend(var)
|
||||
dependend = filter(lambda x: self.is_top_level(x), dependend)
|
||||
connected.union_update(dependend)
|
||||
#for cluster in merge.input_clusters():
|
||||
# if cluster in connected:
|
||||
# connected.remove(cluster)
|
||||
|
||||
# NOTE 07-11-2007 (while writing the paper): this implementation of information increasing may not be correct. We may need to check that the total sum of the information in the overlapping clusters is equal to the information in the output.
|
||||
|
||||
for cluster in connected:
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(output):
|
||||
infinc = False
|
||||
break
|
||||
diag_print("information increasing:"+str(infinc),"clsolver3D")
|
||||
|
||||
# check if method reduces number of clusters (reduc)
|
||||
nremove = 0
|
||||
for cluster in merge.input_clusters():
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(cluster):
|
||||
# will be removed from toplevel
|
||||
nremove += 1
|
||||
reduc = (nremove > 1)
|
||||
diag_print("reduce # clusters:"+str(reduc),"clsolver3D")
|
||||
|
||||
# check if the method is redundant
|
||||
if not infinc and not reduc:
|
||||
diag_print("method is redundant","clsolver3D")
|
||||
return False
|
||||
|
||||
# check consistency and local/global overconstrained
|
||||
consistent = True
|
||||
local_oc = False
|
||||
for i1 in range(0, len(merge.input_clusters())):
|
||||
for i2 in range(i1+1, len(merge.input_clusters())):
|
||||
c1 = merge.input_clusters()[i1]
|
||||
c2 = merge.input_clusters()[i2]
|
||||
if num_constraints(c1.intersection(c2)) != 0:
|
||||
local_oc = True
|
||||
consistent = consistent and self._is_consistent_pair(c1, c2)
|
||||
merge.consistent = consistent
|
||||
merge.overconstrained = local_oc
|
||||
# global overconstrained? (store in output cluster)
|
||||
overconstrained = not consistent
|
||||
for cluster in merge.input_clusters():
|
||||
overconstrained = overconstrained or cluster.overconstrained
|
||||
output.overconstrained = overconstrained
|
||||
# add to graph
|
||||
self._add_cluster(output)
|
||||
self._add_method(merge)
|
||||
# remove input clusters from top_level
|
||||
merge.restore_toplevel = [] # make restore list in method
|
||||
for cluster in merge.input_clusters():
|
||||
# do not remove rigids from toplevel if method does not consider root
|
||||
if isinstance(cluster, Rigid):
|
||||
if hasattr(merge,"noremove") and merge.noremove == True:
|
||||
continue
|
||||
# remove input clusters when all its constraints are in output cluster
|
||||
if num_constraints(cluster.intersection(output)) >= num_constraints(cluster):
|
||||
diag_print("remove from top-level: "+str(cluster),"clsolver3D")
|
||||
self._rem_top_level(cluster)
|
||||
merge.restore_toplevel.append(cluster)
|
||||
else:
|
||||
diag_print("keep top-level: "+str(cluster),"clsolver3D")
|
||||
# add method to determine root-variable
|
||||
self._add_root_method(merge.input_clusters(),merge.outputs()[0])
|
||||
# add solution selection methods
|
||||
output2 = self._add_prototype_selector(merge)
|
||||
output3 = self._add_solution_selector(output2)
|
||||
return True
|
||||
|
||||
def _add_root_method(self,inclusters,outcluster):
|
||||
inroots = []
|
||||
for cluster in inclusters:
|
||||
inroots.append(rootname(cluster))
|
||||
outroot = rootname(outcluster)
|
||||
method = OrMethod(inroots, outroot)
|
||||
# add method
|
||||
self._add_method(method)
|
||||
# make sure its deleted when cluster is deleted
|
||||
self._add_dependency(outcluster, method)
|
||||
|
||||
# overriding superclass function
|
||||
def _add_cluster(self, cluster):
|
||||
# call superclass function
|
||||
ClusterSolver._add_cluster(self, cluster)
|
||||
# add root-variable if needed with default value False
|
||||
root = rootname(cluster)
|
||||
if not self._mg.contains(root):
|
||||
self._mg.add_variable(root, False)
|
||||
self._mg.set(root, False)
|
||||
# add root-variable to dependency graph
|
||||
self._add_dependency(cluster, root)
|
||||
|
||||
# class ClusterSolver3D
|
||||
|
||||
# ----------------------------------------------
|
||||
# ---------- Methods for 3D solving -------------
|
||||
|
@ -261,7 +31,7 @@ class MergePR(ClusterMethod):
|
|||
in1 = map["$p"]
|
||||
in2 = map["$r"]
|
||||
# create ouput
|
||||
outvars = Set(in1.vars).union(in2.vars)
|
||||
outvars = set(in1.vars).union(in2.vars)
|
||||
out = Rigid(outvars)
|
||||
# set method properties
|
||||
in1root = rootname(in1)
|
||||
|
@ -304,7 +74,7 @@ class MergeDR(ClusterMethod):
|
|||
in1 = map["$d"]
|
||||
in2 = map["$r"]
|
||||
# create ouput
|
||||
outvars = Set(in1.vars).union(in2.vars)
|
||||
outvars = set(in1.vars).union(in2.vars)
|
||||
out = Rigid(outvars)
|
||||
# set method properties
|
||||
in1root = rootname(in1)
|
||||
|
@ -347,7 +117,7 @@ class MergeRR(ClusterMethod):
|
|||
in1 = map["$r1"]
|
||||
in2 = map["$r2"]
|
||||
# create output
|
||||
out = Rigid(Set(in1.vars).union(in2.vars))
|
||||
out = Rigid(set(in1.vars).union(in2.vars))
|
||||
# set method parameters
|
||||
in1root = rootname(in1)
|
||||
in2root = rootname(in2)
|
||||
|
@ -636,7 +406,7 @@ class MergeSR(ClusterMethod):
|
|||
in1 = map["$r"]
|
||||
in2 = map["$s"]
|
||||
# create output
|
||||
out = Rigid(Set(in2.vars))
|
||||
out = Rigid(set(in2.vars))
|
||||
# set method parameters
|
||||
self._inputs = [in1, in2]
|
||||
self._outputs = [out]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""Clusters are generalised constraints on sets of points in R^n. Cluster
|
||||
types are Rigids, Hedgehogs and Balloons. """
|
||||
|
||||
from sets import Set, ImmutableSet
|
||||
from multimethod import MultiVariable
|
||||
|
||||
class Distance:
|
||||
|
@ -23,11 +22,11 @@ class Distance:
|
|||
+str(self.vars[1])+")"
|
||||
|
||||
def __hash__(self):
|
||||
return hash(ImmutableSet(self.vars))
|
||||
return hash(frozenset(self.vars))
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Distance):
|
||||
return ImmutableSet(self.vars) == ImmutableSet(other.vars)
|
||||
return frozenset(self.vars) == frozenset(other.vars)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
@ -47,13 +46,13 @@ class Angle:
|
|||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Angle):
|
||||
return self.vars[2] == other.vars[2] and ImmutableSet(self.vars) == ImmutableSet(other.vars)
|
||||
return self.vars[2] == other.vars[2] and frozenset(self.vars) == frozenset(other.vars)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
return hash(ImmutableSet(self.vars))
|
||||
return hash(frozenset(self.vars))
|
||||
|
||||
def __str__(self):
|
||||
return "ang("\
|
||||
|
@ -72,7 +71,7 @@ class Cluster(MultiVariable):
|
|||
self.creationtime = Cluster.staticcounter
|
||||
|
||||
def intersection(self, other):
|
||||
shared = Set(self.vars).intersection(other.vars)
|
||||
shared = set(self.vars).intersection(other.vars)
|
||||
# note, a one point cluster is never returned
|
||||
#because it is not a constraint
|
||||
if len(shared) < 2:
|
||||
|
@ -89,7 +88,7 @@ class Cluster(MultiVariable):
|
|||
else:
|
||||
return None
|
||||
elif isinstance(other, Hedgehog):
|
||||
xvars = Set(shared) - Set([other.cvar])
|
||||
xvars = set(shared) - set([other.cvar])
|
||||
if other.cvar in self.vars and len(xvars) >= 2:
|
||||
return Hedgehog(other.cvar,xvars)
|
||||
else:
|
||||
|
@ -101,20 +100,20 @@ class Cluster(MultiVariable):
|
|||
else:
|
||||
return None
|
||||
elif isinstance(other, Hedgehog):
|
||||
xvars = Set(shared) - Set([other.cvar])
|
||||
xvars = set(shared) - set([other.cvar])
|
||||
if other.cvar in self.vars and len(xvars) >= 2:
|
||||
return Hedgehog(other.cvar,xvars)
|
||||
else:
|
||||
return None
|
||||
elif isinstance(self, Hedgehog):
|
||||
if isinstance(other, Rigid) or isinstance(other, Balloon):
|
||||
xvars = Set(shared) - Set([self.cvar])
|
||||
xvars = set(shared) - set([self.cvar])
|
||||
if self.cvar in other.vars and len(xvars) >= 2:
|
||||
return Hedgehog(self.cvar,xvars)
|
||||
else:
|
||||
return None
|
||||
elif isinstance(other, Hedgehog):
|
||||
xvars = Set(self.xvars).intersection(other.xvars)
|
||||
xvars = set(self.xvars).intersection(other.xvars)
|
||||
if self.cvar == other.cvar and len(xvars) >= 2:
|
||||
return Hedgehog(self.cvar,xvars)
|
||||
else:
|
||||
|
@ -134,7 +133,7 @@ class Rigid(Cluster):
|
|||
vars - list of variables
|
||||
"""
|
||||
Cluster.__init__(self)
|
||||
self.vars = ImmutableSet(vars)
|
||||
self.vars = frozenset(vars)
|
||||
self.overconstrained = False
|
||||
|
||||
def __str__(self):
|
||||
|
@ -165,7 +164,7 @@ class Hedgehog(Cluster):
|
|||
self.cvar = cvar
|
||||
if len(xvars) < 2:
|
||||
raise StandardError, "hedgehog must have at least three variables"
|
||||
self.xvars = ImmutableSet(xvars)
|
||||
self.xvars = frozenset(xvars)
|
||||
self.vars = self.xvars.union([self.cvar])
|
||||
self.overconstrained = False
|
||||
|
||||
|
@ -194,7 +193,7 @@ class Balloon(Cluster):
|
|||
Cluster.__init__(self)
|
||||
if len(variables) < 3:
|
||||
raise StandardError, "balloon must have at least three variables"
|
||||
self.vars = ImmutableSet(variables)
|
||||
self.vars = frozenset(variables)
|
||||
self.overconstrained = False
|
||||
|
||||
def __str__(self):
|
||||
|
@ -240,10 +239,10 @@ def over_angles(c1, c2):
|
|||
def over_distances(c1, c2):
|
||||
"""determine set of distances in c1 and c2"""
|
||||
if not (isinstance(c1, Rigid) and isinstance(c2, Rigid)):
|
||||
return Set()
|
||||
return set()
|
||||
else:
|
||||
shared = list(Set(c1.vars).intersection(c2.vars))
|
||||
overdists = Set()
|
||||
shared = list(set(c1.vars).intersection(c2.vars))
|
||||
overdists = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i):
|
||||
v1 = shared[i]
|
||||
|
@ -253,10 +252,10 @@ def over_distances(c1, c2):
|
|||
|
||||
def over_angles_hh(hog1, hog2):
|
||||
# determine duplicate angles
|
||||
shared = list(Set(hog1.xvars).intersection(hog2.xvars))
|
||||
shared = list(set(hog1.xvars).intersection(hog2.xvars))
|
||||
if not hog1.cvar == hog2.cvar:
|
||||
return Set()
|
||||
overangles = Set()
|
||||
return set()
|
||||
overangles = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i):
|
||||
v1 = shared[i]
|
||||
|
@ -266,8 +265,8 @@ def over_angles_hh(hog1, hog2):
|
|||
|
||||
def over_angles_bb(b1, b2):
|
||||
# determine duplicate angles
|
||||
shared = list(Set(b1.vars).intersection(b2.vars))
|
||||
overangles = Set()
|
||||
shared = list(set(b1.vars).intersection(b2.vars))
|
||||
overangles = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i+1, len(shared)):
|
||||
for k in range(j+1, len(shared)):
|
||||
|
@ -282,8 +281,8 @@ def over_angles_bb(b1, b2):
|
|||
def over_angles_cb(cluster, balloon):
|
||||
# determine duplicate angles
|
||||
# note: identical to over_angles_bb and (non-existent) over_angles_cc
|
||||
shared = list(Set(cluster.vars).intersection(balloon.vars))
|
||||
overangles = Set()
|
||||
shared = list(set(cluster.vars).intersection(balloon.vars))
|
||||
overangles = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i+1, len(shared)):
|
||||
for k in range(j+1, len(shared)):
|
||||
|
@ -297,10 +296,10 @@ def over_angles_cb(cluster, balloon):
|
|||
|
||||
def over_angles_bh(balloon, hog):
|
||||
# determine duplicate angles
|
||||
shared = list(Set(balloon.vars).intersection(hog.xvars))
|
||||
shared = list(set(balloon.vars).intersection(hog.xvars))
|
||||
if hog.cvar not in balloon.vars:
|
||||
return Set()
|
||||
overangles = Set()
|
||||
return set()
|
||||
overangles = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i+1,len(shared)):
|
||||
v1 = shared[i]
|
||||
|
@ -310,10 +309,10 @@ def over_angles_bh(balloon, hog):
|
|||
|
||||
def over_angles_ch(cluster, hog):
|
||||
# determine duplicate angles
|
||||
shared = list(Set(cluster.vars).intersection(hog.xvars))
|
||||
shared = list(set(cluster.vars).intersection(hog.xvars))
|
||||
if hog.cvar not in cluster.vars:
|
||||
return Set()
|
||||
overangles = Set()
|
||||
return set()
|
||||
overangles = set()
|
||||
for i in range(len(shared)):
|
||||
for j in range(i+1,len(shared)):
|
||||
v1 = shared[i]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
A configuration is a set of named points with coordinates."""
|
||||
|
||||
from sets import Set
|
||||
from matfunc import Vec, Mat
|
||||
from intersections import *
|
||||
from tolerance import *
|
||||
|
@ -113,7 +112,7 @@ class Configuration:
|
|||
|
||||
def _merge_transform_2D(self, other):
|
||||
"""returns a new configurations which is this one plus the given other configuration transformed, such that common points will overlap (if possible)."""
|
||||
shared = Set(self.vars()).intersection(other.vars())
|
||||
shared = set(self.vars()).intersection(other.vars())
|
||||
underconstrained = self.underconstrained or other.underconstrained
|
||||
if len(shared) == 0:
|
||||
underconstrained = True
|
||||
|
@ -152,7 +151,7 @@ class Configuration:
|
|||
def merge_scale_2D(self, other, vars=[]):
|
||||
"""returns a new configurations which is this one plus the given other configuration transformed, such that common points will overlap (if possible)."""
|
||||
if len(vars) == 0:
|
||||
shared = Set(self.vars()).intersection(other.vars())
|
||||
shared = set(self.vars()).intersection(other.vars())
|
||||
else:
|
||||
shared = vars
|
||||
underconstrained = self.underconstrained or other.underconstrained
|
||||
|
@ -186,7 +185,7 @@ class Configuration:
|
|||
"""returns a matrix for a rigid transformation
|
||||
such that points in other are mapped onto points in self
|
||||
"""
|
||||
shared = Set(self.vars()).intersection(other.vars())
|
||||
shared = set(self.vars()).intersection(other.vars())
|
||||
underconstrained = self.underconstrained or other.underconstrained
|
||||
if len(shared) == 0:
|
||||
underconstrained = True
|
||||
|
@ -253,7 +252,7 @@ class Configuration:
|
|||
return t
|
||||
|
||||
def _merge_scale_transform_3D(self, other):
|
||||
shared = Set(self.vars()).intersection(other.vars())
|
||||
shared = set(self.vars()).intersection(other.vars())
|
||||
if len(shared) == 0:
|
||||
return self._merge_transform_3D(other)
|
||||
elif len(shared) == 1:
|
||||
|
|
|
@ -41,7 +41,7 @@ def gmatch(pattern, reference):
|
|||
outmatches = []
|
||||
for n in onumbers:
|
||||
outmatches += reference.outfan(n)
|
||||
matches = Set(inmatches).intersection(outmatches)
|
||||
matches = set(inmatches).intersection(outmatches)
|
||||
newsolutions = []
|
||||
if solutions == None:
|
||||
for refvar in matches:
|
||||
|
|
|
@ -31,7 +31,6 @@ Copyright Rick van der Meiden - 2003, 2004, 2005
|
|||
"""
|
||||
|
||||
import random
|
||||
from sets import Set,ImmutableSet
|
||||
from notify import Notifier
|
||||
|
||||
class Graph (Notifier):
|
||||
|
@ -199,9 +198,8 @@ class Graph (Notifier):
|
|||
|
||||
def adjacent_vertices(self, v):
|
||||
"""list of adjacent (ingoing or outgoing) vertices"""
|
||||
from sets import Set
|
||||
iset = Set(self.ingoing_vertices(v))
|
||||
oset = Set(self.outgoing_vertices(v))
|
||||
iset = set(self.ingoing_vertices(v))
|
||||
oset = set(self.outgoing_vertices(v))
|
||||
vset = iset.union(oset)
|
||||
return list(vset)
|
||||
|
||||
|
@ -300,11 +298,11 @@ class Graph (Notifier):
|
|||
|
||||
def connected_subsets(self):
|
||||
"""returns a set of (undirectionally) connected subsets of vertices"""
|
||||
todo = Set(self.vertices())
|
||||
subsets = Set()
|
||||
todo = set(self.vertices())
|
||||
subsets = set()
|
||||
while (todo):
|
||||
v = todo.pop()
|
||||
s = Set(self.connected(v))
|
||||
s = set(self.connected(v))
|
||||
for x in s:
|
||||
todo.remove(x)
|
||||
s.add(v)
|
||||
|
@ -324,13 +322,13 @@ class Graph (Notifier):
|
|||
graph = Graph()
|
||||
for edge in self.edges():
|
||||
(v1,v2) = edge
|
||||
g1 = ImmutableSet([v1])
|
||||
g2 = ImmutableSet([v2])
|
||||
g1 = frozenset([v1])
|
||||
g2 = frozenset([v2])
|
||||
graph.add_edge(g1,g2)
|
||||
|
||||
# Stoer/Wagner algorithm
|
||||
mincutvalue = None
|
||||
mincut = ImmutableSet()
|
||||
mincut = frozenset()
|
||||
while len(graph.vertices()) > 1:
|
||||
(phasecut,phasecutvalue) = self._mincutphase(graph)
|
||||
if mincutvalue == None or phasecutvalue < mincutvalue:
|
||||
|
@ -339,8 +337,8 @@ class Graph (Notifier):
|
|||
|
||||
# rewrite output
|
||||
g1 = mincut
|
||||
g2 = ImmutableSet(self.vertices()).difference(g1)
|
||||
edges = Set()
|
||||
g2 = frozenset(self.vertices()).difference(g1)
|
||||
edges = set()
|
||||
for v in g1:
|
||||
for k in self.adjacent_vertices(v):
|
||||
if k in g2:
|
||||
|
@ -356,7 +354,7 @@ class Graph (Notifier):
|
|||
if self.has_edge(k,v):
|
||||
edges.add((k,v))
|
||||
|
||||
return (mincutvalue, ImmutableSet(edges), g1, g2)
|
||||
return (mincutvalue, frozenset(edges), g1, g2)
|
||||
|
||||
def _mincutphase(self, graph):
|
||||
# returns the last vertex (group) added and the cut value
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""Base classes for multi-valued assignments in methodgraphs"""
|
||||
|
||||
from method import Method, MethodGraph
|
||||
from sets import Set
|
||||
|
||||
class MultiVariable:
|
||||
"""For representing multi-valued variables
|
||||
|
@ -34,6 +33,8 @@ class MultiMethod(Method):
|
|||
The 'multi_execute' method must return a list of possible values for the output variable.
|
||||
The output values returned by subsequent calls multi-execute are collected and stored in the
|
||||
output MultiVariable.
|
||||
|
||||
Note that a set of values for the outputvariable is stored, so that equivalent values are only stored once.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
@ -65,10 +66,10 @@ class MultiMethod(Method):
|
|||
if len(multi_inputs) > 0:
|
||||
mvar = multi_inputs[0]
|
||||
values = inmap[mvar]
|
||||
output = Set()
|
||||
output = set()
|
||||
for value in values:
|
||||
base_inmap[mvar] = value
|
||||
output.union_update(self._recurse_execute(inmap, base_inmap, multi_inputs[1:]))
|
||||
output.update(self._recurse_execute(inmap, base_inmap, multi_inputs[1:]))
|
||||
return output
|
||||
else:
|
||||
return self.multi_execute(base_inmap)
|
||||
|
|
Loading…
Reference in New Issue
Block a user