about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/networkx/linalg/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/linalg/tests
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/linalg/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py402
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_attrmatrix.py108
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_bethehessian.py41
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_graphmatrix.py276
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_laplacian.py336
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_modularity.py87
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_spectrum.py71
8 files changed, 1321 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/__init__.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py
new file mode 100644
index 00000000..089d917a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py
@@ -0,0 +1,402 @@
+from math import sqrt
+
+import pytest
+
+np = pytest.importorskip("numpy")
+
+
+import networkx as nx
+
+methods = ("tracemin_pcg", "tracemin_lu", "lanczos", "lobpcg")
+
+
+def test_algebraic_connectivity_tracemin_chol():
+    """Test that "tracemin_chol" raises an exception."""
+    pytest.importorskip("scipy")
+    G = nx.barbell_graph(5, 4)
+    with pytest.raises(nx.NetworkXError):
+        nx.algebraic_connectivity(G, method="tracemin_chol")
+
+
+def test_fiedler_vector_tracemin_chol():
+    """Test that "tracemin_chol" raises an exception."""
+    pytest.importorskip("scipy")
+    G = nx.barbell_graph(5, 4)
+    with pytest.raises(nx.NetworkXError):
+        nx.fiedler_vector(G, method="tracemin_chol")
+
+
+def test_spectral_ordering_tracemin_chol():
+    """Test that "tracemin_chol" raises an exception."""
+    pytest.importorskip("scipy")
+    G = nx.barbell_graph(5, 4)
+    with pytest.raises(nx.NetworkXError):
+        nx.spectral_ordering(G, method="tracemin_chol")
+
+
+def test_fiedler_vector_tracemin_unknown():
+    """Test that "tracemin_unknown" raises an exception."""
+    pytest.importorskip("scipy")
+    G = nx.barbell_graph(5, 4)
+    L = nx.laplacian_matrix(G)
+    X = np.asarray(np.random.normal(size=(1, L.shape[0]))).T
+    with pytest.raises(nx.NetworkXError, match="Unknown linear system solver"):
+        nx.linalg.algebraicconnectivity._tracemin_fiedler(
+            L, X, normalized=False, tol=1e-8, method="tracemin_unknown"
+        )
+
+
+def test_spectral_bisection():
+    pytest.importorskip("scipy")
+    G = nx.barbell_graph(3, 0)
+    C = nx.spectral_bisection(G)
+    assert C == ({0, 1, 2}, {3, 4, 5})
+
+    mapping = dict(enumerate("badfec"))
+    G = nx.relabel_nodes(G, mapping)
+    C = nx.spectral_bisection(G)
+    assert C == (
+        {mapping[0], mapping[1], mapping[2]},
+        {mapping[3], mapping[4], mapping[5]},
+    )
+
+
+def check_eigenvector(A, l, x):
+    nx = np.linalg.norm(x)
+    # Check zeroness.
+    assert nx != pytest.approx(0, abs=1e-07)
+    y = A @ x
+    ny = np.linalg.norm(y)
+    # Check collinearity.
+    assert x @ y == pytest.approx(nx * ny, abs=1e-7)
+    # Check eigenvalue.
+    assert ny == pytest.approx(l * nx, abs=1e-7)
+
+
+class TestAlgebraicConnectivity:
+    @pytest.mark.parametrize("method", methods)
+    def test_directed(self, method):
+        G = nx.DiGraph()
+        pytest.raises(
+            nx.NetworkXNotImplemented, nx.algebraic_connectivity, G, method=method
+        )
+        pytest.raises(nx.NetworkXNotImplemented, nx.fiedler_vector, G, method=method)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_null_and_singleton(self, method):
+        G = nx.Graph()
+        pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method=method)
+        pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method)
+        G.add_edge(0, 0)
+        pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method=method)
+        pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_disconnected(self, method):
+        G = nx.Graph()
+        G.add_nodes_from(range(2))
+        assert nx.algebraic_connectivity(G) == 0
+        pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method)
+        G.add_edge(0, 1, weight=0)
+        assert nx.algebraic_connectivity(G) == 0
+        pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method=method)
+
+    def test_unrecognized_method(self):
+        pytest.importorskip("scipy")
+        G = nx.path_graph(4)
+        pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, method="unknown")
+        pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method="unknown")
+
+    @pytest.mark.parametrize("method", methods)
+    def test_two_nodes(self, method):
+        pytest.importorskip("scipy")
+        G = nx.Graph()
+        G.add_edge(0, 1, weight=1)
+        A = nx.laplacian_matrix(G)
+        assert nx.algebraic_connectivity(G, tol=1e-12, method=method) == pytest.approx(
+            2, abs=1e-7
+        )
+        x = nx.fiedler_vector(G, tol=1e-12, method=method)
+        check_eigenvector(A, 2, x)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_two_nodes_multigraph(self, method):
+        pytest.importorskip("scipy")
+        G = nx.MultiGraph()
+        G.add_edge(0, 0, spam=1e8)
+        G.add_edge(0, 1, spam=1)
+        G.add_edge(0, 1, spam=-2)
+        A = -3 * nx.laplacian_matrix(G, weight="spam")
+        assert nx.algebraic_connectivity(
+            G, weight="spam", tol=1e-12, method=method
+        ) == pytest.approx(6, abs=1e-7)
+        x = nx.fiedler_vector(G, weight="spam", tol=1e-12, method=method)
+        check_eigenvector(A, 6, x)
+
+    def test_abbreviation_of_method(self):
+        pytest.importorskip("scipy")
+        G = nx.path_graph(8)
+        A = nx.laplacian_matrix(G)
+        sigma = 2 - sqrt(2 + sqrt(2))
+        ac = nx.algebraic_connectivity(G, tol=1e-12, method="tracemin")
+        assert ac == pytest.approx(sigma, abs=1e-7)
+        x = nx.fiedler_vector(G, tol=1e-12, method="tracemin")
+        check_eigenvector(A, sigma, x)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_path(self, method):
+        pytest.importorskip("scipy")
+        G = nx.path_graph(8)
+        A = nx.laplacian_matrix(G)
+        sigma = 2 - sqrt(2 + sqrt(2))
+        ac = nx.algebraic_connectivity(G, tol=1e-12, method=method)
+        assert ac == pytest.approx(sigma, abs=1e-7)
+        x = nx.fiedler_vector(G, tol=1e-12, method=method)
+        check_eigenvector(A, sigma, x)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_problematic_graph_issue_2381(self, method):
+        pytest.importorskip("scipy")
+        G = nx.path_graph(4)
+        G.add_edges_from([(4, 2), (5, 1)])
+        A = nx.laplacian_matrix(G)
+        sigma = 0.438447187191
+        ac = nx.algebraic_connectivity(G, tol=1e-12, method=method)
+        assert ac == pytest.approx(sigma, abs=1e-7)
+        x = nx.fiedler_vector(G, tol=1e-12, method=method)
+        check_eigenvector(A, sigma, x)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_cycle(self, method):
+        pytest.importorskip("scipy")
+        G = nx.cycle_graph(8)
+        A = nx.laplacian_matrix(G)
+        sigma = 2 - sqrt(2)
+        ac = nx.algebraic_connectivity(G, tol=1e-12, method=method)
+        assert ac == pytest.approx(sigma, abs=1e-7)
+        x = nx.fiedler_vector(G, tol=1e-12, method=method)
+        check_eigenvector(A, sigma, x)
+
+    @pytest.mark.parametrize("method", methods)
+    def test_seed_argument(self, method):
+        pytest.importorskip("scipy")
+        G = nx.cycle_graph(8)
+        A = nx.laplacian_matrix(G)
+        sigma = 2 - sqrt(2)
+        ac = nx.algebraic_connectivity(G, tol=1e-12, method=method, seed=1)
+        assert ac == pytest.approx(sigma, abs=1e-7)
+        x = nx.fiedler_vector(G, tol=1e-12, method=method, seed=1)
+        check_eigenvector(A, sigma, x)
+
+    @pytest.mark.parametrize(
+        ("normalized", "sigma", "laplacian_fn"),
+        (
+            (False, 0.2434017461399311, nx.laplacian_matrix),
+            (True, 0.08113391537997749, nx.normalized_laplacian_matrix),
+        ),
+    )
+    @pytest.mark.parametrize("method", methods)
+    def test_buckminsterfullerene(self, normalized, sigma, laplacian_fn, method):
+        pytest.importorskip("scipy")
+        G = nx.Graph(
+            [
+                (1, 10),
+                (1, 41),
+                (1, 59),
+                (2, 12),
+                (2, 42),
+                (2, 60),
+                (3, 6),
+                (3, 43),
+                (3, 57),
+                (4, 8),
+                (4, 44),
+                (4, 58),
+                (5, 13),
+                (5, 56),
+                (5, 57),
+                (6, 10),
+                (6, 31),
+                (7, 14),
+                (7, 56),
+                (7, 58),
+                (8, 12),
+                (8, 32),
+                (9, 23),
+                (9, 53),
+                (9, 59),
+                (10, 15),
+                (11, 24),
+                (11, 53),
+                (11, 60),
+                (12, 16),
+                (13, 14),
+                (13, 25),
+                (14, 26),
+                (15, 27),
+                (15, 49),
+                (16, 28),
+                (16, 50),
+                (17, 18),
+                (17, 19),
+                (17, 54),
+                (18, 20),
+                (18, 55),
+                (19, 23),
+                (19, 41),
+                (20, 24),
+                (20, 42),
+                (21, 31),
+                (21, 33),
+                (21, 57),
+                (22, 32),
+                (22, 34),
+                (22, 58),
+                (23, 24),
+                (25, 35),
+                (25, 43),
+                (26, 36),
+                (26, 44),
+                (27, 51),
+                (27, 59),
+                (28, 52),
+                (28, 60),
+                (29, 33),
+                (29, 34),
+                (29, 56),
+                (30, 51),
+                (30, 52),
+                (30, 53),
+                (31, 47),
+                (32, 48),
+                (33, 45),
+                (34, 46),
+                (35, 36),
+                (35, 37),
+                (36, 38),
+                (37, 39),
+                (37, 49),
+                (38, 40),
+                (38, 50),
+                (39, 40),
+                (39, 51),
+                (40, 52),
+                (41, 47),
+                (42, 48),
+                (43, 49),
+                (44, 50),
+                (45, 46),
+                (45, 54),
+                (46, 55),
+                (47, 54),
+                (48, 55),
+            ]
+        )
+        A = laplacian_fn(G)
+        try:
+            assert nx.algebraic_connectivity(
+                G, normalized=normalized, tol=1e-12, method=method
+            ) == pytest.approx(sigma, abs=1e-7)
+            x = nx.fiedler_vector(G, normalized=normalized, tol=1e-12, method=method)
+            check_eigenvector(A, sigma, x)
+        except nx.NetworkXError as err:
+            if err.args not in (
+                ("Cholesky solver unavailable.",),
+                ("LU solver unavailable.",),
+            ):
+                raise
+
+
+class TestSpectralOrdering:
+    _graphs = (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
+
+    @pytest.mark.parametrize("graph", _graphs)
+    def test_nullgraph(self, graph):
+        G = graph()
+        pytest.raises(nx.NetworkXError, nx.spectral_ordering, G)
+
+    @pytest.mark.parametrize("graph", _graphs)
+    def test_singleton(self, graph):
+        G = graph()
+        G.add_node("x")
+        assert nx.spectral_ordering(G) == ["x"]
+        G.add_edge("x", "x", weight=33)
+        G.add_edge("x", "x", weight=33)
+        assert nx.spectral_ordering(G) == ["x"]
+
+    def test_unrecognized_method(self):
+        G = nx.path_graph(4)
+        pytest.raises(nx.NetworkXError, nx.spectral_ordering, G, method="unknown")
+
+    @pytest.mark.parametrize("method", methods)
+    def test_three_nodes(self, method):
+        pytest.importorskip("scipy")
+        G = nx.Graph()
+        G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1)], weight="spam")
+        order = nx.spectral_ordering(G, weight="spam", method=method)
+        assert set(order) == set(G)
+        assert {1, 3} in (set(order[:-1]), set(order[1:]))
+
+    @pytest.mark.parametrize("method", methods)
+    def test_three_nodes_multigraph(self, method):
+        pytest.importorskip("scipy")
+        G = nx.MultiDiGraph()
+        G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1), (2, 3, 2)])
+        order = nx.spectral_ordering(G, method=method)
+        assert set(order) == set(G)
+        assert {2, 3} in (set(order[:-1]), set(order[1:]))
+
+    @pytest.mark.parametrize("method", methods)
+    def test_path(self, method):
+        pytest.importorskip("scipy")
+        path = list(range(10))
+        np.random.shuffle(path)
+        G = nx.Graph()
+        nx.add_path(G, path)
+        order = nx.spectral_ordering(G, method=method)
+        assert order in [path, list(reversed(path))]
+
+    @pytest.mark.parametrize("method", methods)
+    def test_seed_argument(self, method):
+        pytest.importorskip("scipy")
+        path = list(range(10))
+        np.random.shuffle(path)
+        G = nx.Graph()
+        nx.add_path(G, path)
+        order = nx.spectral_ordering(G, method=method, seed=1)
+        assert order in [path, list(reversed(path))]
+
+    @pytest.mark.parametrize("method", methods)
+    def test_disconnected(self, method):
+        pytest.importorskip("scipy")
+        G = nx.Graph()
+        nx.add_path(G, range(0, 10, 2))
+        nx.add_path(G, range(1, 10, 2))
+        order = nx.spectral_ordering(G, method=method)
+        assert set(order) == set(G)
+        seqs = [
+            list(range(0, 10, 2)),
+            list(range(8, -1, -2)),
+            list(range(1, 10, 2)),
+            list(range(9, -1, -2)),
+        ]
+        assert order[:5] in seqs
+        assert order[5:] in seqs
+
+    @pytest.mark.parametrize(
+        ("normalized", "expected_order"),
+        (
+            (False, [[1, 2, 0, 3, 4, 5, 6, 9, 7, 8], [8, 7, 9, 6, 5, 4, 3, 0, 2, 1]]),
+            (True, [[1, 2, 3, 0, 4, 5, 9, 6, 7, 8], [8, 7, 6, 9, 5, 4, 0, 3, 2, 1]]),
+        ),
+    )
+    @pytest.mark.parametrize("method", methods)
+    def test_cycle(self, normalized, expected_order, method):
+        pytest.importorskip("scipy")
+        path = list(range(10))
+        G = nx.Graph()
+        nx.add_path(G, path, weight=5)
+        G.add_edge(path[-1], path[0], weight=1)
+        A = nx.laplacian_matrix(G).todense()
+        order = nx.spectral_ordering(G, normalized=normalized, method=method)
+        assert order in expected_order
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_attrmatrix.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_attrmatrix.py
new file mode 100644
index 00000000..01574bb3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_attrmatrix.py
@@ -0,0 +1,108 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+
+import networkx as nx
+
+
+def test_attr_matrix():
+    G = nx.Graph()
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 2, thickness=2)
+    G.add_edge(1, 2, thickness=3)
+
+    def node_attr(u):
+        return G.nodes[u].get("size", 0.5) * 3
+
+    def edge_attr(u, v):
+        return G[u][v].get("thickness", 0.5)
+
+    M = nx.attr_matrix(G, edge_attr=edge_attr, node_attr=node_attr)
+    np.testing.assert_equal(M[0], np.array([[6.0]]))
+    assert M[1] == [1.5]
+
+
+def test_attr_matrix_directed():
+    G = nx.DiGraph()
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 2, thickness=2)
+    G.add_edge(1, 2, thickness=3)
+    M = nx.attr_matrix(G, rc_order=[0, 1, 2])
+    # fmt: off
+    data = np.array(
+        [[0., 1., 1.],
+         [0., 0., 1.],
+         [0., 0., 0.]]
+    )
+    # fmt: on
+    np.testing.assert_equal(M, np.array(data))
+
+
+def test_attr_matrix_multigraph():
+    G = nx.MultiGraph()
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 2, thickness=2)
+    G.add_edge(1, 2, thickness=3)
+    M = nx.attr_matrix(G, rc_order=[0, 1, 2])
+    # fmt: off
+    data = np.array(
+        [[0., 3., 1.],
+         [3., 0., 1.],
+         [1., 1., 0.]]
+    )
+    # fmt: on
+    np.testing.assert_equal(M, np.array(data))
+    M = nx.attr_matrix(G, edge_attr="weight", rc_order=[0, 1, 2])
+    # fmt: off
+    data = np.array(
+        [[0., 9., 1.],
+         [9., 0., 1.],
+         [1., 1., 0.]]
+    )
+    # fmt: on
+    np.testing.assert_equal(M, np.array(data))
+    M = nx.attr_matrix(G, edge_attr="thickness", rc_order=[0, 1, 2])
+    # fmt: off
+    data = np.array(
+        [[0., 3., 2.],
+         [3., 0., 3.],
+         [2., 3., 0.]]
+    )
+    # fmt: on
+    np.testing.assert_equal(M, np.array(data))
+
+
+def test_attr_sparse_matrix():
+    pytest.importorskip("scipy")
+    G = nx.Graph()
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 2, thickness=2)
+    G.add_edge(1, 2, thickness=3)
+    M = nx.attr_sparse_matrix(G)
+    mtx = M[0]
+    data = np.ones((3, 3), float)
+    np.fill_diagonal(data, 0)
+    np.testing.assert_equal(mtx.todense(), np.array(data))
+    assert M[1] == [0, 1, 2]
+
+
+def test_attr_sparse_matrix_directed():
+    pytest.importorskip("scipy")
+    G = nx.DiGraph()
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 1, thickness=1, weight=3)
+    G.add_edge(0, 2, thickness=2)
+    G.add_edge(1, 2, thickness=3)
+    M = nx.attr_sparse_matrix(G, rc_order=[0, 1, 2])
+    # fmt: off
+    data = np.array(
+        [[0., 1., 1.],
+         [0., 0., 1.],
+         [0., 0., 0.]]
+    )
+    # fmt: on
+    np.testing.assert_equal(M.todense(), np.array(data))
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_bethehessian.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_bethehessian.py
new file mode 100644
index 00000000..339fe1be
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_bethehessian.py
@@ -0,0 +1,41 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+pytest.importorskip("scipy")
+
+import networkx as nx
+from networkx.generators.degree_seq import havel_hakimi_graph
+
+
+class TestBetheHessian:
+    @classmethod
+    def setup_class(cls):
+        deg = [3, 2, 2, 1, 0]
+        cls.G = havel_hakimi_graph(deg)
+        cls.P = nx.path_graph(3)
+
+    def test_bethe_hessian(self):
+        "Bethe Hessian matrix"
+        # fmt: off
+        H = np.array([[4, -2, 0],
+                      [-2, 5, -2],
+                      [0, -2, 4]])
+        # fmt: on
+        permutation = [2, 0, 1]
+        # Bethe Hessian gives expected form
+        np.testing.assert_equal(nx.bethe_hessian_matrix(self.P, r=2).todense(), H)
+        # nodelist is correctly implemented
+        np.testing.assert_equal(
+            nx.bethe_hessian_matrix(self.P, r=2, nodelist=permutation).todense(),
+            H[np.ix_(permutation, permutation)],
+        )
+        # Equal to Laplacian matrix when r=1
+        np.testing.assert_equal(
+            nx.bethe_hessian_matrix(self.G, r=1).todense(),
+            nx.laplacian_matrix(self.G).todense(),
+        )
+        # Correct default for the regularizer r
+        np.testing.assert_equal(
+            nx.bethe_hessian_matrix(self.G).todense(),
+            nx.bethe_hessian_matrix(self.G, r=1.25).todense(),
+        )
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_graphmatrix.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_graphmatrix.py
new file mode 100644
index 00000000..519198bc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_graphmatrix.py
@@ -0,0 +1,276 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+pytest.importorskip("scipy")
+
+import networkx as nx
+from networkx.exception import NetworkXError
+from networkx.generators.degree_seq import havel_hakimi_graph
+
+
+def test_incidence_matrix_simple():
+    deg = [3, 2, 2, 1, 0]
+    G = havel_hakimi_graph(deg)
+    deg = [(1, 0), (1, 0), (1, 0), (2, 0), (1, 0), (2, 1), (0, 1), (0, 1)]
+    MG = nx.random_clustered_graph(deg, seed=42)
+
+    I = nx.incidence_matrix(G, dtype=int).todense()
+    # fmt: off
+    expected = np.array(
+        [[1, 1, 1, 0],
+         [0, 1, 0, 1],
+         [1, 0, 0, 1],
+         [0, 0, 1, 0],
+         [0, 0, 0, 0]]
+    )
+    # fmt: on
+    np.testing.assert_equal(I, expected)
+
+    I = nx.incidence_matrix(MG, dtype=int).todense()
+    # fmt: off
+    expected = np.array(
+        [[1, 0, 0, 0, 0, 0, 0],
+         [1, 0, 0, 0, 0, 0, 0],
+         [0, 1, 0, 0, 0, 0, 0],
+         [0, 0, 0, 0, 0, 0, 0],
+         [0, 1, 0, 0, 0, 0, 0],
+         [0, 0, 0, 0, 1, 1, 0],
+         [0, 0, 0, 0, 0, 1, 1],
+         [0, 0, 0, 0, 1, 0, 1]]
+    )
+    # fmt: on
+    np.testing.assert_equal(I, expected)
+
+    with pytest.raises(NetworkXError):
+        nx.incidence_matrix(G, nodelist=[0, 1])
+
+
+class TestGraphMatrix:
+    @classmethod
+    def setup_class(cls):
+        deg = [3, 2, 2, 1, 0]
+        cls.G = havel_hakimi_graph(deg)
+        # fmt: off
+        cls.OI = np.array(
+            [[-1, -1, -1, 0],
+             [1, 0, 0, -1],
+             [0, 1, 0, 1],
+             [0, 0, 1, 0],
+             [0, 0, 0, 0]]
+        )
+        cls.A = np.array(
+            [[0, 1, 1, 1, 0],
+             [1, 0, 1, 0, 0],
+             [1, 1, 0, 0, 0],
+             [1, 0, 0, 0, 0],
+             [0, 0, 0, 0, 0]]
+        )
+        # fmt: on
+        cls.WG = havel_hakimi_graph(deg)
+        cls.WG.add_edges_from(
+            (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges()
+        )
+        # fmt: off
+        cls.WA = np.array(
+            [[0, 0.5, 0.5, 0.5, 0],
+             [0.5, 0, 0.5, 0, 0],
+             [0.5, 0.5, 0, 0, 0],
+             [0.5, 0, 0, 0, 0],
+             [0, 0, 0, 0, 0]]
+        )
+        # fmt: on
+        cls.MG = nx.MultiGraph(cls.G)
+        cls.MG2 = cls.MG.copy()
+        cls.MG2.add_edge(0, 1)
+        # fmt: off
+        cls.MG2A = np.array(
+            [[0, 2, 1, 1, 0],
+             [2, 0, 1, 0, 0],
+             [1, 1, 0, 0, 0],
+             [1, 0, 0, 0, 0],
+             [0, 0, 0, 0, 0]]
+        )
+        cls.MGOI = np.array(
+            [[-1, -1, -1, -1, 0],
+             [1, 1, 0, 0, -1],
+             [0, 0, 1, 0, 1],
+             [0, 0, 0, 1, 0],
+             [0, 0, 0, 0, 0]]
+        )
+        # fmt: on
+        cls.no_edges_G = nx.Graph([(1, 2), (3, 2, {"weight": 8})])
+        cls.no_edges_A = np.array([[0, 0], [0, 0]])
+
+    def test_incidence_matrix(self):
+        "Conversion to incidence matrix"
+        I = nx.incidence_matrix(
+            self.G,
+            nodelist=sorted(self.G),
+            edgelist=sorted(self.G.edges()),
+            oriented=True,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, self.OI)
+
+        I = nx.incidence_matrix(
+            self.G,
+            nodelist=sorted(self.G),
+            edgelist=sorted(self.G.edges()),
+            oriented=False,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, np.abs(self.OI))
+
+        I = nx.incidence_matrix(
+            self.MG,
+            nodelist=sorted(self.MG),
+            edgelist=sorted(self.MG.edges()),
+            oriented=True,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, self.OI)
+
+        I = nx.incidence_matrix(
+            self.MG,
+            nodelist=sorted(self.MG),
+            edgelist=sorted(self.MG.edges()),
+            oriented=False,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, np.abs(self.OI))
+
+        I = nx.incidence_matrix(
+            self.MG2,
+            nodelist=sorted(self.MG2),
+            edgelist=sorted(self.MG2.edges()),
+            oriented=True,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, self.MGOI)
+
+        I = nx.incidence_matrix(
+            self.MG2,
+            nodelist=sorted(self.MG),
+            edgelist=sorted(self.MG2.edges()),
+            oriented=False,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, np.abs(self.MGOI))
+
+        I = nx.incidence_matrix(self.G, dtype=np.uint8)
+        assert I.dtype == np.uint8
+
+    def test_weighted_incidence_matrix(self):
+        I = nx.incidence_matrix(
+            self.WG,
+            nodelist=sorted(self.WG),
+            edgelist=sorted(self.WG.edges()),
+            oriented=True,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, self.OI)
+
+        I = nx.incidence_matrix(
+            self.WG,
+            nodelist=sorted(self.WG),
+            edgelist=sorted(self.WG.edges()),
+            oriented=False,
+            dtype=int,
+        ).todense()
+        np.testing.assert_equal(I, np.abs(self.OI))
+
+        # np.testing.assert_equal(nx.incidence_matrix(self.WG,oriented=True,
+        #                                  weight='weight').todense(),0.5*self.OI)
+        # np.testing.assert_equal(nx.incidence_matrix(self.WG,weight='weight').todense(),
+        #              np.abs(0.5*self.OI))
+        # np.testing.assert_equal(nx.incidence_matrix(self.WG,oriented=True,weight='other').todense(),
+        #              0.3*self.OI)
+
+        I = nx.incidence_matrix(
+            self.WG,
+            nodelist=sorted(self.WG),
+            edgelist=sorted(self.WG.edges()),
+            oriented=True,
+            weight="weight",
+        ).todense()
+        np.testing.assert_equal(I, 0.5 * self.OI)
+
+        I = nx.incidence_matrix(
+            self.WG,
+            nodelist=sorted(self.WG),
+            edgelist=sorted(self.WG.edges()),
+            oriented=False,
+            weight="weight",
+        ).todense()
+        np.testing.assert_equal(I, np.abs(0.5 * self.OI))
+
+        I = nx.incidence_matrix(
+            self.WG,
+            nodelist=sorted(self.WG),
+            edgelist=sorted(self.WG.edges()),
+            oriented=True,
+            weight="other",
+        ).todense()
+        np.testing.assert_equal(I, 0.3 * self.OI)
+
+        # WMG=nx.MultiGraph(self.WG)
+        # WMG.add_edge(0,1,weight=0.5,other=0.3)
+        # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='weight').todense(),
+        #              np.abs(0.5*self.MGOI))
+        # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='weight',oriented=True).todense(),
+        #              0.5*self.MGOI)
+        # np.testing.assert_equal(nx.incidence_matrix(WMG,weight='other',oriented=True).todense(),
+        #              0.3*self.MGOI)
+
+        WMG = nx.MultiGraph(self.WG)
+        WMG.add_edge(0, 1, weight=0.5, other=0.3)
+
+        I = nx.incidence_matrix(
+            WMG,
+            nodelist=sorted(WMG),
+            edgelist=sorted(WMG.edges(keys=True)),
+            oriented=True,
+            weight="weight",
+        ).todense()
+        np.testing.assert_equal(I, 0.5 * self.MGOI)
+
+        I = nx.incidence_matrix(
+            WMG,
+            nodelist=sorted(WMG),
+            edgelist=sorted(WMG.edges(keys=True)),
+            oriented=False,
+            weight="weight",
+        ).todense()
+        np.testing.assert_equal(I, np.abs(0.5 * self.MGOI))
+
+        I = nx.incidence_matrix(
+            WMG,
+            nodelist=sorted(WMG),
+            edgelist=sorted(WMG.edges(keys=True)),
+            oriented=True,
+            weight="other",
+        ).todense()
+        np.testing.assert_equal(I, 0.3 * self.MGOI)
+
+    def test_adjacency_matrix(self):
+        "Conversion to adjacency matrix"
+        np.testing.assert_equal(nx.adjacency_matrix(self.G).todense(), self.A)
+        np.testing.assert_equal(nx.adjacency_matrix(self.MG).todense(), self.A)
+        np.testing.assert_equal(nx.adjacency_matrix(self.MG2).todense(), self.MG2A)
+        np.testing.assert_equal(
+            nx.adjacency_matrix(self.G, nodelist=[0, 1]).todense(), self.A[:2, :2]
+        )
+        np.testing.assert_equal(nx.adjacency_matrix(self.WG).todense(), self.WA)
+        np.testing.assert_equal(
+            nx.adjacency_matrix(self.WG, weight=None).todense(), self.A
+        )
+        np.testing.assert_equal(
+            nx.adjacency_matrix(self.MG2, weight=None).todense(), self.MG2A
+        )
+        np.testing.assert_equal(
+            nx.adjacency_matrix(self.WG, weight="other").todense(), 0.6 * self.WA
+        )
+        np.testing.assert_equal(
+            nx.adjacency_matrix(self.no_edges_G, nodelist=[1, 3]).todense(),
+            self.no_edges_A,
+        )
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_laplacian.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_laplacian.py
new file mode 100644
index 00000000..23f1b28e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_laplacian.py
@@ -0,0 +1,336 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+pytest.importorskip("scipy")
+
+import networkx as nx
+from networkx.generators.degree_seq import havel_hakimi_graph
+from networkx.generators.expanders import margulis_gabber_galil_graph
+
+
+class TestLaplacian:
+    @classmethod
+    def setup_class(cls):
+        deg = [3, 2, 2, 1, 0]
+        cls.G = havel_hakimi_graph(deg)
+        cls.WG = nx.Graph(
+            (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges()
+        )
+        cls.WG.add_node(4)
+        cls.MG = nx.MultiGraph(cls.G)
+
+        # Graph with clsloops
+        cls.Gsl = cls.G.copy()
+        for node in cls.Gsl.nodes():
+            cls.Gsl.add_edge(node, node)
+
+        # Graph used as an example in Sec. 4.1 of Langville and Meyer,
+        # "Google's PageRank and Beyond".
+        cls.DiG = nx.DiGraph()
+        cls.DiG.add_edges_from(
+            (
+                (1, 2),
+                (1, 3),
+                (3, 1),
+                (3, 2),
+                (3, 5),
+                (4, 5),
+                (4, 6),
+                (5, 4),
+                (5, 6),
+                (6, 4),
+            )
+        )
+        cls.DiMG = nx.MultiDiGraph(cls.DiG)
+        cls.DiWG = nx.DiGraph(
+            (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.DiG.edges()
+        )
+        cls.DiGsl = cls.DiG.copy()
+        for node in cls.DiGsl.nodes():
+            cls.DiGsl.add_edge(node, node)
+
+    def test_laplacian(self):
+        "Graph Laplacian"
+        # fmt: off
+        NL = np.array([[ 3, -1, -1, -1,  0],
+                       [-1,  2, -1,  0,  0],
+                       [-1, -1,  2,  0,  0],
+                       [-1,  0,  0,  1,  0],
+                       [ 0,  0,  0,  0,  0]])
+        # fmt: on
+        WL = 0.5 * NL
+        OL = 0.3 * NL
+        # fmt: off
+        DiNL = np.array([[ 2, -1, -1,  0,  0,  0],
+                         [ 0,  0,  0,  0,  0,  0],
+                         [-1, -1,  3, -1,  0,  0],
+                         [ 0,  0,  0,  2, -1, -1],
+                         [ 0,  0,  0, -1,  2, -1],
+                         [ 0,  0,  0,  0, -1,  1]])
+        # fmt: on
+        DiWL = 0.5 * DiNL
+        DiOL = 0.3 * DiNL
+        np.testing.assert_equal(nx.laplacian_matrix(self.G).todense(), NL)
+        np.testing.assert_equal(nx.laplacian_matrix(self.MG).todense(), NL)
+        np.testing.assert_equal(
+            nx.laplacian_matrix(self.G, nodelist=[0, 1]).todense(),
+            np.array([[1, -1], [-1, 1]]),
+        )
+        np.testing.assert_equal(nx.laplacian_matrix(self.WG).todense(), WL)
+        np.testing.assert_equal(nx.laplacian_matrix(self.WG, weight=None).todense(), NL)
+        np.testing.assert_equal(
+            nx.laplacian_matrix(self.WG, weight="other").todense(), OL
+        )
+
+        np.testing.assert_equal(nx.laplacian_matrix(self.DiG).todense(), DiNL)
+        np.testing.assert_equal(nx.laplacian_matrix(self.DiMG).todense(), DiNL)
+        np.testing.assert_equal(
+            nx.laplacian_matrix(self.DiG, nodelist=[1, 2]).todense(),
+            np.array([[1, -1], [0, 0]]),
+        )
+        np.testing.assert_equal(nx.laplacian_matrix(self.DiWG).todense(), DiWL)
+        np.testing.assert_equal(
+            nx.laplacian_matrix(self.DiWG, weight=None).todense(), DiNL
+        )
+        np.testing.assert_equal(
+            nx.laplacian_matrix(self.DiWG, weight="other").todense(), DiOL
+        )
+
+    def test_normalized_laplacian(self):
+        "Generalized Graph Laplacian"
+        # fmt: off
+        G = np.array([[ 1.   , -0.408, -0.408, -0.577,  0.],
+                      [-0.408,  1.   , -0.5  ,  0.   ,  0.],
+                      [-0.408, -0.5  ,  1.   ,  0.   ,  0.],
+                      [-0.577,  0.   ,  0.   ,  1.   ,  0.],
+                      [ 0.   ,  0.   ,  0.   ,  0.   ,  0.]])
+        GL = np.array([[ 1.   , -0.408, -0.408, -0.577,  0.   ],
+                       [-0.408,  1.   , -0.5  ,  0.   ,  0.   ],
+                       [-0.408, -0.5  ,  1.   ,  0.   ,  0.   ],
+                       [-0.577,  0.   ,  0.   ,  1.   ,  0.   ],
+                       [ 0.   ,  0.   ,  0.   ,  0.   ,  0.   ]])
+        Lsl = np.array([[ 0.75  , -0.2887, -0.2887, -0.3536,  0.    ],
+                        [-0.2887,  0.6667, -0.3333,  0.    ,  0.    ],
+                        [-0.2887, -0.3333,  0.6667,  0.    ,  0.    ],
+                        [-0.3536,  0.    ,  0.    ,  0.5   ,  0.    ],
+                        [ 0.    ,  0.    ,  0.    ,  0.    ,  0.    ]])
+
+        DiG = np.array([[ 1.    ,  0.    , -0.4082,  0.    ,  0.    ,  0.    ],
+                        [ 0.    ,  0.    ,  0.    ,  0.    ,  0.    ,  0.    ],
+                        [-0.4082,  0.    ,  1.    ,  0.    , -0.4082,  0.    ],
+                        [ 0.    ,  0.    ,  0.    ,  1.    , -0.5   , -0.7071],
+                        [ 0.    ,  0.    ,  0.    , -0.5   ,  1.    , -0.7071],
+                        [ 0.    ,  0.    ,  0.    , -0.7071,  0.     , 1.    ]])
+        DiGL = np.array([[ 1.    ,  0.    , -0.4082,  0.    ,  0.    ,  0.    ],
+                         [ 0.    ,  0.    ,  0.    ,  0.    ,  0.    ,  0.    ],
+                         [-0.4082,  0.    ,  1.    , -0.4082,  0.    ,  0.    ],
+                         [ 0.    ,  0.    ,  0.    ,  1.    , -0.5   , -0.7071],
+                         [ 0.    ,  0.    ,  0.    , -0.5   ,  1.    , -0.7071],
+                         [ 0.    ,  0.    ,  0.    ,  0.    , -0.7071,  1.    ]])
+        DiLsl = np.array([[ 0.6667, -0.5774, -0.2887,  0.    ,  0.    ,  0.    ],
+                          [ 0.    ,  0.    ,  0.    ,  0.    ,  0.    ,  0.    ],
+                          [-0.2887, -0.5   ,  0.75  , -0.2887,  0.    ,  0.    ],
+                          [ 0.    ,  0.    ,  0.    ,  0.6667, -0.3333, -0.4082],
+                          [ 0.    ,  0.    ,  0.    , -0.3333,  0.6667, -0.4082],
+                          [ 0.    ,  0.    ,  0.    ,  0.    , -0.4082,  0.5   ]])
+        # fmt: on
+
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.G, nodelist=range(5)).todense(),
+            G,
+            decimal=3,
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.G).todense(), GL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.MG).todense(), GL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.WG).todense(), GL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.WG, weight="other").todense(),
+            GL,
+            decimal=3,
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.Gsl).todense(), Lsl, decimal=3
+        )
+
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(
+                self.DiG,
+                nodelist=range(1, 1 + 6),
+            ).todense(),
+            DiG,
+            decimal=3,
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.DiG).todense(), DiGL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.DiMG).todense(), DiGL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.DiWG).todense(), DiGL, decimal=3
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.DiWG, weight="other").todense(),
+            DiGL,
+            decimal=3,
+        )
+        np.testing.assert_almost_equal(
+            nx.normalized_laplacian_matrix(self.DiGsl).todense(), DiLsl, decimal=3
+        )
+
+
+def test_directed_laplacian():
+    "Directed Laplacian"
+    # Graph used as an example in Sec. 4.1 of Langville and Meyer,
+    # "Google's PageRank and Beyond". The graph contains dangling nodes, so
+    # the pagerank random walk is selected by directed_laplacian
+    G = nx.DiGraph()
+    G.add_edges_from(
+        (
+            (1, 2),
+            (1, 3),
+            (3, 1),
+            (3, 2),
+            (3, 5),
+            (4, 5),
+            (4, 6),
+            (5, 4),
+            (5, 6),
+            (6, 4),
+        )
+    )
+    # fmt: off
+    GL = np.array([[ 0.9833, -0.2941, -0.3882, -0.0291, -0.0231, -0.0261],
+                   [-0.2941,  0.8333, -0.2339, -0.0536, -0.0589, -0.0554],
+                   [-0.3882, -0.2339,  0.9833, -0.0278, -0.0896, -0.0251],
+                   [-0.0291, -0.0536, -0.0278,  0.9833, -0.4878, -0.6675],
+                   [-0.0231, -0.0589, -0.0896, -0.4878,  0.9833, -0.2078],
+                   [-0.0261, -0.0554, -0.0251, -0.6675, -0.2078,  0.9833]])
+    # fmt: on
+    L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G))
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    # Make the graph strongly connected, so we can use a random and lazy walk
+    G.add_edges_from(((2, 5), (6, 1)))
+    # fmt: off
+    GL = np.array([[ 1.    , -0.3062, -0.4714,  0.    ,  0.    , -0.3227],
+                   [-0.3062,  1.    , -0.1443,  0.    , -0.3162,  0.    ],
+                   [-0.4714, -0.1443,  1.    ,  0.    , -0.0913,  0.    ],
+                   [ 0.    ,  0.    ,  0.    ,  1.    , -0.5   , -0.5   ],
+                   [ 0.    , -0.3162, -0.0913, -0.5   ,  1.    , -0.25  ],
+                   [-0.3227,  0.    ,  0.    , -0.5   , -0.25  ,  1.    ]])
+    # fmt: on
+    L = nx.directed_laplacian_matrix(
+        G, alpha=0.9, nodelist=sorted(G), walk_type="random"
+    )
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    # fmt: off
+    GL = np.array([[ 0.5   , -0.1531, -0.2357,  0.    ,  0.    , -0.1614],
+                   [-0.1531,  0.5   , -0.0722,  0.    , -0.1581,  0.    ],
+                   [-0.2357, -0.0722,  0.5   ,  0.    , -0.0456,  0.    ],
+                   [ 0.    ,  0.    ,  0.    ,  0.5   , -0.25  , -0.25  ],
+                   [ 0.    , -0.1581, -0.0456, -0.25  ,  0.5   , -0.125 ],
+                   [-0.1614,  0.    ,  0.    , -0.25  , -0.125 ,  0.5   ]])  
+    # fmt: on
+    L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G), walk_type="lazy")
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    # Make a strongly connected periodic graph
+    G = nx.DiGraph()
+    G.add_edges_from(((1, 2), (2, 4), (4, 1), (1, 3), (3, 4)))
+    # fmt: off
+    GL = np.array([[ 0.5  , -0.176, -0.176, -0.25 ],
+                   [-0.176,  0.5  ,  0.   , -0.176],
+                   [-0.176,  0.   ,  0.5  , -0.176],
+                   [-0.25 , -0.176, -0.176,  0.5  ]])
+    # fmt: on
+    L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G))
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+
+def test_directed_combinatorial_laplacian():
+    "Directed combinatorial Laplacian"
+    # Graph used as an example in Sec. 4.1 of Langville and Meyer,
+    # "Google's PageRank and Beyond". The graph contains dangling nodes, so
+    # the pagerank random walk is selected by directed_laplacian
+    G = nx.DiGraph()
+    G.add_edges_from(
+        (
+            (1, 2),
+            (1, 3),
+            (3, 1),
+            (3, 2),
+            (3, 5),
+            (4, 5),
+            (4, 6),
+            (5, 4),
+            (5, 6),
+            (6, 4),
+        )
+    )
+    # fmt: off
+    GL = np.array([[ 0.0366, -0.0132, -0.0153, -0.0034, -0.0020, -0.0027],
+                   [-0.0132,  0.0450, -0.0111, -0.0076, -0.0062, -0.0069],
+                   [-0.0153, -0.0111,  0.0408, -0.0035, -0.0083, -0.0027],
+                   [-0.0034, -0.0076, -0.0035,  0.3688, -0.1356, -0.2187],
+                   [-0.0020, -0.0062, -0.0083, -0.1356,  0.2026, -0.0505],
+                   [-0.0027, -0.0069, -0.0027, -0.2187, -0.0505,  0.2815]])
+    # fmt: on
+
+    L = nx.directed_combinatorial_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G))
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    # Make the graph strongly connected, so we can use a random and lazy walk
+    G.add_edges_from(((2, 5), (6, 1)))
+
+    # fmt: off
+    GL = np.array([[ 0.1395, -0.0349, -0.0465,  0.    ,  0.    , -0.0581],
+                   [-0.0349,  0.093 , -0.0116,  0.    , -0.0465,  0.    ],
+                   [-0.0465, -0.0116,  0.0698,  0.    , -0.0116,  0.    ],
+                   [ 0.    ,  0.    ,  0.    ,  0.2326, -0.1163, -0.1163],
+                   [ 0.    , -0.0465, -0.0116, -0.1163,  0.2326, -0.0581],
+                   [-0.0581,  0.    ,  0.    , -0.1163, -0.0581,  0.2326]])
+    # fmt: on
+
+    L = nx.directed_combinatorial_laplacian_matrix(
+        G, alpha=0.9, nodelist=sorted(G), walk_type="random"
+    )
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    # fmt: off
+    GL = np.array([[ 0.0698, -0.0174, -0.0233,  0.    ,  0.    , -0.0291],
+                   [-0.0174,  0.0465, -0.0058,  0.    , -0.0233,  0.    ],
+                   [-0.0233, -0.0058,  0.0349,  0.    , -0.0058,  0.    ],
+                   [ 0.    ,  0.    ,  0.    ,  0.1163, -0.0581, -0.0581],
+                   [ 0.    , -0.0233, -0.0058, -0.0581,  0.1163, -0.0291],
+                   [-0.0291,  0.    ,  0.    , -0.0581, -0.0291,  0.1163]])
+    # fmt: on
+
+    L = nx.directed_combinatorial_laplacian_matrix(
+        G, alpha=0.9, nodelist=sorted(G), walk_type="lazy"
+    )
+    np.testing.assert_almost_equal(L, GL, decimal=3)
+
+    E = nx.DiGraph(margulis_gabber_galil_graph(2))
+    L = nx.directed_combinatorial_laplacian_matrix(E)
+    # fmt: off
+    expected = np.array(
+        [[ 0.16666667, -0.08333333, -0.08333333,  0.        ],
+         [-0.08333333,  0.16666667,  0.        , -0.08333333],
+         [-0.08333333,  0.        ,  0.16666667, -0.08333333],
+         [ 0.        , -0.08333333, -0.08333333,  0.16666667]]
+    )
+    # fmt: on
+    np.testing.assert_almost_equal(L, expected, decimal=6)
+
+    with pytest.raises(nx.NetworkXError):
+        nx.directed_combinatorial_laplacian_matrix(G, walk_type="pagerank", alpha=100)
+    with pytest.raises(nx.NetworkXError):
+        nx.directed_combinatorial_laplacian_matrix(G, walk_type="silly")
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_modularity.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_modularity.py
new file mode 100644
index 00000000..9f94ff4d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_modularity.py
@@ -0,0 +1,87 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+pytest.importorskip("scipy")
+
+import networkx as nx
+from networkx.generators.degree_seq import havel_hakimi_graph
+
+
+class TestModularity:
+    @classmethod
+    def setup_class(cls):
+        deg = [3, 2, 2, 1, 0]
+        cls.G = havel_hakimi_graph(deg)
+        # Graph used as an example in Sec. 4.1 of Langville and Meyer,
+        # "Google's PageRank and Beyond". (Used for test_directed_laplacian)
+        cls.DG = nx.DiGraph()
+        cls.DG.add_edges_from(
+            (
+                (1, 2),
+                (1, 3),
+                (3, 1),
+                (3, 2),
+                (3, 5),
+                (4, 5),
+                (4, 6),
+                (5, 4),
+                (5, 6),
+                (6, 4),
+            )
+        )
+
+    def test_modularity(self):
+        "Modularity matrix"
+        # fmt: off
+        B = np.array([[-1.125,  0.25,  0.25,  0.625,  0.],
+                      [0.25, -0.5,  0.5, -0.25,  0.],
+                      [0.25,  0.5, -0.5, -0.25,  0.],
+                      [0.625, -0.25, -0.25, -0.125,  0.],
+                      [0.,  0.,  0.,  0.,  0.]])
+        # fmt: on
+
+        permutation = [4, 0, 1, 2, 3]
+        np.testing.assert_equal(nx.modularity_matrix(self.G), B)
+        np.testing.assert_equal(
+            nx.modularity_matrix(self.G, nodelist=permutation),
+            B[np.ix_(permutation, permutation)],
+        )
+
+    def test_modularity_weight(self):
+        "Modularity matrix with weights"
+        # fmt: off
+        B = np.array([[-1.125,  0.25,  0.25,  0.625,  0.],
+                      [0.25, -0.5,  0.5, -0.25,  0.],
+                      [0.25,  0.5, -0.5, -0.25,  0.],
+                      [0.625, -0.25, -0.25, -0.125,  0.],
+                      [0.,  0.,  0.,  0.,  0.]])
+        # fmt: on
+
+        G_weighted = self.G.copy()
+        for n1, n2 in G_weighted.edges():
+            G_weighted.edges[n1, n2]["weight"] = 0.5
+        # The following test would fail in networkx 1.1
+        np.testing.assert_equal(nx.modularity_matrix(G_weighted), B)
+        # The following test that the modularity matrix get rescaled accordingly
+        np.testing.assert_equal(
+            nx.modularity_matrix(G_weighted, weight="weight"), 0.5 * B
+        )
+
+    def test_directed_modularity(self):
+        "Directed Modularity matrix"
+        # fmt: off
+        B = np.array([[-0.2,  0.6,  0.8, -0.4, -0.4, -0.4],
+                      [0.,  0.,  0.,  0.,  0.,  0.],
+                      [0.7,  0.4, -0.3, -0.6,  0.4, -0.6],
+                      [-0.2, -0.4, -0.2, -0.4,  0.6,  0.6],
+                      [-0.2, -0.4, -0.2,  0.6, -0.4,  0.6],
+                      [-0.1, -0.2, -0.1,  0.8, -0.2, -0.2]])
+        # fmt: on
+        node_permutation = [5, 1, 2, 3, 4, 6]
+        idx_permutation = [4, 0, 1, 2, 3, 5]
+        mm = nx.directed_modularity_matrix(self.DG, nodelist=sorted(self.DG))
+        np.testing.assert_equal(mm, B)
+        np.testing.assert_equal(
+            nx.directed_modularity_matrix(self.DG, nodelist=node_permutation),
+            B[np.ix_(idx_permutation, idx_permutation)],
+        )
diff --git a/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_spectrum.py b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_spectrum.py
new file mode 100644
index 00000000..e9101303
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/linalg/tests/test_spectrum.py
@@ -0,0 +1,71 @@
+import pytest
+
+np = pytest.importorskip("numpy")
+pytest.importorskip("scipy")
+
+import networkx as nx
+from networkx.generators.degree_seq import havel_hakimi_graph
+
+
+class TestSpectrum:
+    @classmethod
+    def setup_class(cls):
+        deg = [3, 2, 2, 1, 0]
+        cls.G = havel_hakimi_graph(deg)
+        cls.P = nx.path_graph(3)
+        cls.WG = nx.Graph(
+            (u, v, {"weight": 0.5, "other": 0.3}) for (u, v) in cls.G.edges()
+        )
+        cls.WG.add_node(4)
+        cls.DG = nx.DiGraph()
+        nx.add_path(cls.DG, [0, 1, 2])
+
+    def test_laplacian_spectrum(self):
+        "Laplacian eigenvalues"
+        evals = np.array([0, 0, 1, 3, 4])
+        e = sorted(nx.laplacian_spectrum(self.G))
+        np.testing.assert_almost_equal(e, evals)
+        e = sorted(nx.laplacian_spectrum(self.WG, weight=None))
+        np.testing.assert_almost_equal(e, evals)
+        e = sorted(nx.laplacian_spectrum(self.WG))
+        np.testing.assert_almost_equal(e, 0.5 * evals)
+        e = sorted(nx.laplacian_spectrum(self.WG, weight="other"))
+        np.testing.assert_almost_equal(e, 0.3 * evals)
+
+    def test_normalized_laplacian_spectrum(self):
+        "Normalized Laplacian eigenvalues"
+        evals = np.array([0, 0, 0.7712864461218, 1.5, 1.7287135538781])
+        e = sorted(nx.normalized_laplacian_spectrum(self.G))
+        np.testing.assert_almost_equal(e, evals)
+        e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight=None))
+        np.testing.assert_almost_equal(e, evals)
+        e = sorted(nx.normalized_laplacian_spectrum(self.WG))
+        np.testing.assert_almost_equal(e, evals)
+        e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight="other"))
+        np.testing.assert_almost_equal(e, evals)
+
+    def test_adjacency_spectrum(self):
+        "Adjacency eigenvalues"
+        evals = np.array([-np.sqrt(2), 0, np.sqrt(2)])
+        e = sorted(nx.adjacency_spectrum(self.P))
+        np.testing.assert_almost_equal(e, evals)
+
+    def test_modularity_spectrum(self):
+        "Modularity eigenvalues"
+        evals = np.array([-1.5, 0.0, 0.0])
+        e = sorted(nx.modularity_spectrum(self.P))
+        np.testing.assert_almost_equal(e, evals)
+        # Directed modularity eigenvalues
+        evals = np.array([-0.5, 0.0, 0.0])
+        e = sorted(nx.modularity_spectrum(self.DG))
+        np.testing.assert_almost_equal(e, evals)
+
+    def test_bethe_hessian_spectrum(self):
+        "Bethe Hessian eigenvalues"
+        evals = np.array([0.5 * (9 - np.sqrt(33)), 4, 0.5 * (9 + np.sqrt(33))])
+        e = sorted(nx.bethe_hessian_spectrum(self.P, r=2))
+        np.testing.assert_almost_equal(e, evals)
+        # Collapses back to Laplacian:
+        e1 = sorted(nx.bethe_hessian_spectrum(self.P, r=1))
+        e2 = sorted(nx.laplacian_spectrum(self.P))
+        np.testing.assert_almost_equal(e1, e2)