[pypy-svn] r50538 - in pypy/dist/pypy/tool/algo: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Sun Jan 13 09:06:39 CET 2008
Author: cfbolz
Date: Sun Jan 13 09:06:38 2008
New Revision: 50538
Modified:
pypy/dist/pypy/tool/algo/graphlib.py
pypy/dist/pypy/tool/algo/test/test_graphlib.py
Log:
make the implementation of the cycle breaker algorithm less braindead: don't
recompute the cycles every time you break a few, reuse the existing information
instead. The algorithm stays exponential but I think it's still reasonable for
"practical" call trees which are far from being complete graphs.
Modified: pypy/dist/pypy/tool/algo/graphlib.py
==============================================================================
--- pypy/dist/pypy/tool/algo/graphlib.py (original)
+++ pypy/dist/pypy/tool/algo/graphlib.py Sun Jan 13 09:06:38 2008
@@ -100,26 +100,42 @@
def break_cycles(vertices, edges):
"""Enumerates a reasonably minimal set of edges that must be removed to
make the graph acyclic."""
- graphs = [(vertices, edges)]
- for vertices, edges in graphs:
- #print ''.join(vertices),
- #print [e.source+e.target for l in edges.values() for e in l]
- for component in strong_components(vertices, edges):
- #print '-->', ''.join(component)
- edge_weights = {}
- random_vertex = component.iterkeys().next()
- for cycle in all_cycles(random_vertex, component, edges):
- #print '\tcycle:', [e.source+e.target for e in cycle]
- for edge in cycle:
- edge_weights[edge] = edge_weights.get(edge, 0) + 1
- if edge_weights:
- max_weight = max(edge_weights.values())
- for edge, weight in edge_weights.iteritems():
- if weight == max_weight:
- break
- # kill this edge
- yield edge
- new_edges = edges.copy()
- new_edges[edge.source] = [e for e in new_edges[edge.source]
- if e is not edge]
- graphs.append((component, new_edges))
+ # the approach is as follows: for each strongly connected component, find
+ # all cycles (which takens exponential time, potentially). Then break the
+ # edges that are part of the most cycles, until all cycles in that
+ # component are broken.
+ for component in strong_components(vertices, edges):
+ #print '-->', ''.join(component)
+ random_vertex = component.iterkeys().next()
+ cycles = all_cycles(random_vertex, component, edges)
+ if not cycles:
+ continue
+ allcycles = dict.fromkeys([id(cycle) for cycle in cycles])
+ edge2cycles = {}
+ edge_weights = {}
+ for cycle in cycles:
+ #print '\tcycle:', [e.source+e.target for e in cycle]
+ for edge in cycle:
+ edge2cycles.setdefault(edge, []).append(cycle)
+ edge_weights[edge] = edge_weights.get(edge, 0) + 1
+ while allcycles:
+ max_weight = 0
+ max_edge = None
+ for edge, weight in edge_weights.iteritems():
+ if weight >= max_weight:
+ max_edge = edge
+ max_weight = weight
+ broken_cycles = edge2cycles[max_edge]
+ assert max_edge is not None
+ # kill this edge
+ yield max_edge
+ for broken_cycle in broken_cycles:
+ try:
+ del allcycles[id(broken_cycle)]
+ except KeyError:
+ pass
+ else:
+ for edge in broken_cycle:
+ edge_weights[edge] -= 1
+ if edge_weights[edge] == 0:
+ del edge_weights[edge]
Modified: pypy/dist/pypy/tool/algo/test/test_graphlib.py
==============================================================================
--- pypy/dist/pypy/tool/algo/test/test_graphlib.py (original)
+++ pypy/dist/pypy/tool/algo/test/test_graphlib.py Sun Jan 13 09:06:38 2008
@@ -146,7 +146,7 @@
class TestBadCase:
# a complete graph
- NUM = 30
+ NUM = 50
edges = make_edge_dict([Edge(i, j) for i in range(NUM)
for j in range(NUM)])
vertices = dict.fromkeys(range(NUM))
More information about the Pypy-commit
mailing list