Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: New largest_component() returns the largest connected component #786

Merged
merged 10 commits into from
May 22, 2023
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ export(laplacian_matrix)
export(largest.cliques)
export(largest.independent.vertex.sets)
export(largest_cliques)
export(largest_component)
export(largest_ivs)
export(largest_weighted_cliques)
export(last_cit)
Expand Down
17 changes: 17 additions & 0 deletions R/components.R
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,20 @@ bridges <- bridges_impl
#' @family components
#' @export
biconnected_components <- biconnected_components_impl


#' @rdname components
#' @family components
#' @export
largest_component <- function(graph, mode = c("weak", "strong")) {
if (!is_igraph(graph)) {
stop("Not a graph object")
}

comps <- components(graph, mode = mode)

lcc_id <- which.max(comps$csize)
vids <- V(graph)[comps$membership == lcc_id]

induced_subgraph(graph, vids)
}
9 changes: 8 additions & 1 deletion R/structural.properties.R
Original file line number Diff line number Diff line change
Expand Up @@ -1846,6 +1846,11 @@ dfs <- function(graph, root, mode = c("out", "in", "all", "total"),
#' `component_distribution()` creates a histogram for the maximal connected
#' component sizes.
#'
#' `largest_component()` returns the largest connected component of a graph. For
#' directed graphs, optionally the largest weakly or strongly connected component.
#' In case of a tie, the first component by vertex ID order is returned. Vertex
#' IDs from the original graph are not retained in the returned graph.
#'
#' The weakly connected components are found by a simple breadth-first search.
#' The strongly connected components are implemented by two consecutive
#' depth-first searches.
Expand All @@ -1870,6 +1875,8 @@ dfs <- function(graph, root, mode = c("out", "in", "all", "total"),
#' frequencies. The length of the vector is the size of the largest component
#' plus one. Note that (for currently unknown reasons) the first element of the
#' vector is the number of clusters of size zero, so this is always zero.
#'
#' For `largest_component()` the largest connected component of the graph.
#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
#' @seealso [decompose()], [subcomponent()], [groups()]
#' @family structural.properties
Expand All @@ -1880,7 +1887,7 @@ dfs <- function(graph, root, mode = c("out", "in", "all", "total"),
#' g <- sample_gnp(20, 1 / 20)
#' clu <- components(g)
#' groups(clu)
#'
#' largest_component(g)
components <- function(graph, mode = c("weak", "strong")) {
# Argument checks
ensure_igraph(graph)
Expand Down
17 changes: 16 additions & 1 deletion man/components.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 68 additions & 0 deletions tests/testthat/test-components.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
test_that("count_components counts correctly", {
g <- make_star(20, "undirected")
h <- make_ring(10)

G <- disjoint_union(g, h)

expect_that(count_components(G), equals(2L))
})

test_that("a null graph has zero components", {
g <- make_empty_graph(0)

expect_that(count_components(g), equals(0L))
})

test_that("component_distribution finds correct distribution", {
g <- graph_from_literal(
A,
B - C,
D - E - F,
G - H
)

ref <- c(0.00, 0.25, 0.50, 0.25)

expect_that(component_distribution(g), equals(ref))
})

test_that("largest component is actually the largest", {
g <- make_star(20, "undirected")
h <- make_ring(10)

G <- disjoint_union(g, h)

expect_true(isomorphic(largest_component(G), g))
})

test_that("largest strongly and weakly components are correct", {
g <- graph_from_literal(
A -+ B,
B -+ C,
C -+ A,
C -+ D,
E
)

strongly <- graph_from_literal(
A -+ B,
B -+ C,
C -+ A
)
weakly <- graph_from_literal(
A -+ B,
B -+ C,
C -+ A,
C -+ D
)

expect_true(isomorphic(largest_component(g, "weak"), weakly))
expect_true(isomorphic(largest_component(g, "strong"), strongly))
})

test_that("the largest component of a null graph is a valid null graph", {
nullgraph <- make_empty_graph(0)

expect_true(isomorphic(largest_component(make_empty_graph(0)), nullgraph))
})