diff --git a/src/vertex_components.cpp b/src/vertex_components.cpp index 850aae9b..c48f8742 100644 --- a/src/vertex_components.cpp +++ b/src/vertex_components.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include namespace nb = nanobind; using namespace nb::literals; @@ -16,6 +18,16 @@ namespace pyigl igl::vertex_components(F, C); return C; } + + // Wrapper for vertex_components with adjacency matrix + auto vertex_components_from_adjacency_matrix( + const Eigen::SparseMatrixI &adjacency) + { + Eigen::VectorXI c; + Eigen::VectorXI counts; + igl::vertex_components(adjacency, c, counts); + return std::make_tuple(c, counts); + } } // Bind the wrappers to the Python module @@ -30,4 +42,13 @@ void bind_vertex_components(nb::module_ &m) @param[in] F #F by 3 matrix of triangle (face) indices @return Vector C of per-vertex connected-component ids)"); + + m.def( + "vertex_components_from_adjacency_matrix", + &pyigl::vertex_components_from_adjacency_matrix, + "adjacency"_a, + R"(Compute the connected components of a graph using an adjacency matrix, returning component IDs and counts. + +@param[in] adjacency n by n sparse adjacency matrix +@return A tuple (c, counts) where c is an array of component ids (starting with 0) and counts is a #components array of counts for each component)"); } diff --git a/tests/test_all.py b/tests/test_all.py index 370c7431..27c70ca1 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -1791,3 +1791,24 @@ def test_resolve_duplicated_faces(): F = np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2], [3, 4, 5]], dtype=np.int64) F2, J = igl.resolve_duplicated_faces(F) assert set(map(tuple, F2.tolist())) == {(3, 4, 5)} + + +def test_vertex_components_from_adjacency_matrix(): + # Two disconnected components: a triangle {0,1,2} and an edge {3,4}. + edges = [(0, 1), (1, 2), (0, 2), (3, 4)] + n = 5 + rows, cols = [], [] + for i, j in edges: + rows += [i, j] + cols += [j, i] + A = scipy.sparse.csr_matrix( + (np.ones(len(rows)), (rows, cols)), shape=(n, n)).astype(np.int64) + c, counts = igl.vertex_components_from_adjacency_matrix(A) + assert c.shape[0] == n + # vertices in the same component share an id; different components differ + assert c[0] == c[1] == c[2] + assert c[3] == c[4] + assert c[0] != c[3] + # counts is per-component and sums to the number of vertices + assert counts.sum() == n + assert sorted(counts.ravel().tolist()) == [2, 3]