123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- from collections import deque
- from itertools import combinations, permutations
- import pytest
- import networkx as nx
- from networkx.utils import edges_equal, pairwise
- # Recipe from the itertools documentation.
- def _consume(iterator):
- "Consume the iterator entirely."
- # Feed the entire iterator into a zero-length deque.
- deque(iterator, maxlen=0)
- class TestDagLongestPath:
- """Unit tests computing the longest path in a directed acyclic graph."""
- def test_empty(self):
- G = nx.DiGraph()
- assert nx.dag_longest_path(G) == []
- def test_unweighted1(self):
- edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (3, 7)]
- G = nx.DiGraph(edges)
- assert nx.dag_longest_path(G) == [1, 2, 3, 5, 6]
- def test_unweighted2(self):
- edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)]
- G = nx.DiGraph(edges)
- assert nx.dag_longest_path(G) == [1, 2, 3, 4, 5]
- def test_weighted(self):
- G = nx.DiGraph()
- edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), (1, 6, 2)]
- G.add_weighted_edges_from(edges)
- assert nx.dag_longest_path(G) == [2, 3, 5]
- def test_undirected_not_implemented(self):
- G = nx.Graph()
- pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path, G)
- def test_unorderable_nodes(self):
- """Tests that computing the longest path does not depend on
- nodes being orderable.
- For more information, see issue #1989.
- """
- # Create the directed path graph on four nodes in a diamond shape,
- # with nodes represented as (unorderable) Python objects.
- nodes = [object() for n in range(4)]
- G = nx.DiGraph()
- G.add_edge(nodes[0], nodes[1])
- G.add_edge(nodes[0], nodes[2])
- G.add_edge(nodes[2], nodes[3])
- G.add_edge(nodes[1], nodes[3])
- # this will raise NotImplementedError when nodes need to be ordered
- nx.dag_longest_path(G)
- def test_multigraph_unweighted(self):
- edges = [(1, 2), (2, 3), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)]
- G = nx.MultiDiGraph(edges)
- assert nx.dag_longest_path(G) == [1, 2, 3, 4, 5]
- def test_multigraph_weighted(self):
- G = nx.MultiDiGraph()
- edges = [
- (1, 2, 2),
- (2, 3, 2),
- (1, 3, 1),
- (1, 3, 5),
- (1, 3, 2),
- ]
- G.add_weighted_edges_from(edges)
- assert nx.dag_longest_path(G) == [1, 3]
- def test_multigraph_weighted_default_weight(self):
- G = nx.MultiDiGraph([(1, 2), (2, 3)]) # Unweighted edges
- G.add_weighted_edges_from([(1, 3, 1), (1, 3, 5), (1, 3, 2)])
- # Default value for default weight is 1
- assert nx.dag_longest_path(G) == [1, 3]
- assert nx.dag_longest_path(G, default_weight=3) == [1, 2, 3]
- class TestDagLongestPathLength:
- """Unit tests for computing the length of a longest path in a
- directed acyclic graph.
- """
- def test_unweighted(self):
- edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)]
- G = nx.DiGraph(edges)
- assert nx.dag_longest_path_length(G) == 4
- edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)]
- G = nx.DiGraph(edges)
- assert nx.dag_longest_path_length(G) == 4
- # test degenerate graphs
- G = nx.DiGraph()
- G.add_node(1)
- assert nx.dag_longest_path_length(G) == 0
- def test_undirected_not_implemented(self):
- G = nx.Graph()
- pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path_length, G)
- def test_weighted(self):
- edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), (1, 6, 2)]
- G = nx.DiGraph()
- G.add_weighted_edges_from(edges)
- assert nx.dag_longest_path_length(G) == 5
- def test_multigraph_unweighted(self):
- edges = [(1, 2), (2, 3), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)]
- G = nx.MultiDiGraph(edges)
- assert nx.dag_longest_path_length(G) == 4
- def test_multigraph_weighted(self):
- G = nx.MultiDiGraph()
- edges = [
- (1, 2, 2),
- (2, 3, 2),
- (1, 3, 1),
- (1, 3, 5),
- (1, 3, 2),
- ]
- G.add_weighted_edges_from(edges)
- assert nx.dag_longest_path_length(G) == 5
- class TestDAG:
- @classmethod
- def setup_class(cls):
- pass
- def test_topological_sort1(self):
- DG = nx.DiGraph([(1, 2), (1, 3), (2, 3)])
- for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]:
- assert tuple(algorithm(DG)) == (1, 2, 3)
- DG.add_edge(3, 2)
- for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]:
- pytest.raises(nx.NetworkXUnfeasible, _consume, algorithm(DG))
- DG.remove_edge(2, 3)
- for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]:
- assert tuple(algorithm(DG)) == (1, 3, 2)
- DG.remove_edge(3, 2)
- assert tuple(nx.topological_sort(DG)) in {(1, 2, 3), (1, 3, 2)}
- assert tuple(nx.lexicographical_topological_sort(DG)) == (1, 2, 3)
- def test_is_directed_acyclic_graph(self):
- G = nx.generators.complete_graph(2)
- assert not nx.is_directed_acyclic_graph(G)
- assert not nx.is_directed_acyclic_graph(G.to_directed())
- assert not nx.is_directed_acyclic_graph(nx.Graph([(3, 4), (4, 5)]))
- assert nx.is_directed_acyclic_graph(nx.DiGraph([(3, 4), (4, 5)]))
- def test_topological_sort2(self):
- DG = nx.DiGraph(
- {
- 1: [2],
- 2: [3],
- 3: [4],
- 4: [5],
- 5: [1],
- 11: [12],
- 12: [13],
- 13: [14],
- 14: [15],
- }
- )
- pytest.raises(nx.NetworkXUnfeasible, _consume, nx.topological_sort(DG))
- assert not nx.is_directed_acyclic_graph(DG)
- DG.remove_edge(1, 2)
- _consume(nx.topological_sort(DG))
- assert nx.is_directed_acyclic_graph(DG)
- def test_topological_sort3(self):
- DG = nx.DiGraph()
- DG.add_edges_from([(1, i) for i in range(2, 5)])
- DG.add_edges_from([(2, i) for i in range(5, 9)])
- DG.add_edges_from([(6, i) for i in range(9, 12)])
- DG.add_edges_from([(4, i) for i in range(12, 15)])
- def validate(order):
- assert isinstance(order, list)
- assert set(order) == set(DG)
- for u, v in combinations(order, 2):
- assert not nx.has_path(DG, v, u)
- validate(list(nx.topological_sort(DG)))
- DG.add_edge(14, 1)
- pytest.raises(nx.NetworkXUnfeasible, _consume, nx.topological_sort(DG))
- def test_topological_sort4(self):
- G = nx.Graph()
- G.add_edge(1, 2)
- # Only directed graphs can be topologically sorted.
- pytest.raises(nx.NetworkXError, _consume, nx.topological_sort(G))
- def test_topological_sort5(self):
- G = nx.DiGraph()
- G.add_edge(0, 1)
- assert list(nx.topological_sort(G)) == [0, 1]
- def test_topological_sort6(self):
- for algorithm in [nx.topological_sort, nx.lexicographical_topological_sort]:
- def runtime_error():
- DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- first = True
- for x in algorithm(DG):
- if first:
- first = False
- DG.add_edge(5 - x, 5)
- def unfeasible_error():
- DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- first = True
- for x in algorithm(DG):
- if first:
- first = False
- DG.remove_node(4)
- def runtime_error2():
- DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- first = True
- for x in algorithm(DG):
- if first:
- first = False
- DG.remove_node(2)
- pytest.raises(RuntimeError, runtime_error)
- pytest.raises(RuntimeError, runtime_error2)
- pytest.raises(nx.NetworkXUnfeasible, unfeasible_error)
- def test_all_topological_sorts_1(self):
- DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 5)])
- assert list(nx.all_topological_sorts(DG)) == [[1, 2, 3, 4, 5]]
- def test_all_topological_sorts_2(self):
- DG = nx.DiGraph([(1, 3), (2, 1), (2, 4), (4, 3), (4, 5)])
- assert sorted(nx.all_topological_sorts(DG)) == [
- [2, 1, 4, 3, 5],
- [2, 1, 4, 5, 3],
- [2, 4, 1, 3, 5],
- [2, 4, 1, 5, 3],
- [2, 4, 5, 1, 3],
- ]
- def test_all_topological_sorts_3(self):
- def unfeasible():
- DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 2), (4, 5)])
- # convert to list to execute generator
- list(nx.all_topological_sorts(DG))
- def not_implemented():
- G = nx.Graph([(1, 2), (2, 3)])
- # convert to list to execute generator
- list(nx.all_topological_sorts(G))
- def not_implemted_2():
- G = nx.MultiGraph([(1, 2), (1, 2), (2, 3)])
- list(nx.all_topological_sorts(G))
- pytest.raises(nx.NetworkXUnfeasible, unfeasible)
- pytest.raises(nx.NetworkXNotImplemented, not_implemented)
- pytest.raises(nx.NetworkXNotImplemented, not_implemted_2)
- def test_all_topological_sorts_4(self):
- DG = nx.DiGraph()
- for i in range(7):
- DG.add_node(i)
- assert sorted(map(list, permutations(DG.nodes))) == sorted(
- nx.all_topological_sorts(DG)
- )
- def test_all_topological_sorts_multigraph_1(self):
- DG = nx.MultiDiGraph([(1, 2), (1, 2), (2, 3), (3, 4), (3, 5), (3, 5), (3, 5)])
- assert sorted(nx.all_topological_sorts(DG)) == sorted(
- [[1, 2, 3, 4, 5], [1, 2, 3, 5, 4]]
- )
- def test_all_topological_sorts_multigraph_2(self):
- N = 9
- edges = []
- for i in range(1, N):
- edges.extend([(i, i + 1)] * i)
- DG = nx.MultiDiGraph(edges)
- assert list(nx.all_topological_sorts(DG)) == [list(range(1, N + 1))]
- def test_ancestors(self):
- G = nx.DiGraph()
- ancestors = nx.algorithms.dag.ancestors
- G.add_edges_from([(1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)])
- assert ancestors(G, 6) == {1, 2, 4, 5}
- assert ancestors(G, 3) == {1, 4}
- assert ancestors(G, 1) == set()
- pytest.raises(nx.NetworkXError, ancestors, G, 8)
- def test_descendants(self):
- G = nx.DiGraph()
- descendants = nx.algorithms.dag.descendants
- G.add_edges_from([(1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)])
- assert descendants(G, 1) == {2, 3, 6}
- assert descendants(G, 4) == {2, 3, 5, 6}
- assert descendants(G, 3) == set()
- pytest.raises(nx.NetworkXError, descendants, G, 8)
- def test_transitive_closure(self):
- G = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (2, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)]
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
- solution = [(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(sorted(nx.transitive_closure(G).edges()), soln)
- G = nx.Graph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution)
- G = nx.MultiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution)
- G = nx.MultiDiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- assert edges_equal(sorted(nx.transitive_closure(G).edges()), solution)
- # test if edge data is copied
- G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)])
- H = nx.transitive_closure(G)
- for u, v in G.edges():
- assert G.get_edge_data(u, v) == H.get_edge_data(u, v)
- k = 10
- G = nx.DiGraph((i, i + 1, {"f": "b", "weight": i}) for i in range(k))
- H = nx.transitive_closure(G)
- for u, v in G.edges():
- assert G.get_edge_data(u, v) == H.get_edge_data(u, v)
- G = nx.Graph()
- with pytest.raises(nx.NetworkXError):
- nx.transitive_closure(G, reflexive="wrong input")
- def test_reflexive_transitive_closure(self):
- G = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, False).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, True).edges(), soln)
- assert edges_equal(nx.transitive_closure(G, None).edges(), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (2, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, False).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, True).edges(), soln)
- assert edges_equal(nx.transitive_closure(G, None).edges(), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
- solution = sorted([(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)])
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(sorted(nx.transitive_closure(G).edges()), soln)
- assert edges_equal(sorted(nx.transitive_closure(G, False).edges()), soln)
- assert edges_equal(sorted(nx.transitive_closure(G, None).edges()), solution)
- assert edges_equal(sorted(nx.transitive_closure(G, True).edges()), soln)
- G = nx.Graph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, False).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, True).edges(), soln)
- assert edges_equal(nx.transitive_closure(G, None).edges(), solution)
- G = nx.MultiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, False).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, True).edges(), soln)
- assert edges_equal(nx.transitive_closure(G, None).edges(), solution)
- G = nx.MultiDiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- soln = sorted(solution + [(n, n) for n in G])
- assert edges_equal(nx.transitive_closure(G).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, False).edges(), solution)
- assert edges_equal(nx.transitive_closure(G, True).edges(), soln)
- assert edges_equal(nx.transitive_closure(G, None).edges(), solution)
- def test_transitive_closure_dag(self):
- G = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- transitive_closure = nx.algorithms.dag.transitive_closure_dag
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
- assert edges_equal(transitive_closure(G).edges(), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (2, 4)])
- solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)]
- assert edges_equal(transitive_closure(G).edges(), solution)
- G = nx.Graph([(1, 2), (2, 3), (3, 4)])
- pytest.raises(nx.NetworkXNotImplemented, transitive_closure, G)
- # test if edge data is copied
- G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)])
- H = transitive_closure(G)
- for u, v in G.edges():
- assert G.get_edge_data(u, v) == H.get_edge_data(u, v)
- k = 10
- G = nx.DiGraph((i, i + 1, {"foo": "bar", "weight": i}) for i in range(k))
- H = transitive_closure(G)
- for u, v in G.edges():
- assert G.get_edge_data(u, v) == H.get_edge_data(u, v)
- def test_transitive_reduction(self):
- G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)])
- transitive_reduction = nx.algorithms.dag.transitive_reduction
- solution = [(1, 2), (2, 3), (3, 4)]
- assert edges_equal(transitive_reduction(G).edges(), solution)
- G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)])
- transitive_reduction = nx.algorithms.dag.transitive_reduction
- solution = [(1, 2), (2, 3), (2, 4)]
- assert edges_equal(transitive_reduction(G).edges(), solution)
- G = nx.Graph([(1, 2), (2, 3), (3, 4)])
- pytest.raises(nx.NetworkXNotImplemented, transitive_reduction, G)
- def _check_antichains(self, solution, result):
- sol = [frozenset(a) for a in solution]
- res = [frozenset(a) for a in result]
- assert set(sol) == set(res)
- def test_antichains(self):
- antichains = nx.algorithms.dag.antichains
- G = nx.DiGraph([(1, 2), (2, 3), (3, 4)])
- solution = [[], [4], [3], [2], [1]]
- self._check_antichains(list(antichains(G)), solution)
- G = nx.DiGraph([(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)])
- solution = [
- [],
- [4],
- [7],
- [7, 4],
- [6],
- [6, 4],
- [6, 7],
- [6, 7, 4],
- [5],
- [5, 4],
- [3],
- [3, 4],
- [2],
- [1],
- ]
- self._check_antichains(list(antichains(G)), solution)
- G = nx.DiGraph([(1, 2), (1, 3), (3, 4), (3, 5), (5, 6)])
- solution = [
- [],
- [6],
- [5],
- [4],
- [4, 6],
- [4, 5],
- [3],
- [2],
- [2, 6],
- [2, 5],
- [2, 4],
- [2, 4, 6],
- [2, 4, 5],
- [2, 3],
- [1],
- ]
- self._check_antichains(list(antichains(G)), solution)
- G = nx.DiGraph({0: [1, 2], 1: [4], 2: [3], 3: [4]})
- solution = [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]]
- self._check_antichains(list(antichains(G)), solution)
- G = nx.DiGraph()
- self._check_antichains(list(antichains(G)), [[]])
- G = nx.DiGraph()
- G.add_nodes_from([0, 1, 2])
- solution = [[], [0], [1], [1, 0], [2], [2, 0], [2, 1], [2, 1, 0]]
- self._check_antichains(list(antichains(G)), solution)
- def f(x):
- return list(antichains(x))
- G = nx.Graph([(1, 2), (2, 3), (3, 4)])
- pytest.raises(nx.NetworkXNotImplemented, f, G)
- G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
- pytest.raises(nx.NetworkXUnfeasible, f, G)
- def test_lexicographical_topological_sort(self):
- G = nx.DiGraph([(1, 2), (2, 3), (1, 4), (1, 5), (2, 6)])
- assert list(nx.lexicographical_topological_sort(G)) == [1, 2, 3, 4, 5, 6]
- assert list(nx.lexicographical_topological_sort(G, key=lambda x: x)) == [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- ]
- assert list(nx.lexicographical_topological_sort(G, key=lambda x: -x)) == [
- 1,
- 5,
- 4,
- 2,
- 6,
- 3,
- ]
- def test_lexicographical_topological_sort2(self):
- """
- Check the case of two or more nodes with same key value.
- Want to avoid exception raised due to comparing nodes directly.
- See Issue #3493
- """
- class Test_Node:
- def __init__(self, n):
- self.label = n
- self.priority = 1
- def __repr__(self):
- return f"Node({self.label})"
- def sorting_key(node):
- return node.priority
- test_nodes = [Test_Node(n) for n in range(4)]
- G = nx.DiGraph()
- edges = [(0, 1), (0, 2), (0, 3), (2, 3)]
- G.add_edges_from((test_nodes[a], test_nodes[b]) for a, b in edges)
- sorting = list(nx.lexicographical_topological_sort(G, key=sorting_key))
- assert sorting == test_nodes
- def test_topological_generations():
- G = nx.DiGraph(
- {1: [2, 3], 2: [4, 5], 3: [7], 4: [], 5: [6, 7], 6: [], 7: []}
- ).reverse()
- # order within each generation is inconsequential
- generations = [sorted(gen) for gen in nx.topological_generations(G)]
- expected = [[4, 6, 7], [3, 5], [2], [1]]
- assert generations == expected
- MG = nx.MultiDiGraph(G.edges)
- MG.add_edge(2, 1)
- generations = [sorted(gen) for gen in nx.topological_generations(MG)]
- assert generations == expected
- def test_topological_generations_empty():
- G = nx.DiGraph()
- assert list(nx.topological_generations(G)) == []
- def test_topological_generations_cycle():
- G = nx.DiGraph([[2, 1], [3, 1], [1, 2]])
- with pytest.raises(nx.NetworkXUnfeasible):
- list(nx.topological_generations(G))
- def test_is_aperiodic_cycle():
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- assert not nx.is_aperiodic(G)
- def test_is_aperiodic_cycle2():
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- nx.add_cycle(G, [3, 4, 5, 6, 7])
- assert nx.is_aperiodic(G)
- def test_is_aperiodic_cycle3():
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- nx.add_cycle(G, [3, 4, 5, 6])
- assert not nx.is_aperiodic(G)
- def test_is_aperiodic_cycle4():
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- G.add_edge(1, 3)
- assert nx.is_aperiodic(G)
- def test_is_aperiodic_selfloop():
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- G.add_edge(1, 1)
- assert nx.is_aperiodic(G)
- def test_is_aperiodic_raise():
- G = nx.Graph()
- pytest.raises(nx.NetworkXError, nx.is_aperiodic, G)
- def test_is_aperiodic_bipartite():
- # Bipartite graph
- G = nx.DiGraph(nx.davis_southern_women_graph())
- assert not nx.is_aperiodic(G)
- def test_is_aperiodic_rary_tree():
- G = nx.full_rary_tree(3, 27, create_using=nx.DiGraph())
- assert not nx.is_aperiodic(G)
- def test_is_aperiodic_disconnected():
- # disconnected graph
- G = nx.DiGraph()
- nx.add_cycle(G, [1, 2, 3, 4])
- nx.add_cycle(G, [5, 6, 7, 8])
- assert not nx.is_aperiodic(G)
- G.add_edge(1, 3)
- G.add_edge(5, 7)
- assert nx.is_aperiodic(G)
- def test_is_aperiodic_disconnected2():
- G = nx.DiGraph()
- nx.add_cycle(G, [0, 1, 2])
- G.add_edge(3, 3)
- assert not nx.is_aperiodic(G)
- class TestDagToBranching:
- """Unit tests for the :func:`networkx.dag_to_branching` function."""
- def test_single_root(self):
- """Tests that a directed acyclic graph with a single degree
- zero node produces an arborescence.
- """
- G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)])
- B = nx.dag_to_branching(G)
- expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4)])
- assert nx.is_arborescence(B)
- assert nx.is_isomorphic(B, expected)
- def test_multiple_roots(self):
- """Tests that a directed acyclic graph with multiple degree zero
- nodes creates an arborescence with multiple (weakly) connected
- components.
- """
- G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3), (5, 2)])
- B = nx.dag_to_branching(G)
- expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4), (5, 6), (6, 7)])
- assert nx.is_branching(B)
- assert not nx.is_arborescence(B)
- assert nx.is_isomorphic(B, expected)
- # # Attributes are not copied by this function. If they were, this would
- # # be a good test to uncomment.
- # def test_copy_attributes(self):
- # """Tests that node attributes are copied in the branching."""
- # G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)])
- # for v in G:
- # G.node[v]['label'] = str(v)
- # B = nx.dag_to_branching(G)
- # # Determine the root node of the branching.
- # root = next(v for v, d in B.in_degree() if d == 0)
- # assert_equal(B.node[root]['label'], '0')
- # children = B[root]
- # # Get the left and right children, nodes 1 and 2, respectively.
- # left, right = sorted(children, key=lambda v: B.node[v]['label'])
- # assert_equal(B.node[left]['label'], '1')
- # assert_equal(B.node[right]['label'], '2')
- # # Get the left grandchild.
- # children = B[left]
- # assert_equal(len(children), 1)
- # left_grandchild = arbitrary_element(children)
- # assert_equal(B.node[left_grandchild]['label'], '3')
- # # Get the right grandchild.
- # children = B[right]
- # assert_equal(len(children), 1)
- # right_grandchild = arbitrary_element(children)
- # assert_equal(B.node[right_grandchild]['label'], '3')
- def test_already_arborescence(self):
- """Tests that a directed acyclic graph that is already an
- arborescence produces an isomorphic arborescence as output.
- """
- A = nx.balanced_tree(2, 2, create_using=nx.DiGraph())
- B = nx.dag_to_branching(A)
- assert nx.is_isomorphic(A, B)
- def test_already_branching(self):
- """Tests that a directed acyclic graph that is already a
- branching produces an isomorphic branching as output.
- """
- T1 = nx.balanced_tree(2, 2, create_using=nx.DiGraph())
- T2 = nx.balanced_tree(2, 2, create_using=nx.DiGraph())
- G = nx.disjoint_union(T1, T2)
- B = nx.dag_to_branching(G)
- assert nx.is_isomorphic(G, B)
- def test_not_acyclic(self):
- """Tests that a non-acyclic graph causes an exception."""
- with pytest.raises(nx.HasACycle):
- G = nx.DiGraph(pairwise("abc", cyclic=True))
- nx.dag_to_branching(G)
- def test_undirected(self):
- with pytest.raises(nx.NetworkXNotImplemented):
- nx.dag_to_branching(nx.Graph())
- def test_multigraph(self):
- with pytest.raises(nx.NetworkXNotImplemented):
- nx.dag_to_branching(nx.MultiGraph())
- def test_multidigraph(self):
- with pytest.raises(nx.NetworkXNotImplemented):
- nx.dag_to_branching(nx.MultiDiGraph())
- def test_ancestors_descendants_undirected():
- """Regression test to ensure anscestors and descendants work as expected on
- undirected graphs."""
- G = nx.path_graph(5)
- nx.ancestors(G, 2) == nx.descendants(G, 2) == {0, 1, 3, 4}
- def test_compute_v_structures_raise():
- G = nx.Graph()
- pytest.raises(nx.NetworkXNotImplemented, nx.compute_v_structures, G)
- def test_compute_v_structures():
- edges = [(0, 1), (0, 2), (3, 2)]
- G = nx.DiGraph(edges)
- v_structs = set(nx.compute_v_structures(G))
- assert len(v_structs) == 1
- assert (0, 2, 3) in v_structs
- edges = [("A", "B"), ("C", "B"), ("B", "D"), ("D", "E"), ("G", "E")]
- G = nx.DiGraph(edges)
- v_structs = set(nx.compute_v_structures(G))
- assert len(v_structs) == 2
|