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

fix: subgraph_centrality() now ignores edge directions #1414

Merged
merged 8 commits into from
Jul 2, 2024
Merged
17 changes: 11 additions & 6 deletions R/centrality.R
Original file line number Diff line number Diff line change
Expand Up @@ -766,16 +766,15 @@ arpack.unpack.complex <- function(vectors, values, nev) {
#' Subgraph centrality of a vertex measures the number of subgraphs a vertex
#' participates in, weighting them according to their size.
#'
#' The subgraph centrality of a vertex is defined as the number of closed loops
#' originating at the vertex, where longer loops are exponentially
#' downweighted.
#' The subgraph centrality of a vertex is defined as the number of closed walks
#' originating at the vertex, where longer walks are downweighted by the
#' factorial of their length.
#'
#' Currently the calculation is performed by explicitly calculating all
#' eigenvalues and eigenvectors of the adjacency matrix of the graph. This
#' effectively means that the measure can only be calculated for small graphs.
#'
#' @param graph The input graph, it should be undirected, but the
#' implementation does not check this currently.
#' @param graph The input graph. It will be treated as undirected.
#' @param diag Boolean scalar, whether to include the diagonal of the adjacency
#' matrix in the analysis. Giving `FALSE` here effectively eliminates the
#' loops edges from the graph before the calculation.
Expand All @@ -799,7 +798,13 @@ subgraph_centrality <- function(graph, diag = FALSE) {
if (!diag) {
diag(A) <- 0
}
eig <- eigen(A)
# Ignore edge directions in directed graphs
if (is_directed(graph)) {
A <- A + Matrix::t(A)
}
# This calls lapack and creates a dense matrix, but accepts the sparse matrix A
# We can choose to convert A to a dense matrix right away, but it doesn't matter
eig <- eigen(A, symmetric = TRUE)
maelle marked this conversation as resolved.
Show resolved Hide resolved
res <- as.vector(eig$vectors^2 %*% exp(eig$values))
if (igraph_opt("add.vertex.names") && is_named(graph)) {
names(res) <- vertex_attr(graph, "name")
Expand Down
3 changes: 1 addition & 2 deletions man/subgraph.centrality.Rd

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

9 changes: 4 additions & 5 deletions man/subgraph_centrality.Rd

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

24 changes: 24 additions & 0 deletions tests/testthat/test-centrality.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
test_that("subgraph_centrality() works", {
frucht_graph <- make_graph("Frucht")
expect_equal(
subgraph_centrality(frucht_graph),
Matrix::diag(Matrix::expm(as_adj(frucht_graph, sparse = FALSE))),
tolerance = 1e-10
)

grotzsch_graph <- make_graph("Grotzsch")
expect_equal(
subgraph_centrality(grotzsch_graph),
Matrix::diag(Matrix::expm(as_adj(grotzsch_graph, sparse = FALSE))),
tolerance = 1e-10
)
})

test_that("subgraph_centrality() ignored edge directions", {
withr::local_seed(137)
g <- sample_gnm(10, 20, directed = TRUE)
expect_equal(
subgraph_centrality((g)),
subgraph_centrality(as.undirected(g, mode = "each"))
)
})
Loading