From: Mike Bayer Date: Tue, 30 Mar 2010 22:15:02 +0000 (-0400) Subject: merge trunk. Re-instating topological._find_cycles for the moment X-Git-Tag: rel_0_6_0~82 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=00738b252c280111dafc8a034eade1507c1dddd8;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git merge trunk. Re-instating topological._find_cycles for the moment --- 00738b252c280111dafc8a034eade1507c1dddd8 diff --cc lib/sqlalchemy/topological.py index 3f2ff6399c,d35213f6b5..324995889f --- a/lib/sqlalchemy/topological.py +++ b/lib/sqlalchemy/topological.py @@@ -141,3 -216,82 +141,36 @@@ def sort(tuples, allitems) queue.append(childnode) return output -def _organize_as_tree(nodes): - """Given a list of nodes from a topological sort, organize the - nodes into a tree structure, with as many non-dependent nodes - set as siblings to each other as possible. - - returns nodes as 3-tuples (item, cycles, children). - """ - - if not nodes: - return None - # a list of all currently independent subtrees as a tuple of - # (root_node, set_of_all_tree_nodes, set_of_all_cycle_nodes_in_tree) - # order of the list has no semantics for the algorithmic - independents = [] - # in reverse topological order - for node in reversed(nodes): - # nodes subtree and cycles contain the node itself - subtree = set([node]) - if node.cycles is not None: - cycles = set(node.cycles) - else: - cycles = set() - # get a set of dependent nodes of node and its cycles - nodealldeps = node.all_deps() - if nodealldeps: - # iterate over independent node indexes in reverse order so we can efficiently remove them - for index in xrange(len(independents) - 1, -1, -1): - child, childsubtree, childcycles = independents[index] - # if there is a dependency between this node and an independent node - if (childsubtree.intersection(nodealldeps) or childcycles.intersection(node.dependencies)): - # prepend child to nodes children - # (append should be fine, but previous implemetation used prepend) - node.children[0:0] = [(child.item, [n.item for n in child.cycles or []], child.children)] - # merge childs subtree and cycles - subtree.update(childsubtree) - cycles.update(childcycles) - # remove the child from list of independent subtrees - independents[index:index+1] = [] - # add node as a new independent subtree - independents.append((node, subtree, cycles)) - # choose an arbitrary node from list of all independent subtrees - head = independents.pop()[0] - # add all other independent subtrees as a child of the chosen root - # used prepend [0:0] instead of extend to maintain exact behaviour of previous implementation - head.children[0:0] = [(i[0].item, [n.item for n in i[0].cycles or []], i[0].children) for i in independents] - return (head.item, [n.item for n in head.cycles or []], head.children) + + def _find_cycles(edges): + cycles = {} + + def traverse(node, cycle, goal): + for (n, key) in edges.edges_by_parent(node): + if key in cycle: + continue + cycle.add(key) + if key is goal: + cycset = set(cycle) + for x in cycle: + if x in cycles: + existing_set = cycles[x] + existing_set.update(cycset) + for y in existing_set: + cycles[y] = existing_set + cycset = existing_set + else: + cycles[x] = cycset + else: + traverse(key, cycle, goal) + cycle.pop() + + for parent in edges.get_parents(): + traverse(parent, set(), parent) + + unique_cycles = set(tuple(s) for s in cycles.values()) + + for cycle in unique_cycles: + edgecollection = [edge for edge in edges + if edge[0] in cycle and edge[1] in cycle] + yield edgecollection