aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py25
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_bfs.py203
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_dfs.py305
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py147
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py131
6 files changed, 811 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/__init__.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py
new file mode 100644
index 00000000..049f116b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py
@@ -0,0 +1,25 @@
+"""Unit tests for the beam search functions."""
+
+import pytest
+
+import networkx as nx
+
+
+def test_narrow():
+ """Tests that a narrow beam width may cause an incomplete search."""
+ # In this search, we enqueue only the neighbor 3 at the first
+ # step, then only the neighbor 2 at the second step. Once at
+ # node 2, the search chooses node 3, since it has a higher value
+ # than node 1, but node 3 has already been visited, so the
+ # search terminates.
+ G = nx.cycle_graph(4)
+ edges = nx.bfs_beam_edges(G, source=0, value=lambda n: n, width=1)
+ assert list(edges) == [(0, 3), (3, 2)]
+
+
+@pytest.mark.parametrize("width", (2, None))
+def test_wide(width):
+ """All nodes are searched when `width` is None or >= max degree"""
+ G = nx.cycle_graph(4)
+ edges = nx.bfs_beam_edges(G, source=0, value=lambda n: n, width=width)
+ assert list(edges) == [(0, 3), (0, 1), (3, 2)]
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_bfs.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_bfs.py
new file mode 100644
index 00000000..fcfbbc68
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_bfs.py
@@ -0,0 +1,203 @@
+from functools import partial
+
+import pytest
+
+import networkx as nx
+
+
+class TestBFS:
+ @classmethod
+ def setup_class(cls):
+ # simple graph
+ G = nx.Graph()
+ G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
+ cls.G = G
+
+ def test_successor(self):
+ assert dict(nx.bfs_successors(self.G, source=0)) == {0: [1], 1: [2, 3], 2: [4]}
+
+ def test_predecessor(self):
+ assert dict(nx.bfs_predecessors(self.G, source=0)) == {1: 0, 2: 1, 3: 1, 4: 2}
+
+ def test_bfs_tree(self):
+ T = nx.bfs_tree(self.G, source=0)
+ assert sorted(T.nodes()) == sorted(self.G.nodes())
+ assert sorted(T.edges()) == [(0, 1), (1, 2), (1, 3), (2, 4)]
+
+ def test_bfs_edges(self):
+ edges = nx.bfs_edges(self.G, source=0)
+ assert list(edges) == [(0, 1), (1, 2), (1, 3), (2, 4)]
+
+ def test_bfs_edges_reverse(self):
+ D = nx.DiGraph()
+ D.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
+ edges = nx.bfs_edges(D, source=4, reverse=True)
+ assert list(edges) == [(4, 2), (4, 3), (2, 1), (1, 0)]
+
+ def test_bfs_edges_sorting(self):
+ D = nx.DiGraph()
+ D.add_edges_from([(0, 1), (0, 2), (1, 4), (1, 3), (2, 5)])
+ sort_desc = partial(sorted, reverse=True)
+ edges_asc = nx.bfs_edges(D, source=0, sort_neighbors=sorted)
+ edges_desc = nx.bfs_edges(D, source=0, sort_neighbors=sort_desc)
+ assert list(edges_asc) == [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5)]
+ assert list(edges_desc) == [(0, 2), (0, 1), (2, 5), (1, 4), (1, 3)]
+
+ def test_bfs_tree_isolates(self):
+ G = nx.Graph()
+ G.add_node(1)
+ G.add_node(2)
+ T = nx.bfs_tree(G, source=1)
+ assert sorted(T.nodes()) == [1]
+ assert sorted(T.edges()) == []
+
+ def test_bfs_layers(self):
+ expected = {
+ 0: [0],
+ 1: [1],
+ 2: [2, 3],
+ 3: [4],
+ }
+ assert dict(enumerate(nx.bfs_layers(self.G, sources=[0]))) == expected
+ assert dict(enumerate(nx.bfs_layers(self.G, sources=0))) == expected
+
+ def test_bfs_layers_missing_source(self):
+ with pytest.raises(nx.NetworkXError):
+ next(nx.bfs_layers(self.G, sources="abc"))
+ with pytest.raises(nx.NetworkXError):
+ next(nx.bfs_layers(self.G, sources=["abc"]))
+
+ def test_descendants_at_distance(self):
+ for distance, descendants in enumerate([{0}, {1}, {2, 3}, {4}]):
+ assert nx.descendants_at_distance(self.G, 0, distance) == descendants
+
+ def test_descendants_at_distance_missing_source(self):
+ with pytest.raises(nx.NetworkXError):
+ nx.descendants_at_distance(self.G, "abc", 0)
+
+ def test_bfs_labeled_edges_directed(self):
+ D = nx.cycle_graph(5, create_using=nx.DiGraph)
+ expected = [
+ (0, 1, "tree"),
+ (1, 2, "tree"),
+ (2, 3, "tree"),
+ (3, 4, "tree"),
+ (4, 0, "reverse"),
+ ]
+ answer = list(nx.bfs_labeled_edges(D, 0))
+ assert expected == answer
+
+ D.add_edge(4, 4)
+ expected.append((4, 4, "level"))
+ answer = list(nx.bfs_labeled_edges(D, 0))
+ assert expected == answer
+
+ D.add_edge(0, 2)
+ D.add_edge(1, 5)
+ D.add_edge(2, 5)
+ D.remove_edge(4, 4)
+ expected = [
+ (0, 1, "tree"),
+ (0, 2, "tree"),
+ (1, 2, "level"),
+ (1, 5, "tree"),
+ (2, 3, "tree"),
+ (2, 5, "forward"),
+ (3, 4, "tree"),
+ (4, 0, "reverse"),
+ ]
+ answer = list(nx.bfs_labeled_edges(D, 0))
+ assert expected == answer
+
+ G = D.to_undirected()
+ G.add_edge(4, 4)
+ expected = [
+ (0, 1, "tree"),
+ (0, 2, "tree"),
+ (0, 4, "tree"),
+ (1, 2, "level"),
+ (1, 5, "tree"),
+ (2, 3, "tree"),
+ (2, 5, "forward"),
+ (4, 3, "forward"),
+ (4, 4, "level"),
+ ]
+ answer = list(nx.bfs_labeled_edges(G, 0))
+ assert expected == answer
+
+
+class TestBreadthLimitedSearch:
+ @classmethod
+ def setup_class(cls):
+ # a tree
+ G = nx.Graph()
+ nx.add_path(G, [0, 1, 2, 3, 4, 5, 6])
+ nx.add_path(G, [2, 7, 8, 9, 10])
+ cls.G = G
+ # a disconnected graph
+ D = nx.Graph()
+ D.add_edges_from([(0, 1), (2, 3)])
+ nx.add_path(D, [2, 7, 8, 9, 10])
+ cls.D = D
+
+ def test_limited_bfs_successor(self):
+ assert dict(nx.bfs_successors(self.G, source=1, depth_limit=3)) == {
+ 1: [0, 2],
+ 2: [3, 7],
+ 3: [4],
+ 7: [8],
+ }
+ result = {
+ n: sorted(s) for n, s in nx.bfs_successors(self.D, source=7, depth_limit=2)
+ }
+ assert result == {8: [9], 2: [3], 7: [2, 8]}
+
+ def test_limited_bfs_predecessor(self):
+ assert dict(nx.bfs_predecessors(self.G, source=1, depth_limit=3)) == {
+ 0: 1,
+ 2: 1,
+ 3: 2,
+ 4: 3,
+ 7: 2,
+ 8: 7,
+ }
+ assert dict(nx.bfs_predecessors(self.D, source=7, depth_limit=2)) == {
+ 2: 7,
+ 3: 2,
+ 8: 7,
+ 9: 8,
+ }
+
+ def test_limited_bfs_tree(self):
+ T = nx.bfs_tree(self.G, source=3, depth_limit=1)
+ assert sorted(T.edges()) == [(3, 2), (3, 4)]
+
+ def test_limited_bfs_edges(self):
+ edges = nx.bfs_edges(self.G, source=9, depth_limit=4)
+ assert list(edges) == [(9, 8), (9, 10), (8, 7), (7, 2), (2, 1), (2, 3)]
+
+ def test_limited_bfs_layers(self):
+ assert dict(enumerate(nx.bfs_layers(self.G, sources=[0]))) == {
+ 0: [0],
+ 1: [1],
+ 2: [2],
+ 3: [3, 7],
+ 4: [4, 8],
+ 5: [5, 9],
+ 6: [6, 10],
+ }
+ assert dict(enumerate(nx.bfs_layers(self.D, sources=2))) == {
+ 0: [2],
+ 1: [3, 7],
+ 2: [8],
+ 3: [9],
+ 4: [10],
+ }
+
+ def test_limited_descendants_at_distance(self):
+ for distance, descendants in enumerate(
+ [{0}, {1}, {2}, {3, 7}, {4, 8}, {5, 9}, {6, 10}]
+ ):
+ assert nx.descendants_at_distance(self.G, 0, distance) == descendants
+ for distance, descendants in enumerate([{2}, {3, 7}, {8}, {9}, {10}]):
+ assert nx.descendants_at_distance(self.D, 2, distance) == descendants
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_dfs.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_dfs.py
new file mode 100644
index 00000000..e43d7d61
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_dfs.py
@@ -0,0 +1,305 @@
+import networkx as nx
+
+
+class TestDFS:
+ @classmethod
+ def setup_class(cls):
+ # simple graph
+ G = nx.Graph()
+ G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)])
+ cls.G = G
+ # simple graph, disconnected
+ D = nx.Graph()
+ D.add_edges_from([(0, 1), (2, 3)])
+ cls.D = D
+
+ def test_preorder_nodes(self):
+ assert list(nx.dfs_preorder_nodes(self.G, source=0)) == [0, 1, 2, 4, 3]
+ assert list(nx.dfs_preorder_nodes(self.D)) == [0, 1, 2, 3]
+ assert list(nx.dfs_preorder_nodes(self.D, source=2)) == [2, 3]
+
+ def test_postorder_nodes(self):
+ assert list(nx.dfs_postorder_nodes(self.G, source=0)) == [4, 2, 3, 1, 0]
+ assert list(nx.dfs_postorder_nodes(self.D)) == [1, 0, 3, 2]
+ assert list(nx.dfs_postorder_nodes(self.D, source=0)) == [1, 0]
+
+ def test_successor(self):
+ assert nx.dfs_successors(self.G, source=0) == {0: [1], 1: [2, 3], 2: [4]}
+ assert nx.dfs_successors(self.G, source=1) == {0: [3, 4], 1: [0], 4: [2]}
+ assert nx.dfs_successors(self.D) == {0: [1], 2: [3]}
+ assert nx.dfs_successors(self.D, source=1) == {1: [0]}
+
+ def test_predecessor(self):
+ assert nx.dfs_predecessors(self.G, source=0) == {1: 0, 2: 1, 3: 1, 4: 2}
+ assert nx.dfs_predecessors(self.D) == {1: 0, 3: 2}
+
+ def test_dfs_tree(self):
+ exp_nodes = sorted(self.G.nodes())
+ exp_edges = [(0, 1), (1, 2), (1, 3), (2, 4)]
+ # Search from first node
+ T = nx.dfs_tree(self.G, source=0)
+ assert sorted(T.nodes()) == exp_nodes
+ assert sorted(T.edges()) == exp_edges
+ # Check source=None
+ T = nx.dfs_tree(self.G, source=None)
+ assert sorted(T.nodes()) == exp_nodes
+ assert sorted(T.edges()) == exp_edges
+ # Check source=None is the default
+ T = nx.dfs_tree(self.G)
+ assert sorted(T.nodes()) == exp_nodes
+ assert sorted(T.edges()) == exp_edges
+
+ def test_dfs_edges(self):
+ edges = nx.dfs_edges(self.G, source=0)
+ assert list(edges) == [(0, 1), (1, 2), (2, 4), (1, 3)]
+ edges = nx.dfs_edges(self.D)
+ assert list(edges) == [(0, 1), (2, 3)]
+
+ def test_dfs_edges_sorting(self):
+ G = nx.Graph([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)])
+ edges_asc = nx.dfs_edges(G, source=0, sort_neighbors=sorted)
+ sorted_desc = lambda x: sorted(x, reverse=True)
+ edges_desc = nx.dfs_edges(G, source=0, sort_neighbors=sorted_desc)
+ assert list(edges_asc) == [(0, 1), (1, 2), (2, 4), (1, 3)]
+ assert list(edges_desc) == [(0, 4), (4, 2), (2, 1), (1, 3)]
+
+ def test_dfs_labeled_edges(self):
+ edges = list(nx.dfs_labeled_edges(self.G, source=0))
+ forward = [(u, v) for (u, v, d) in edges if d == "forward"]
+ assert forward == [(0, 0), (0, 1), (1, 2), (2, 4), (1, 3)]
+ assert edges == [
+ (0, 0, "forward"),
+ (0, 1, "forward"),
+ (1, 0, "nontree"),
+ (1, 2, "forward"),
+ (2, 1, "nontree"),
+ (2, 4, "forward"),
+ (4, 2, "nontree"),
+ (4, 0, "nontree"),
+ (2, 4, "reverse"),
+ (1, 2, "reverse"),
+ (1, 3, "forward"),
+ (3, 1, "nontree"),
+ (3, 0, "nontree"),
+ (1, 3, "reverse"),
+ (0, 1, "reverse"),
+ (0, 3, "nontree"),
+ (0, 4, "nontree"),
+ (0, 0, "reverse"),
+ ]
+
+ def test_dfs_labeled_edges_sorting(self):
+ G = nx.Graph([(0, 1), (1, 2), (1, 3), (2, 4), (3, 0), (0, 4)])
+ edges_asc = nx.dfs_labeled_edges(G, source=0, sort_neighbors=sorted)
+ sorted_desc = lambda x: sorted(x, reverse=True)
+ edges_desc = nx.dfs_labeled_edges(G, source=0, sort_neighbors=sorted_desc)
+ assert list(edges_asc) == [
+ (0, 0, "forward"),
+ (0, 1, "forward"),
+ (1, 0, "nontree"),
+ (1, 2, "forward"),
+ (2, 1, "nontree"),
+ (2, 4, "forward"),
+ (4, 0, "nontree"),
+ (4, 2, "nontree"),
+ (2, 4, "reverse"),
+ (1, 2, "reverse"),
+ (1, 3, "forward"),
+ (3, 0, "nontree"),
+ (3, 1, "nontree"),
+ (1, 3, "reverse"),
+ (0, 1, "reverse"),
+ (0, 3, "nontree"),
+ (0, 4, "nontree"),
+ (0, 0, "reverse"),
+ ]
+ assert list(edges_desc) == [
+ (0, 0, "forward"),
+ (0, 4, "forward"),
+ (4, 2, "forward"),
+ (2, 4, "nontree"),
+ (2, 1, "forward"),
+ (1, 3, "forward"),
+ (3, 1, "nontree"),
+ (3, 0, "nontree"),
+ (1, 3, "reverse"),
+ (1, 2, "nontree"),
+ (1, 0, "nontree"),
+ (2, 1, "reverse"),
+ (4, 2, "reverse"),
+ (4, 0, "nontree"),
+ (0, 4, "reverse"),
+ (0, 3, "nontree"),
+ (0, 1, "nontree"),
+ (0, 0, "reverse"),
+ ]
+
+ def test_dfs_labeled_disconnected_edges(self):
+ edges = list(nx.dfs_labeled_edges(self.D))
+ forward = [(u, v) for (u, v, d) in edges if d == "forward"]
+ assert forward == [(0, 0), (0, 1), (2, 2), (2, 3)]
+ assert edges == [
+ (0, 0, "forward"),
+ (0, 1, "forward"),
+ (1, 0, "nontree"),
+ (0, 1, "reverse"),
+ (0, 0, "reverse"),
+ (2, 2, "forward"),
+ (2, 3, "forward"),
+ (3, 2, "nontree"),
+ (2, 3, "reverse"),
+ (2, 2, "reverse"),
+ ]
+
+ def test_dfs_tree_isolates(self):
+ G = nx.Graph()
+ G.add_node(1)
+ G.add_node(2)
+ T = nx.dfs_tree(G, source=1)
+ assert sorted(T.nodes()) == [1]
+ assert sorted(T.edges()) == []
+ T = nx.dfs_tree(G, source=None)
+ assert sorted(T.nodes()) == [1, 2]
+ assert sorted(T.edges()) == []
+
+
+class TestDepthLimitedSearch:
+ @classmethod
+ def setup_class(cls):
+ # a tree
+ G = nx.Graph()
+ nx.add_path(G, [0, 1, 2, 3, 4, 5, 6])
+ nx.add_path(G, [2, 7, 8, 9, 10])
+ cls.G = G
+ # a disconnected graph
+ D = nx.Graph()
+ D.add_edges_from([(0, 1), (2, 3)])
+ nx.add_path(D, [2, 7, 8, 9, 10])
+ cls.D = D
+
+ def test_dls_preorder_nodes(self):
+ assert list(nx.dfs_preorder_nodes(self.G, source=0, depth_limit=2)) == [0, 1, 2]
+ assert list(nx.dfs_preorder_nodes(self.D, source=1, depth_limit=2)) == ([1, 0])
+
+ def test_dls_postorder_nodes(self):
+ assert list(nx.dfs_postorder_nodes(self.G, source=3, depth_limit=3)) == [
+ 1,
+ 7,
+ 2,
+ 5,
+ 4,
+ 3,
+ ]
+ assert list(nx.dfs_postorder_nodes(self.D, source=2, depth_limit=2)) == (
+ [3, 7, 2]
+ )
+
+ def test_dls_successor(self):
+ result = nx.dfs_successors(self.G, source=4, depth_limit=3)
+ assert {n: set(v) for n, v in result.items()} == {
+ 2: {1, 7},
+ 3: {2},
+ 4: {3, 5},
+ 5: {6},
+ }
+ result = nx.dfs_successors(self.D, source=7, depth_limit=2)
+ assert {n: set(v) for n, v in result.items()} == {8: {9}, 2: {3}, 7: {8, 2}}
+
+ def test_dls_predecessor(self):
+ assert nx.dfs_predecessors(self.G, source=0, depth_limit=3) == {
+ 1: 0,
+ 2: 1,
+ 3: 2,
+ 7: 2,
+ }
+ assert nx.dfs_predecessors(self.D, source=2, depth_limit=3) == {
+ 8: 7,
+ 9: 8,
+ 3: 2,
+ 7: 2,
+ }
+
+ def test_dls_tree(self):
+ T = nx.dfs_tree(self.G, source=3, depth_limit=1)
+ assert sorted(T.edges()) == [(3, 2), (3, 4)]
+
+ def test_dls_edges(self):
+ edges = nx.dfs_edges(self.G, source=9, depth_limit=4)
+ assert list(edges) == [(9, 8), (8, 7), (7, 2), (2, 1), (2, 3), (9, 10)]
+
+ def test_dls_labeled_edges_depth_1(self):
+ edges = list(nx.dfs_labeled_edges(self.G, source=5, depth_limit=1))
+ forward = [(u, v) for (u, v, d) in edges if d == "forward"]
+ assert forward == [(5, 5), (5, 4), (5, 6)]
+ # Note: reverse-depth_limit edge types were not reported before gh-6240
+ assert edges == [
+ (5, 5, "forward"),
+ (5, 4, "forward"),
+ (5, 4, "reverse-depth_limit"),
+ (5, 6, "forward"),
+ (5, 6, "reverse-depth_limit"),
+ (5, 5, "reverse"),
+ ]
+
+ def test_dls_labeled_edges_depth_2(self):
+ edges = list(nx.dfs_labeled_edges(self.G, source=6, depth_limit=2))
+ forward = [(u, v) for (u, v, d) in edges if d == "forward"]
+ assert forward == [(6, 6), (6, 5), (5, 4)]
+ assert edges == [
+ (6, 6, "forward"),
+ (6, 5, "forward"),
+ (5, 4, "forward"),
+ (5, 4, "reverse-depth_limit"),
+ (5, 6, "nontree"),
+ (6, 5, "reverse"),
+ (6, 6, "reverse"),
+ ]
+
+ def test_dls_labeled_disconnected_edges(self):
+ edges = list(nx.dfs_labeled_edges(self.D, depth_limit=1))
+ assert edges == [
+ (0, 0, "forward"),
+ (0, 1, "forward"),
+ (0, 1, "reverse-depth_limit"),
+ (0, 0, "reverse"),
+ (2, 2, "forward"),
+ (2, 3, "forward"),
+ (2, 3, "reverse-depth_limit"),
+ (2, 7, "forward"),
+ (2, 7, "reverse-depth_limit"),
+ (2, 2, "reverse"),
+ (8, 8, "forward"),
+ (8, 7, "nontree"),
+ (8, 9, "forward"),
+ (8, 9, "reverse-depth_limit"),
+ (8, 8, "reverse"),
+ (10, 10, "forward"),
+ (10, 9, "nontree"),
+ (10, 10, "reverse"),
+ ]
+ # large depth_limit has no impact
+ edges = list(nx.dfs_labeled_edges(self.D, depth_limit=19))
+ assert edges == [
+ (0, 0, "forward"),
+ (0, 1, "forward"),
+ (1, 0, "nontree"),
+ (0, 1, "reverse"),
+ (0, 0, "reverse"),
+ (2, 2, "forward"),
+ (2, 3, "forward"),
+ (3, 2, "nontree"),
+ (2, 3, "reverse"),
+ (2, 7, "forward"),
+ (7, 2, "nontree"),
+ (7, 8, "forward"),
+ (8, 7, "nontree"),
+ (8, 9, "forward"),
+ (9, 8, "nontree"),
+ (9, 10, "forward"),
+ (10, 9, "nontree"),
+ (9, 10, "reverse"),
+ (8, 9, "reverse"),
+ (7, 8, "reverse"),
+ (2, 7, "reverse"),
+ (2, 2, "reverse"),
+ ]
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py
new file mode 100644
index 00000000..1bf3fae0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py
@@ -0,0 +1,147 @@
+import pytest
+
+import networkx as nx
+from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE
+
+
+class TestEdgeBFS:
+ @classmethod
+ def setup_class(cls):
+ cls.nodes = [0, 1, 2, 3]
+ cls.edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)]
+
+ def test_empty(self):
+ G = nx.Graph()
+ edges = list(nx.edge_bfs(G))
+ assert edges == []
+
+ def test_graph_single_source(self):
+ G = nx.Graph(self.edges)
+ G.add_edge(4, 5)
+ x = list(nx.edge_bfs(G, [0]))
+ x_ = [(0, 1), (0, 2), (1, 2), (1, 3)]
+ assert x == x_
+
+ def test_graph(self):
+ G = nx.Graph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes))
+ x_ = [(0, 1), (0, 2), (1, 2), (1, 3)]
+ assert x == x_
+
+ def test_digraph(self):
+ G = nx.DiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes))
+ x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)]
+ assert x == x_
+
+ def test_digraph_orientation_invalid(self):
+ G = nx.DiGraph(self.edges)
+ edge_iterator = nx.edge_bfs(G, self.nodes, orientation="hello")
+ pytest.raises(nx.NetworkXError, list, edge_iterator)
+
+ def test_digraph_orientation_none(self):
+ G = nx.DiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation=None))
+ x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)]
+ assert x == x_
+
+ def test_digraph_orientation_original(self):
+ G = nx.DiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation="original"))
+ x_ = [
+ (0, 1, FORWARD),
+ (1, 0, FORWARD),
+ (2, 0, FORWARD),
+ (2, 1, FORWARD),
+ (3, 1, FORWARD),
+ ]
+ assert x == x_
+
+ def test_digraph2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(nx.edge_bfs(G, [0]))
+ x_ = [(0, 1), (1, 2), (2, 3)]
+ assert x == x_
+
+ def test_digraph_rev(self):
+ G = nx.DiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation="reverse"))
+ x_ = [
+ (1, 0, REVERSE),
+ (2, 0, REVERSE),
+ (0, 1, REVERSE),
+ (2, 1, REVERSE),
+ (3, 1, REVERSE),
+ ]
+ assert x == x_
+
+ def test_digraph_rev2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(nx.edge_bfs(G, [3], orientation="reverse"))
+ x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)]
+ assert x == x_
+
+ def test_multigraph(self):
+ G = nx.MultiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes))
+ x_ = [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)]
+ # This is an example of where hash randomization can break.
+ # There are 3! * 2 alternative outputs, such as:
+ # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)]
+ # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k)
+ # edges. So the algorithm only guarantees a partial order. A total
+ # order is guaranteed only if the graph data structures are ordered.
+ assert x == x_
+
+ def test_multidigraph(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes))
+ x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)]
+ assert x == x_
+
+ def test_multidigraph_rev(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation="reverse"))
+ x_ = [
+ (1, 0, 0, REVERSE),
+ (1, 0, 1, REVERSE),
+ (2, 0, 0, REVERSE),
+ (0, 1, 0, REVERSE),
+ (2, 1, 0, REVERSE),
+ (3, 1, 0, REVERSE),
+ ]
+ assert x == x_
+
+ def test_digraph_ignore(self):
+ G = nx.DiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation="ignore"))
+ x_ = [
+ (0, 1, FORWARD),
+ (1, 0, REVERSE),
+ (2, 0, REVERSE),
+ (2, 1, REVERSE),
+ (3, 1, REVERSE),
+ ]
+ assert x == x_
+
+ def test_digraph_ignore2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(nx.edge_bfs(G, [0], orientation="ignore"))
+ x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)]
+ assert x == x_
+
+ def test_multidigraph_ignore(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(nx.edge_bfs(G, self.nodes, orientation="ignore"))
+ x_ = [
+ (0, 1, 0, FORWARD),
+ (1, 0, 0, REVERSE),
+ (1, 0, 1, REVERSE),
+ (2, 0, 0, REVERSE),
+ (2, 1, 0, REVERSE),
+ (3, 1, 0, REVERSE),
+ ]
+ assert x == x_
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py
new file mode 100644
index 00000000..7c1967cc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py
@@ -0,0 +1,131 @@
+import pytest
+
+import networkx as nx
+from networkx.algorithms import edge_dfs
+from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE
+
+# These tests can fail with hash randomization. The easiest and clearest way
+# to write these unit tests is for the edges to be output in an expected total
+# order, but we cannot guarantee the order amongst outgoing edges from a node,
+# unless each class uses an ordered data structure for neighbors. This is
+# painful to do with the current API. The alternative is that the tests are
+# written (IMO confusingly) so that there is not a total order over the edges,
+# but only a partial order. Due to the small size of the graphs, hopefully
+# failures due to hash randomization will not occur. For an example of how
+# this can fail, see TestEdgeDFS.test_multigraph.
+
+
+class TestEdgeDFS:
+ @classmethod
+ def setup_class(cls):
+ cls.nodes = [0, 1, 2, 3]
+ cls.edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)]
+
+ def test_empty(self):
+ G = nx.Graph()
+ edges = list(edge_dfs(G))
+ assert edges == []
+
+ def test_graph(self):
+ G = nx.Graph(self.edges)
+ x = list(edge_dfs(G, self.nodes))
+ x_ = [(0, 1), (1, 2), (1, 3)]
+ assert x == x_
+
+ def test_digraph(self):
+ G = nx.DiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes))
+ x_ = [(0, 1), (1, 0), (2, 1), (3, 1)]
+ assert x == x_
+
+ def test_digraph_orientation_invalid(self):
+ G = nx.DiGraph(self.edges)
+ edge_iterator = edge_dfs(G, self.nodes, orientation="hello")
+ pytest.raises(nx.NetworkXError, list, edge_iterator)
+
+ def test_digraph_orientation_none(self):
+ G = nx.DiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation=None))
+ x_ = [(0, 1), (1, 0), (2, 1), (3, 1)]
+ assert x == x_
+
+ def test_digraph_orientation_original(self):
+ G = nx.DiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation="original"))
+ x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, FORWARD), (3, 1, FORWARD)]
+ assert x == x_
+
+ def test_digraph2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(edge_dfs(G, [0]))
+ x_ = [(0, 1), (1, 2), (2, 3)]
+ assert x == x_
+
+ def test_digraph_rev(self):
+ G = nx.DiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation="reverse"))
+ x_ = [(1, 0, REVERSE), (0, 1, REVERSE), (2, 1, REVERSE), (3, 1, REVERSE)]
+ assert x == x_
+
+ def test_digraph_rev2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(edge_dfs(G, [3], orientation="reverse"))
+ x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)]
+ assert x == x_
+
+ def test_multigraph(self):
+ G = nx.MultiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes))
+ x_ = [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)]
+ # This is an example of where hash randomization can break.
+ # There are 3! * 2 alternative outputs, such as:
+ # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)]
+ # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k)
+ # edges. So the algorithm only guarantees a partial order. A total
+ # order is guaranteed only if the graph data structures are ordered.
+ assert x == x_
+
+ def test_multidigraph(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes))
+ x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)]
+ assert x == x_
+
+ def test_multidigraph_rev(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation="reverse"))
+ x_ = [
+ (1, 0, 0, REVERSE),
+ (0, 1, 0, REVERSE),
+ (1, 0, 1, REVERSE),
+ (2, 1, 0, REVERSE),
+ (3, 1, 0, REVERSE),
+ ]
+ assert x == x_
+
+ def test_digraph_ignore(self):
+ G = nx.DiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation="ignore"))
+ x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 1, REVERSE), (3, 1, REVERSE)]
+ assert x == x_
+
+ def test_digraph_ignore2(self):
+ G = nx.DiGraph()
+ nx.add_path(G, range(4))
+ x = list(edge_dfs(G, [0], orientation="ignore"))
+ x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)]
+ assert x == x_
+
+ def test_multidigraph_ignore(self):
+ G = nx.MultiDiGraph(self.edges)
+ x = list(edge_dfs(G, self.nodes, orientation="ignore"))
+ x_ = [
+ (0, 1, 0, FORWARD),
+ (1, 0, 0, FORWARD),
+ (1, 0, 1, REVERSE),
+ (2, 1, 0, REVERSE),
+ (3, 1, 0, REVERSE),
+ ]
+ assert x == x_