Skip to content

Commit

Permalink
fix: subgraph_centrality() now ignores edge directions (#1414)
Browse files Browse the repository at this point in the history
  • Loading branch information
aviator-app[bot] committed Jul 2, 2024
2 parents 19f9c84 + c7cdef6 commit 68fa712
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 13 deletions.
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)
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"))
)
})

0 comments on commit 68fa712

Please sign in to comment.