Skip to content

Commit 805adc6

Browse files
authored
Merge pull request #63 from mdickinson/fix/subgraph-from-list
Fix quadratic-time behaviour in DirectedGraph.full_subgraph.
2 parents 6ee91fa + 19b1e5c commit 805adc6

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
@@ -291,6 +291,38 @@ def test_full_subgraph(self):
291291
self.assertCountEqual(vertices, [1, 2, 3, 4, 5])
292292
self.assertEqual(len(edges), 5)
293293

294+
def test_full_subgraph_large_from_list(self):
295+
# An earlier version of full_subgraph had quadratic-time behaviour.
296+
vertex_count = 20000
297+
vertices = set(range(vertex_count))
298+
edge_mapper = {
299+
n: [(n + 1) % vertex_count, (n + 1) % vertex_count]
300+
for n in vertices
301+
}
302+
graph = DirectedGraph.from_out_edges(
303+
vertices=vertices,
304+
edge_mapper=edge_mapper,
305+
)
306+
subgraph = graph.full_subgraph(list(vertices))
307+
self.assertEqual(len(subgraph.vertices), len(graph.vertices))
308+
self.assertEqual(len(subgraph.edges), len(graph.edges))
309+
310+
def test_full_subgraph_from_iterator(self):
311+
# Should be fine to create a subgraph from an iterator.
312+
vertex_count = 100
313+
vertices = set(range(vertex_count))
314+
edge_mapper = {
315+
n: [(n + 1) % vertex_count, (n + 1) % vertex_count]
316+
for n in vertices
317+
}
318+
graph = DirectedGraph.from_out_edges(
319+
vertices=vertices,
320+
edge_mapper=edge_mapper,
321+
)
322+
subgraph = graph.full_subgraph(iter(vertices))
323+
self.assertEqual(len(subgraph.vertices), len(graph.vertices))
324+
self.assertEqual(len(subgraph.edges), len(graph.edges))
325+
294326
def test_to_dot(self):
295327
dot = test_graph.to_dot()
296328
self.assertIsInstance(dot, six.text_type)

0 commit comments

Comments
 (0)