aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_all.py328
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_binary.py453
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_product.py491
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_unary.py55
5 files changed, 1327 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/__init__.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_all.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_all.py
new file mode 100644
index 00000000..8ec29c15
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_all.py
@@ -0,0 +1,328 @@
+import pytest
+
+import networkx as nx
+from networkx.utils import edges_equal
+
+
+def test_union_all_attributes():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+
+ j = g.copy()
+ j.graph["name"] = "j"
+ j.graph["attr"] = "attr"
+ j.nodes[0]["x"] = 7
+
+ ghj = nx.union_all([g, h, j], rename=("g", "h", "j"))
+ assert set(ghj.nodes()) == {"h0", "h1", "g0", "g1", "j0", "j1"}
+ for n in ghj:
+ graph, node = n
+ assert ghj.nodes[n] == eval(graph).nodes[int(node)]
+
+ assert ghj.graph["attr"] == "attr"
+ assert ghj.graph["name"] == "j" # j graph attributes take precedent
+
+
+def test_intersection_all():
+ G = nx.Graph()
+ H = nx.Graph()
+ R = nx.Graph(awesome=True)
+ G.add_nodes_from([1, 2, 3, 4])
+ G.add_edge(1, 2)
+ G.add_edge(2, 3)
+ H.add_nodes_from([1, 2, 3, 4])
+ H.add_edge(2, 3)
+ H.add_edge(3, 4)
+ R.add_nodes_from([1, 2, 3, 4])
+ R.add_edge(2, 3)
+ R.add_edge(4, 1)
+ I = nx.intersection_all([G, H, R])
+ assert set(I.nodes()) == {1, 2, 3, 4}
+ assert sorted(I.edges()) == [(2, 3)]
+ assert I.graph == {}
+
+
+def test_intersection_all_different_node_sets():
+ G = nx.Graph()
+ H = nx.Graph()
+ R = nx.Graph()
+ G.add_nodes_from([1, 2, 3, 4, 6, 7])
+ G.add_edge(1, 2)
+ G.add_edge(2, 3)
+ G.add_edge(6, 7)
+ H.add_nodes_from([1, 2, 3, 4])
+ H.add_edge(2, 3)
+ H.add_edge(3, 4)
+ R.add_nodes_from([1, 2, 3, 4, 8, 9])
+ R.add_edge(2, 3)
+ R.add_edge(4, 1)
+ R.add_edge(8, 9)
+ I = nx.intersection_all([G, H, R])
+ assert set(I.nodes()) == {1, 2, 3, 4}
+ assert sorted(I.edges()) == [(2, 3)]
+
+
+def test_intersection_all_attributes():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+
+ gh = nx.intersection_all([g, h])
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == sorted(g.edges())
+
+
+def test_intersection_all_attributes_different_node_sets():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ g.add_node(2)
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+
+ gh = nx.intersection_all([g, h])
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == sorted(g.edges())
+
+
+def test_intersection_all_multigraph_attributes():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=3)
+ gh = nx.intersection_all([g, h])
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == [(0, 1)]
+ assert sorted(gh.edges(keys=True)) == [(0, 1, 0)]
+
+
+def test_intersection_all_multigraph_attributes_different_node_sets():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ g.add_edge(1, 2, key=1)
+ g.add_edge(1, 2, key=2)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=2)
+ h.add_edge(0, 1, key=3)
+ gh = nx.intersection_all([g, h])
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == [(0, 1), (0, 1)]
+ assert sorted(gh.edges(keys=True)) == [(0, 1, 0), (0, 1, 2)]
+
+
+def test_intersection_all_digraph():
+ g = nx.DiGraph()
+ g.add_edges_from([(1, 2), (2, 3)])
+ h = nx.DiGraph()
+ h.add_edges_from([(2, 1), (2, 3)])
+ gh = nx.intersection_all([g, h])
+ assert sorted(gh.edges()) == [(2, 3)]
+
+
+def test_union_all_and_compose_all():
+ K3 = nx.complete_graph(3)
+ P3 = nx.path_graph(3)
+
+ G1 = nx.DiGraph()
+ G1.add_edge("A", "B")
+ G1.add_edge("A", "C")
+ G1.add_edge("A", "D")
+ G2 = nx.DiGraph()
+ G2.add_edge("1", "2")
+ G2.add_edge("1", "3")
+ G2.add_edge("1", "4")
+
+ G = nx.union_all([G1, G2])
+ H = nx.compose_all([G1, G2])
+ assert edges_equal(G.edges(), H.edges())
+ assert not G.has_edge("A", "1")
+ pytest.raises(nx.NetworkXError, nx.union, K3, P3)
+ H1 = nx.union_all([H, G1], rename=("H", "G1"))
+ assert sorted(H1.nodes()) == [
+ "G1A",
+ "G1B",
+ "G1C",
+ "G1D",
+ "H1",
+ "H2",
+ "H3",
+ "H4",
+ "HA",
+ "HB",
+ "HC",
+ "HD",
+ ]
+
+ H2 = nx.union_all([H, G2], rename=("H", ""))
+ assert sorted(H2.nodes()) == [
+ "1",
+ "2",
+ "3",
+ "4",
+ "H1",
+ "H2",
+ "H3",
+ "H4",
+ "HA",
+ "HB",
+ "HC",
+ "HD",
+ ]
+
+ assert not H1.has_edge("NB", "NA")
+
+ G = nx.compose_all([G, G])
+ assert edges_equal(G.edges(), H.edges())
+
+ G2 = nx.union_all([G2, G2], rename=("", "copy"))
+ assert sorted(G2.nodes()) == [
+ "1",
+ "2",
+ "3",
+ "4",
+ "copy1",
+ "copy2",
+ "copy3",
+ "copy4",
+ ]
+
+ assert sorted(G2.neighbors("copy4")) == []
+ assert sorted(G2.neighbors("copy1")) == ["copy2", "copy3", "copy4"]
+ assert len(G) == 8
+ assert nx.number_of_edges(G) == 6
+
+ E = nx.disjoint_union_all([G, G])
+ assert len(E) == 16
+ assert nx.number_of_edges(E) == 12
+
+ E = nx.disjoint_union_all([G1, G2])
+ assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
+
+ G1 = nx.DiGraph()
+ G1.add_edge("A", "B")
+ G2 = nx.DiGraph()
+ G2.add_edge(1, 2)
+ G3 = nx.DiGraph()
+ G3.add_edge(11, 22)
+ G4 = nx.union_all([G1, G2, G3], rename=("G1", "G2", "G3"))
+ assert sorted(G4.nodes()) == ["G1A", "G1B", "G21", "G22", "G311", "G322"]
+
+
+def test_union_all_multigraph():
+ G = nx.MultiGraph()
+ G.add_edge(1, 2, key=0)
+ G.add_edge(1, 2, key=1)
+ H = nx.MultiGraph()
+ H.add_edge(3, 4, key=0)
+ H.add_edge(3, 4, key=1)
+ GH = nx.union_all([G, H])
+ assert set(GH) == set(G) | set(H)
+ assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True))
+
+
+def test_input_output():
+ l = [nx.Graph([(1, 2)]), nx.Graph([(3, 4)], awesome=True)]
+ U = nx.disjoint_union_all(l)
+ assert len(l) == 2
+ assert U.graph["awesome"]
+ C = nx.compose_all(l)
+ assert len(l) == 2
+ l = [nx.Graph([(1, 2)]), nx.Graph([(1, 2)])]
+ R = nx.intersection_all(l)
+ assert len(l) == 2
+
+
+def test_mixed_type_union():
+ with pytest.raises(nx.NetworkXError):
+ G = nx.Graph()
+ H = nx.MultiGraph()
+ I = nx.Graph()
+ U = nx.union_all([G, H, I])
+ with pytest.raises(nx.NetworkXError):
+ X = nx.Graph()
+ Y = nx.DiGraph()
+ XY = nx.union_all([X, Y])
+
+
+def test_mixed_type_disjoint_union():
+ with pytest.raises(nx.NetworkXError):
+ G = nx.Graph()
+ H = nx.MultiGraph()
+ I = nx.Graph()
+ U = nx.disjoint_union_all([G, H, I])
+ with pytest.raises(nx.NetworkXError):
+ X = nx.Graph()
+ Y = nx.DiGraph()
+ XY = nx.disjoint_union_all([X, Y])
+
+
+def test_mixed_type_intersection():
+ with pytest.raises(nx.NetworkXError):
+ G = nx.Graph()
+ H = nx.MultiGraph()
+ I = nx.Graph()
+ U = nx.intersection_all([G, H, I])
+ with pytest.raises(nx.NetworkXError):
+ X = nx.Graph()
+ Y = nx.DiGraph()
+ XY = nx.intersection_all([X, Y])
+
+
+def test_mixed_type_compose():
+ with pytest.raises(nx.NetworkXError):
+ G = nx.Graph()
+ H = nx.MultiGraph()
+ I = nx.Graph()
+ U = nx.compose_all([G, H, I])
+ with pytest.raises(nx.NetworkXError):
+ X = nx.Graph()
+ Y = nx.DiGraph()
+ XY = nx.compose_all([X, Y])
+
+
+def test_empty_union():
+ with pytest.raises(ValueError):
+ nx.union_all([])
+
+
+def test_empty_disjoint_union():
+ with pytest.raises(ValueError):
+ nx.disjoint_union_all([])
+
+
+def test_empty_compose_all():
+ with pytest.raises(ValueError):
+ nx.compose_all([])
+
+
+def test_empty_intersection_all():
+ with pytest.raises(ValueError):
+ nx.intersection_all([])
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_binary.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_binary.py
new file mode 100644
index 00000000..c907cd6f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_binary.py
@@ -0,0 +1,453 @@
+import os
+
+import pytest
+
+import networkx as nx
+from networkx.utils import edges_equal
+
+
+def test_union_attributes():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+
+ gh = nx.union(g, h, rename=("g", "h"))
+ assert set(gh.nodes()) == {"h0", "h1", "g0", "g1"}
+ for n in gh:
+ graph, node = n
+ assert gh.nodes[n] == eval(graph).nodes[int(node)]
+
+ assert gh.graph["attr"] == "attr"
+ assert gh.graph["name"] == "h" # h graph attributes take precedent
+
+
+def test_intersection():
+ G = nx.Graph()
+ H = nx.Graph()
+ G.add_nodes_from([1, 2, 3, 4])
+ G.add_edge(1, 2)
+ G.add_edge(2, 3)
+ H.add_nodes_from([1, 2, 3, 4])
+ H.add_edge(2, 3)
+ H.add_edge(3, 4)
+ I = nx.intersection(G, H)
+ assert set(I.nodes()) == {1, 2, 3, 4}
+ assert sorted(I.edges()) == [(2, 3)]
+
+
+def test_intersection_node_sets_different():
+ G = nx.Graph()
+ H = nx.Graph()
+ G.add_nodes_from([1, 2, 3, 4, 7])
+ G.add_edge(1, 2)
+ G.add_edge(2, 3)
+ H.add_nodes_from([1, 2, 3, 4, 5, 6])
+ H.add_edge(2, 3)
+ H.add_edge(3, 4)
+ H.add_edge(5, 6)
+ I = nx.intersection(G, H)
+ assert set(I.nodes()) == {1, 2, 3, 4}
+ assert sorted(I.edges()) == [(2, 3)]
+
+
+def test_intersection_attributes():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+ gh = nx.intersection(g, h)
+
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == sorted(g.edges())
+
+
+def test_intersection_attributes_node_sets_different():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_node(2, x=3)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+ h.remove_node(2)
+
+ gh = nx.intersection(g, h)
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == sorted(g.edges())
+
+
+def test_intersection_multigraph_attributes():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=3)
+ gh = nx.intersection(g, h)
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == [(0, 1)]
+ assert sorted(gh.edges(keys=True)) == [(0, 1, 0)]
+
+
+def test_intersection_multigraph_attributes_node_set_different():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ g.add_edge(0, 2, key=2)
+ g.add_edge(0, 2, key=1)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=3)
+ gh = nx.intersection(g, h)
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == [(0, 1)]
+ assert sorted(gh.edges(keys=True)) == [(0, 1, 0)]
+
+
+def test_difference():
+ G = nx.Graph()
+ H = nx.Graph()
+ G.add_nodes_from([1, 2, 3, 4])
+ G.add_edge(1, 2)
+ G.add_edge(2, 3)
+ H.add_nodes_from([1, 2, 3, 4])
+ H.add_edge(2, 3)
+ H.add_edge(3, 4)
+ D = nx.difference(G, H)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == [(1, 2)]
+ D = nx.difference(H, G)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == [(3, 4)]
+ D = nx.symmetric_difference(G, H)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == [(1, 2), (3, 4)]
+
+
+def test_difference2():
+ G = nx.Graph()
+ H = nx.Graph()
+ G.add_nodes_from([1, 2, 3, 4])
+ H.add_nodes_from([1, 2, 3, 4])
+ G.add_edge(1, 2)
+ H.add_edge(1, 2)
+ G.add_edge(2, 3)
+ D = nx.difference(G, H)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == [(2, 3)]
+ D = nx.difference(H, G)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == []
+ H.add_edge(3, 4)
+ D = nx.difference(H, G)
+ assert set(D.nodes()) == {1, 2, 3, 4}
+ assert sorted(D.edges()) == [(3, 4)]
+
+
+def test_difference_attributes():
+ g = nx.Graph()
+ g.add_node(0, x=4)
+ g.add_node(1, x=5)
+ g.add_edge(0, 1, size=5)
+ g.graph["name"] = "g"
+
+ h = g.copy()
+ h.graph["name"] = "h"
+ h.graph["attr"] = "attr"
+ h.nodes[0]["x"] = 7
+
+ gh = nx.difference(g, h)
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == []
+ # node and graph data should not be copied over
+ assert gh.nodes.data() != g.nodes.data()
+ assert gh.graph != g.graph
+
+
+def test_difference_multigraph_attributes():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=3)
+ gh = nx.difference(g, h)
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == [(0, 1), (0, 1)]
+ assert sorted(gh.edges(keys=True)) == [(0, 1, 1), (0, 1, 2)]
+
+
+def test_difference_raise():
+ G = nx.path_graph(4)
+ H = nx.path_graph(3)
+ pytest.raises(nx.NetworkXError, nx.difference, G, H)
+ pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H)
+
+
+def test_symmetric_difference_multigraph():
+ g = nx.MultiGraph()
+ g.add_edge(0, 1, key=0)
+ g.add_edge(0, 1, key=1)
+ g.add_edge(0, 1, key=2)
+ h = nx.MultiGraph()
+ h.add_edge(0, 1, key=0)
+ h.add_edge(0, 1, key=3)
+ gh = nx.symmetric_difference(g, h)
+ assert set(gh.nodes()) == set(g.nodes())
+ assert set(gh.nodes()) == set(h.nodes())
+ assert sorted(gh.edges()) == 3 * [(0, 1)]
+ assert sorted(sorted(e) for e in gh.edges(keys=True)) == [
+ [0, 1, 1],
+ [0, 1, 2],
+ [0, 1, 3],
+ ]
+
+
+def test_union_and_compose():
+ K3 = nx.complete_graph(3)
+ P3 = nx.path_graph(3)
+
+ G1 = nx.DiGraph()
+ G1.add_edge("A", "B")
+ G1.add_edge("A", "C")
+ G1.add_edge("A", "D")
+ G2 = nx.DiGraph()
+ G2.add_edge("1", "2")
+ G2.add_edge("1", "3")
+ G2.add_edge("1", "4")
+
+ G = nx.union(G1, G2)
+ H = nx.compose(G1, G2)
+ assert edges_equal(G.edges(), H.edges())
+ assert not G.has_edge("A", 1)
+ pytest.raises(nx.NetworkXError, nx.union, K3, P3)
+ H1 = nx.union(H, G1, rename=("H", "G1"))
+ assert sorted(H1.nodes()) == [
+ "G1A",
+ "G1B",
+ "G1C",
+ "G1D",
+ "H1",
+ "H2",
+ "H3",
+ "H4",
+ "HA",
+ "HB",
+ "HC",
+ "HD",
+ ]
+
+ H2 = nx.union(H, G2, rename=("H", ""))
+ assert sorted(H2.nodes()) == [
+ "1",
+ "2",
+ "3",
+ "4",
+ "H1",
+ "H2",
+ "H3",
+ "H4",
+ "HA",
+ "HB",
+ "HC",
+ "HD",
+ ]
+
+ assert not H1.has_edge("NB", "NA")
+
+ G = nx.compose(G, G)
+ assert edges_equal(G.edges(), H.edges())
+
+ G2 = nx.union(G2, G2, rename=("", "copy"))
+ assert sorted(G2.nodes()) == [
+ "1",
+ "2",
+ "3",
+ "4",
+ "copy1",
+ "copy2",
+ "copy3",
+ "copy4",
+ ]
+
+ assert sorted(G2.neighbors("copy4")) == []
+ assert sorted(G2.neighbors("copy1")) == ["copy2", "copy3", "copy4"]
+ assert len(G) == 8
+ assert nx.number_of_edges(G) == 6
+
+ E = nx.disjoint_union(G, G)
+ assert len(E) == 16
+ assert nx.number_of_edges(E) == 12
+
+ E = nx.disjoint_union(G1, G2)
+ assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
+
+ G = nx.Graph()
+ H = nx.Graph()
+ G.add_nodes_from([(1, {"a1": 1})])
+ H.add_nodes_from([(1, {"b1": 1})])
+ R = nx.compose(G, H)
+ assert R.nodes == {1: {"a1": 1, "b1": 1}}
+
+
+def test_union_multigraph():
+ G = nx.MultiGraph()
+ G.add_edge(1, 2, key=0)
+ G.add_edge(1, 2, key=1)
+ H = nx.MultiGraph()
+ H.add_edge(3, 4, key=0)
+ H.add_edge(3, 4, key=1)
+ GH = nx.union(G, H)
+ assert set(GH) == set(G) | set(H)
+ assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True))
+
+
+def test_disjoint_union_multigraph():
+ G = nx.MultiGraph()
+ G.add_edge(0, 1, key=0)
+ G.add_edge(0, 1, key=1)
+ H = nx.MultiGraph()
+ H.add_edge(2, 3, key=0)
+ H.add_edge(2, 3, key=1)
+ GH = nx.disjoint_union(G, H)
+ assert set(GH) == set(G) | set(H)
+ assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True))
+
+
+def test_compose_multigraph():
+ G = nx.MultiGraph()
+ G.add_edge(1, 2, key=0)
+ G.add_edge(1, 2, key=1)
+ H = nx.MultiGraph()
+ H.add_edge(3, 4, key=0)
+ H.add_edge(3, 4, key=1)
+ GH = nx.compose(G, H)
+ assert set(GH) == set(G) | set(H)
+ assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True))
+ H.add_edge(1, 2, key=2)
+ GH = nx.compose(G, H)
+ assert set(GH) == set(G) | set(H)
+ assert set(GH.edges(keys=True)) == set(G.edges(keys=True)) | set(H.edges(keys=True))
+
+
+def test_full_join_graph():
+ # Simple Graphs
+ G = nx.Graph()
+ G.add_node(0)
+ G.add_edge(1, 2)
+ H = nx.Graph()
+ H.add_edge(3, 4)
+
+ U = nx.full_join(G, H)
+ assert set(U) == set(G) | set(H)
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H)
+
+ # Rename
+ U = nx.full_join(G, H, rename=("g", "h"))
+ assert set(U) == {"g0", "g1", "g2", "h3", "h4"}
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H)
+
+ # Rename graphs with string-like nodes
+ G = nx.Graph()
+ G.add_node("a")
+ G.add_edge("b", "c")
+ H = nx.Graph()
+ H.add_edge("d", "e")
+
+ U = nx.full_join(G, H, rename=("g", "h"))
+ assert set(U) == {"ga", "gb", "gc", "hd", "he"}
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H)
+
+ # DiGraphs
+ G = nx.DiGraph()
+ G.add_node(0)
+ G.add_edge(1, 2)
+ H = nx.DiGraph()
+ H.add_edge(3, 4)
+
+ U = nx.full_join(G, H)
+ assert set(U) == set(G) | set(H)
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2
+
+ # DiGraphs Rename
+ U = nx.full_join(G, H, rename=("g", "h"))
+ assert set(U) == {"g0", "g1", "g2", "h3", "h4"}
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2
+
+
+def test_full_join_multigraph():
+ # MultiGraphs
+ G = nx.MultiGraph()
+ G.add_node(0)
+ G.add_edge(1, 2)
+ H = nx.MultiGraph()
+ H.add_edge(3, 4)
+
+ U = nx.full_join(G, H)
+ assert set(U) == set(G) | set(H)
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H)
+
+ # MultiGraphs rename
+ U = nx.full_join(G, H, rename=("g", "h"))
+ assert set(U) == {"g0", "g1", "g2", "h3", "h4"}
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H)
+
+ # MultiDiGraphs
+ G = nx.MultiDiGraph()
+ G.add_node(0)
+ G.add_edge(1, 2)
+ H = nx.MultiDiGraph()
+ H.add_edge(3, 4)
+
+ U = nx.full_join(G, H)
+ assert set(U) == set(G) | set(H)
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2
+
+ # MultiDiGraphs rename
+ U = nx.full_join(G, H, rename=("g", "h"))
+ assert set(U) == {"g0", "g1", "g2", "h3", "h4"}
+ assert len(U) == len(G) + len(H)
+ assert len(U.edges()) == len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2
+
+
+def test_mixed_type_union():
+ G = nx.Graph()
+ H = nx.MultiGraph()
+ pytest.raises(nx.NetworkXError, nx.union, G, H)
+ pytest.raises(nx.NetworkXError, nx.disjoint_union, G, H)
+ pytest.raises(nx.NetworkXError, nx.intersection, G, H)
+ pytest.raises(nx.NetworkXError, nx.difference, G, H)
+ pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H)
+ pytest.raises(nx.NetworkXError, nx.compose, G, H)
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_product.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_product.py
new file mode 100644
index 00000000..8ee54b93
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_product.py
@@ -0,0 +1,491 @@
+import pytest
+
+import networkx as nx
+from networkx.utils import edges_equal
+
+
+def test_tensor_product_raises():
+ with pytest.raises(nx.NetworkXError):
+ P = nx.tensor_product(nx.DiGraph(), nx.Graph())
+
+
+def test_tensor_product_null():
+ null = nx.null_graph()
+ empty10 = nx.empty_graph(10)
+ K3 = nx.complete_graph(3)
+ K10 = nx.complete_graph(10)
+ P3 = nx.path_graph(3)
+ P10 = nx.path_graph(10)
+ # null graph
+ G = nx.tensor_product(null, null)
+ assert nx.is_isomorphic(G, null)
+ # null_graph X anything = null_graph and v.v.
+ G = nx.tensor_product(null, empty10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(null, K3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(null, K10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(null, P3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(null, P10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(empty10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(K3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(K10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(P3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.tensor_product(P10, null)
+ assert nx.is_isomorphic(G, null)
+
+
+def test_tensor_product_size():
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ K5 = nx.complete_graph(5)
+
+ G = nx.tensor_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.tensor_product(K3, K5)
+ assert nx.number_of_nodes(G) == 3 * 5
+
+
+def test_tensor_product_combinations():
+ # basic smoke test, more realistic tests would be useful
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.tensor_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.tensor_product(P5, nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.tensor_product(nx.MultiGraph(P5), K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.tensor_product(nx.MultiGraph(P5), nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+
+ G = nx.tensor_product(nx.DiGraph(P5), nx.DiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+
+
+def test_tensor_product_classic_result():
+ K2 = nx.complete_graph(2)
+ G = nx.petersen_graph()
+ G = nx.tensor_product(G, K2)
+ assert nx.is_isomorphic(G, nx.desargues_graph())
+
+ G = nx.cycle_graph(5)
+ G = nx.tensor_product(G, K2)
+ assert nx.is_isomorphic(G, nx.cycle_graph(10))
+
+ G = nx.tetrahedral_graph()
+ G = nx.tensor_product(G, K2)
+ assert nx.is_isomorphic(G, nx.cubical_graph())
+
+
+def test_tensor_product_random():
+ G = nx.erdos_renyi_graph(10, 2 / 10.0)
+ H = nx.erdos_renyi_graph(10, 2 / 10.0)
+ GH = nx.tensor_product(G, H)
+
+ for u_G, u_H in GH.nodes():
+ for v_G, v_H in GH.nodes():
+ if H.has_edge(u_H, v_H) and G.has_edge(u_G, v_G):
+ assert GH.has_edge((u_G, u_H), (v_G, v_H))
+ else:
+ assert not GH.has_edge((u_G, u_H), (v_G, v_H))
+
+
+def test_cartesian_product_multigraph():
+ G = nx.MultiGraph()
+ G.add_edge(1, 2, key=0)
+ G.add_edge(1, 2, key=1)
+ H = nx.MultiGraph()
+ H.add_edge(3, 4, key=0)
+ H.add_edge(3, 4, key=1)
+ GH = nx.cartesian_product(G, H)
+ assert set(GH) == {(1, 3), (2, 3), (2, 4), (1, 4)}
+ assert {(frozenset([u, v]), k) for u, v, k in GH.edges(keys=True)} == {
+ (frozenset([u, v]), k)
+ for u, v, k in [
+ ((1, 3), (2, 3), 0),
+ ((1, 3), (2, 3), 1),
+ ((1, 3), (1, 4), 0),
+ ((1, 3), (1, 4), 1),
+ ((2, 3), (2, 4), 0),
+ ((2, 3), (2, 4), 1),
+ ((2, 4), (1, 4), 0),
+ ((2, 4), (1, 4), 1),
+ ]
+ }
+
+
+def test_cartesian_product_raises():
+ with pytest.raises(nx.NetworkXError):
+ P = nx.cartesian_product(nx.DiGraph(), nx.Graph())
+
+
+def test_cartesian_product_null():
+ null = nx.null_graph()
+ empty10 = nx.empty_graph(10)
+ K3 = nx.complete_graph(3)
+ K10 = nx.complete_graph(10)
+ P3 = nx.path_graph(3)
+ P10 = nx.path_graph(10)
+ # null graph
+ G = nx.cartesian_product(null, null)
+ assert nx.is_isomorphic(G, null)
+ # null_graph X anything = null_graph and v.v.
+ G = nx.cartesian_product(null, empty10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(null, K3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(null, K10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(null, P3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(null, P10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(empty10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(K3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(K10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(P3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.cartesian_product(P10, null)
+ assert nx.is_isomorphic(G, null)
+
+
+def test_cartesian_product_size():
+ # order(GXH)=order(G)*order(H)
+ K5 = nx.complete_graph(5)
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.cartesian_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ assert nx.number_of_edges(G) == nx.number_of_edges(P5) * nx.number_of_nodes(
+ K3
+ ) + nx.number_of_edges(K3) * nx.number_of_nodes(P5)
+ G = nx.cartesian_product(K3, K5)
+ assert nx.number_of_nodes(G) == 3 * 5
+ assert nx.number_of_edges(G) == nx.number_of_edges(K5) * nx.number_of_nodes(
+ K3
+ ) + nx.number_of_edges(K3) * nx.number_of_nodes(K5)
+
+
+def test_cartesian_product_classic():
+ # test some classic product graphs
+ P2 = nx.path_graph(2)
+ P3 = nx.path_graph(3)
+ # cube = 2-path X 2-path
+ G = nx.cartesian_product(P2, P2)
+ G = nx.cartesian_product(P2, G)
+ assert nx.is_isomorphic(G, nx.cubical_graph())
+
+ # 3x3 grid
+ G = nx.cartesian_product(P3, P3)
+ assert nx.is_isomorphic(G, nx.grid_2d_graph(3, 3))
+
+
+def test_cartesian_product_random():
+ G = nx.erdos_renyi_graph(10, 2 / 10.0)
+ H = nx.erdos_renyi_graph(10, 2 / 10.0)
+ GH = nx.cartesian_product(G, H)
+
+ for u_G, u_H in GH.nodes():
+ for v_G, v_H in GH.nodes():
+ if (u_G == v_G and H.has_edge(u_H, v_H)) or (
+ u_H == v_H and G.has_edge(u_G, v_G)
+ ):
+ assert GH.has_edge((u_G, u_H), (v_G, v_H))
+ else:
+ assert not GH.has_edge((u_G, u_H), (v_G, v_H))
+
+
+def test_lexicographic_product_raises():
+ with pytest.raises(nx.NetworkXError):
+ P = nx.lexicographic_product(nx.DiGraph(), nx.Graph())
+
+
+def test_lexicographic_product_null():
+ null = nx.null_graph()
+ empty10 = nx.empty_graph(10)
+ K3 = nx.complete_graph(3)
+ K10 = nx.complete_graph(10)
+ P3 = nx.path_graph(3)
+ P10 = nx.path_graph(10)
+ # null graph
+ G = nx.lexicographic_product(null, null)
+ assert nx.is_isomorphic(G, null)
+ # null_graph X anything = null_graph and v.v.
+ G = nx.lexicographic_product(null, empty10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(null, K3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(null, K10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(null, P3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(null, P10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(empty10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(K3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(K10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(P3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.lexicographic_product(P10, null)
+ assert nx.is_isomorphic(G, null)
+
+
+def test_lexicographic_product_size():
+ K5 = nx.complete_graph(5)
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.lexicographic_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.lexicographic_product(K3, K5)
+ assert nx.number_of_nodes(G) == 3 * 5
+
+
+def test_lexicographic_product_combinations():
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.lexicographic_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.lexicographic_product(nx.MultiGraph(P5), K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.lexicographic_product(P5, nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.lexicographic_product(nx.MultiGraph(P5), nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+
+ # No classic easily found classic results for lexicographic product
+
+
+def test_lexicographic_product_random():
+ G = nx.erdos_renyi_graph(10, 2 / 10.0)
+ H = nx.erdos_renyi_graph(10, 2 / 10.0)
+ GH = nx.lexicographic_product(G, H)
+
+ for u_G, u_H in GH.nodes():
+ for v_G, v_H in GH.nodes():
+ if G.has_edge(u_G, v_G) or (u_G == v_G and H.has_edge(u_H, v_H)):
+ assert GH.has_edge((u_G, u_H), (v_G, v_H))
+ else:
+ assert not GH.has_edge((u_G, u_H), (v_G, v_H))
+
+
+def test_strong_product_raises():
+ with pytest.raises(nx.NetworkXError):
+ P = nx.strong_product(nx.DiGraph(), nx.Graph())
+
+
+def test_strong_product_null():
+ null = nx.null_graph()
+ empty10 = nx.empty_graph(10)
+ K3 = nx.complete_graph(3)
+ K10 = nx.complete_graph(10)
+ P3 = nx.path_graph(3)
+ P10 = nx.path_graph(10)
+ # null graph
+ G = nx.strong_product(null, null)
+ assert nx.is_isomorphic(G, null)
+ # null_graph X anything = null_graph and v.v.
+ G = nx.strong_product(null, empty10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(null, K3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(null, K10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(null, P3)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(null, P10)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(empty10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(K3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(K10, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(P3, null)
+ assert nx.is_isomorphic(G, null)
+ G = nx.strong_product(P10, null)
+ assert nx.is_isomorphic(G, null)
+
+
+def test_strong_product_size():
+ K5 = nx.complete_graph(5)
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.strong_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.strong_product(K3, K5)
+ assert nx.number_of_nodes(G) == 3 * 5
+
+
+def test_strong_product_combinations():
+ P5 = nx.path_graph(5)
+ K3 = nx.complete_graph(3)
+ G = nx.strong_product(P5, K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.strong_product(nx.MultiGraph(P5), K3)
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.strong_product(P5, nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+ G = nx.strong_product(nx.MultiGraph(P5), nx.MultiGraph(K3))
+ assert nx.number_of_nodes(G) == 5 * 3
+
+ # No classic easily found classic results for strong product
+
+
+def test_strong_product_random():
+ G = nx.erdos_renyi_graph(10, 2 / 10.0)
+ H = nx.erdos_renyi_graph(10, 2 / 10.0)
+ GH = nx.strong_product(G, H)
+
+ for u_G, u_H in GH.nodes():
+ for v_G, v_H in GH.nodes():
+ if (
+ (u_G == v_G and H.has_edge(u_H, v_H))
+ or (u_H == v_H and G.has_edge(u_G, v_G))
+ or (G.has_edge(u_G, v_G) and H.has_edge(u_H, v_H))
+ ):
+ assert GH.has_edge((u_G, u_H), (v_G, v_H))
+ else:
+ assert not GH.has_edge((u_G, u_H), (v_G, v_H))
+
+
+def test_graph_power_raises():
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.power(nx.MultiDiGraph(), 2)
+
+
+def test_graph_power():
+ # wikipedia example for graph power
+ G = nx.cycle_graph(7)
+ G.add_edge(6, 7)
+ G.add_edge(7, 8)
+ G.add_edge(8, 9)
+ G.add_edge(9, 2)
+ H = nx.power(G, 2)
+
+ assert edges_equal(
+ list(H.edges()),
+ [
+ (0, 1),
+ (0, 2),
+ (0, 5),
+ (0, 6),
+ (0, 7),
+ (1, 9),
+ (1, 2),
+ (1, 3),
+ (1, 6),
+ (2, 3),
+ (2, 4),
+ (2, 8),
+ (2, 9),
+ (3, 4),
+ (3, 5),
+ (3, 9),
+ (4, 5),
+ (4, 6),
+ (5, 6),
+ (5, 7),
+ (6, 7),
+ (6, 8),
+ (7, 8),
+ (7, 9),
+ (8, 9),
+ ],
+ )
+
+
+def test_graph_power_negative():
+ with pytest.raises(ValueError):
+ nx.power(nx.Graph(), -1)
+
+
+def test_rooted_product_raises():
+ with pytest.raises(nx.NodeNotFound):
+ nx.rooted_product(nx.Graph(), nx.path_graph(2), 10)
+
+
+def test_rooted_product():
+ G = nx.cycle_graph(5)
+ H = nx.Graph()
+ H.add_edges_from([("a", "b"), ("b", "c"), ("b", "d")])
+ R = nx.rooted_product(G, H, "a")
+ assert len(R) == len(G) * len(H)
+ assert R.size() == G.size() + len(G) * H.size()
+
+
+def test_corona_product():
+ G = nx.cycle_graph(3)
+ H = nx.path_graph(2)
+ C = nx.corona_product(G, H)
+ assert len(C) == (len(G) * len(H)) + len(G)
+ assert C.size() == G.size() + len(G) * H.size() + len(G) * len(H)
+
+
+def test_modular_product():
+ G = nx.path_graph(3)
+ H = nx.path_graph(4)
+ M = nx.modular_product(G, H)
+ assert len(M) == len(G) * len(H)
+
+ assert edges_equal(
+ list(M.edges()),
+ [
+ ((0, 0), (1, 1)),
+ ((0, 0), (2, 2)),
+ ((0, 0), (2, 3)),
+ ((0, 1), (1, 0)),
+ ((0, 1), (1, 2)),
+ ((0, 1), (2, 3)),
+ ((0, 2), (1, 1)),
+ ((0, 2), (1, 3)),
+ ((0, 2), (2, 0)),
+ ((0, 3), (1, 2)),
+ ((0, 3), (2, 0)),
+ ((0, 3), (2, 1)),
+ ((1, 0), (2, 1)),
+ ((1, 1), (2, 0)),
+ ((1, 1), (2, 2)),
+ ((1, 2), (2, 1)),
+ ((1, 2), (2, 3)),
+ ((1, 3), (2, 2)),
+ ],
+ )
+
+
+def test_modular_product_raises():
+ G = nx.Graph([(0, 1), (1, 2), (2, 0)])
+ H = nx.Graph([(0, 1), (1, 2), (2, 0)])
+ DG = nx.DiGraph([(0, 1), (1, 2), (2, 0)])
+ DH = nx.DiGraph([(0, 1), (1, 2), (2, 0)])
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(G, DH)
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(DG, H)
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(DG, DH)
+
+ MG = nx.MultiGraph([(0, 1), (1, 2), (2, 0), (0, 1)])
+ MH = nx.MultiGraph([(0, 1), (1, 2), (2, 0), (0, 1)])
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(G, MH)
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(MG, H)
+ with pytest.raises(nx.NetworkXNotImplemented):
+ nx.modular_product(MG, MH)
+ with pytest.raises(nx.NetworkXNotImplemented):
+ # check multigraph with no multiedges
+ nx.modular_product(nx.MultiGraph(G), H)
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_unary.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_unary.py
new file mode 100644
index 00000000..d68e55cd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/tests/test_unary.py
@@ -0,0 +1,55 @@
+import pytest
+
+import networkx as nx
+
+
+def test_complement():
+ null = nx.null_graph()
+ empty1 = nx.empty_graph(1)
+ empty10 = nx.empty_graph(10)
+ K3 = nx.complete_graph(3)
+ K5 = nx.complete_graph(5)
+ K10 = nx.complete_graph(10)
+ P2 = nx.path_graph(2)
+ P3 = nx.path_graph(3)
+ P5 = nx.path_graph(5)
+ P10 = nx.path_graph(10)
+ # complement of the complete graph is empty
+
+ G = nx.complement(K3)
+ assert nx.is_isomorphic(G, nx.empty_graph(3))
+ G = nx.complement(K5)
+ assert nx.is_isomorphic(G, nx.empty_graph(5))
+ # for any G, G=complement(complement(G))
+ P3cc = nx.complement(nx.complement(P3))
+ assert nx.is_isomorphic(P3, P3cc)
+ nullcc = nx.complement(nx.complement(null))
+ assert nx.is_isomorphic(null, nullcc)
+ b = nx.bull_graph()
+ bcc = nx.complement(nx.complement(b))
+ assert nx.is_isomorphic(b, bcc)
+
+
+def test_complement_2():
+ G1 = nx.DiGraph()
+ G1.add_edge("A", "B")
+ G1.add_edge("A", "C")
+ G1.add_edge("A", "D")
+ G1C = nx.complement(G1)
+ assert sorted(G1C.edges()) == [
+ ("B", "A"),
+ ("B", "C"),
+ ("B", "D"),
+ ("C", "A"),
+ ("C", "B"),
+ ("C", "D"),
+ ("D", "A"),
+ ("D", "B"),
+ ("D", "C"),
+ ]
+
+
+def test_reverse1():
+ # Other tests for reverse are done by the DiGraph and MultiDigraph.
+ G1 = nx.Graph()
+ pytest.raises(nx.NetworkXError, nx.reverse, G1)