From 8d9e4ca934284a162b41dd9bc24439b02f4e7524 Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Thu, 24 Oct 2019 23:41:11 +0300 Subject: [PATCH] graph: use find_cycle instead of simple_cycle (#2668) We are incorrectly using `simple_cycle` here, `find_cycle` is much more suitable for this application and much faster too. For example: ``` $ cat test_networkx.py import networkx as nx from dvc.repo.graph import check_acyclic G = nx.scale_free_graph(1200) list(nx.find_cycle(G, orientation='ignore')) list(nx.simple_cycles(G)) $ python -mcProfile -scumtime test_networkx.py &> log.log ``` shows ~100s for `simple_cycles` and ~0s for `find_cycle`. Fixes #2666 --- dvc/repo/graph.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dvc/repo/graph.py b/dvc/repo/graph.py index 58cbd4ea0..0aba69226 100644 --- a/dvc/repo/graph.py +++ b/dvc/repo/graph.py @@ -5,10 +5,17 @@ def check_acyclic(graph): import networkx as nx from dvc.exceptions import CyclicGraphError - cycle = next(nx.simple_cycles(graph), None) + try: + edges = nx.find_cycle(graph, orientation="original") + except nx.NetworkXNoCycle: + return - if cycle: - raise CyclicGraphError(cycle) + stages = set() + for from_node, to_node, _ in edges: + stages.add(from_node) + stages.add(to_node) + + raise CyclicGraphError(list(stages)) def get_pipeline(pipelines, node):