Skip to content

Commit 19b1e5c

Browse files
committed
Fix quadratic-time behaviour in full_subgraph.
1 parent f936500 commit 19b1e5c

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

refcycle/directed_graph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ def full_subgraph(self, vertices):
102102
"""
103103
subgraph_vertices = {v for v in vertices}
104104
subgraph_edges = {edge
105-
for v in vertices
105+
for v in subgraph_vertices
106106
for edge in self._out_edges[v]
107-
if self._heads[edge] in vertices}
107+
if self._heads[edge] in subgraph_vertices}
108108
subgraph_heads = {edge: self._heads[edge]
109109
for edge in subgraph_edges}
110110
subgraph_tails = {edge: self._tails[edge]

refcycle/test/test_directed_graph.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,38 @@ def test_full_subgraph(self):
257257
self.assertCountEqual(vertices, [1, 2, 3, 4, 5])
258258
self.assertEqual(len(edges), 5)
259259

260+
def test_full_subgraph_large_from_list(self):
261+
# An earlier version of full_subgraph had quadratic-time behaviour.
262+
vertex_count = 20000
263+
vertices = set(range(vertex_count))
264+
edge_mapper = {
265+
n: [(n + 1) % vertex_count, (n + 1) % vertex_count]
266+
for n in vertices
267+
}
268+
graph = DirectedGraph.from_out_edges(
269+
vertices=vertices,
270+
edge_mapper=edge_mapper,
271+
)
272+
subgraph = graph.full_subgraph(list(vertices))
273+
self.assertEqual(len(subgraph.vertices), len(graph.vertices))
274+
self.assertEqual(len(subgraph.edges), len(graph.edges))
275+
276+
def test_full_subgraph_from_iterator(self):
277+
# Should be fine to create a subgraph from an iterator.
278+
vertex_count = 100
279+
vertices = set(range(vertex_count))
280+
edge_mapper = {
281+
n: [(n + 1) % vertex_count, (n + 1) % vertex_count]
282+
for n in vertices
283+
}
284+
graph = DirectedGraph.from_out_edges(
285+
vertices=vertices,
286+
edge_mapper=edge_mapper,
287+
)
288+
subgraph = graph.full_subgraph(iter(vertices))
289+
self.assertEqual(len(subgraph.vertices), len(graph.vertices))
290+
self.assertEqual(len(subgraph.edges), len(graph.edges))
291+
260292
def test_to_dot(self):
261293
dot = test_graph.to_dot()
262294
self.assertIsInstance(dot, six.text_type)

0 commit comments

Comments
 (0)