Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tests/testthat/_snaps/community.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@
Error:
! The `membership` argument of `modularity_matrix()` is no longer used as of igraph 2.1.0.

# modularity_matrix() covers migrated tail args and positional recovery

Code
modularity_matrix(karate, rep(1, vcount(karate)), rep(1, ecount(karate)))
Condition
Warning:
Calling `modularity_matrix()` with positional or abbreviated arguments was deprecated in igraph 3.0.0.
i Detected call: modularity_matrix(graph, membership, weights)
i Use instead: modularity_matrix(graph, membership, weights = )
Error:
! The `membership` argument of `modularity_matrix()` is no longer used as of igraph 2.1.0.

321 changes: 321 additions & 0 deletions tests/testthat/test-centrality.R
Original file line number Diff line number Diff line change
Expand Up @@ -936,3 +936,324 @@ test_that("arpack() errors well", {
)
})
})

# ---- ellipsis migration: argument coverage ----------------------------

test_that("betweenness() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
ring <- make_ring(5)
# The weight attribute is a decoy that the explicit `weights` must override.
E(ring)$weight <- c(100, 1, 1, 1, 1)

res <- betweenness(
ring,
v = V(ring)[1:3],
directed = FALSE,
weights = rep(1, 5),
normalized = TRUE,
cutoff = 2
)
# In C5 with unit weights each vertex lies on exactly one geodesic,
# and normalization divides by (n - 1) * (n - 2) / 2 = 6.
expect_equal(res, rep(1 / 6, 3))
# A cutoff of 1 removes all paths that have intermediate vertices.
expect_equal(
betweenness(ring, weights = rep(1, 5), cutoff = 1),
rep(0, 5)
)

lifecycle::expect_deprecated(
res_legacy <- betweenness(ring, V(ring), FALSE)
)
expect_identical(res_legacy, betweenness(ring, V(ring), directed = FALSE))
})

test_that("closeness() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
path <- make_graph(c(1, 2, 2, 3), directed = TRUE)
# The weight attribute is a decoy that the explicit `weights` must override.
E(path)$weight <- c(5, 5)

res <- closeness(
path,
vids = V(path)[3],
mode = "in",
weights = c(1, 1),
normalized = TRUE,
cutoff = -1
)
# Vertex 3 is reached with distances 1 and 2, so 2 / (1 + 2).
expect_equal(res, 2 / 3)
# With a cutoff of 1 only the direct predecessor remains.
expect_equal(
closeness(
path,
vids = V(path)[3],
mode = "in",
weights = c(1, 1),
cutoff = 1
),
1
)

lifecycle::expect_deprecated(
res_legacy <- closeness(path, V(path), "in")
)
expect_identical(res_legacy, closeness(path, V(path), mode = "in"))
})

test_that("edge_betweenness() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
ring <- make_ring(5)
# The weight attribute is a decoy that the explicit `weights` must override.
E(ring)$weight <- c(100, 1, 1, 1, 1)

res <- edge_betweenness(
ring,
e = E(ring)[1:3],
directed = FALSE,
weights = rep(1, 5),
cutoff = -1
)
# In C5 with unit weights each edge carries three geodesics.
expect_equal(res, rep(3, 3))
# With a cutoff of 1 each edge only carries the path of its endpoints.
expect_equal(
edge_betweenness(ring, e = E(ring)[1:3], weights = rep(1, 5), cutoff = 1),
rep(1, 3)
)

lifecycle::expect_deprecated(
res_legacy <- edge_betweenness(ring, E(ring), FALSE)
)
expect_identical(
res_legacy,
edge_betweenness(ring, E(ring), directed = FALSE)
)
})

test_that("harmonic_centrality() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
path <- make_graph(c(1, 2, 2, 3), directed = TRUE)
# The weight attribute is a decoy that the explicit `weights` must override.
E(path)$weight <- c(5, 5)

res <- harmonic_centrality(
path,
vids = V(path)[3],
mode = "in",
weights = c(1, 1),
normalized = TRUE,
cutoff = -1
)
# Vertex 3 collects inverse distances 1 + 1/2, normalized by n - 1 = 2.
expect_equal(res, 0.75)
# The cutoff drops the two-step path from vertex 1.
expect_equal(
harmonic_centrality(
path,
vids = V(path)[3],
mode = "in",
weights = c(1, 1),
normalized = TRUE,
cutoff = 1
),
0.5
)

lifecycle::expect_deprecated(
res_legacy <- harmonic_centrality(path, V(path), "in")
)
expect_identical(res_legacy, harmonic_centrality(path, V(path), mode = "in"))
})

test_that("page_rank() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
star <- make_star(10, mode = "undirected")
# The weight attribute is a decoy that the explicit `weights` must override.
E(star)$weight <- c(10, rep(1, 8))

# `algo` keeps its default value:
# non-default values select the legacy ARPACK implementation,
# and `options` is only consumed by that implementation.
res <- page_rank(
star,
algo = "prpack",
vids = V(star)[1:5],
directed = FALSE,
damping = 0.9,
personalized = c(1, rep(0, 9)),
weights = rep(1, 9),
options = arpack_defaults()
)
expect_length(res$vector, 5)
# All personalization mass sits on the hub, so it dominates the leaves,
# and the unit weights keep the leaves interchangeable.
expect_true(res$vector[1] > max(res$vector[-1]))
expect_equal(sd(res$vector[-1]), 0)
# PRPACK ignores the ARPACK options, and `vids` merely subsets the result.
res_full <- page_rank(
star,
directed = FALSE,
damping = 0.9,
personalized = c(1, rep(0, 9)),
weights = rep(1, 9)
)
expect_equal(res$vector, res_full$vector[1:5])
expect_equal(sum(res_full$vector), 1)

lifecycle::expect_deprecated(
res_legacy <- page_rank(star, "prpack")
)
expect_identical(res_legacy, page_rank(star, algo = "prpack"))
})

test_that("strength() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
star <- make_star(6, mode = "out")
star <- add_edges(star, c(2, 2))
E(star)$weight <- 1:6

res <- strength(
star,
vids = V(star)[1:3],
mode = "out",
loops = FALSE,
weights = 1:6
)
# Only the hub has non-loop out-edges, with weights 1 to 5.
expect_equal(res, c(15, 0, 0))
# Counting loops adds the loop weight 6 to vertex 2.
expect_equal(
strength(
star,
vids = V(star)[1:3],
mode = "out",
loops = TRUE,
weights = 1:6
),
c(15, 6, 0)
)

lifecycle::expect_deprecated(
res_legacy <- strength(star, V(star), "in")
)
expect_identical(res_legacy, strength(star, V(star), mode = "in"))
})

test_that("diversity() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
ring <- make_ring(10)

res <- diversity(ring, weights = 1:10, vids = V(ring)[1:4])
# Scaled entropy of the two incident edge weights, e.g. {10, 1} for vertex 1.
expect_equal(
res,
c(0.4394970, 0.9182958, 0.9709506, 0.9852281),
tolerance = 1e-6
)

lifecycle::expect_deprecated(
res_legacy <- diversity(ring, 1:10)
)
expect_identical(res_legacy, diversity(ring, weights = 1:10))
})

test_that("subgraph_centrality() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
# A square with a loop on vertex 1, so that `diag` has a visible effect.
looped <- make_graph(c(1, 2, 2, 3, 3, 4, 4, 1, 1, 1), directed = FALSE)

res <- subgraph_centrality(looped, diag = TRUE)
expect_equal(
res,
Matrix::diag(Matrix::expm(as_adjacency_matrix(looped, sparse = FALSE))),
tolerance = 1e-10
)
expect_false(isTRUE(all.equal(res, subgraph_centrality(looped))))

lifecycle::expect_deprecated(
res_legacy <- subgraph_centrality(looped, TRUE)
)
expect_identical(res_legacy, subgraph_centrality(looped, diag = TRUE))
})

test_that("power_centrality() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
ring <- make_ring(5)
# The weight attribute is a decoy that the explicit `weights` must override.
E(ring)$weight <- c(1.5, 2.5, 3.5, 4.5, 5.5)

res <- power_centrality(
ring,
nodes = V(ring)[1:3],
loops = FALSE,
exponent = 0.2,
rescale = TRUE,
tol = 1e-10,
sparse = FALSE,
weights = rep(1, 5)
)
# With unit weights the ring is symmetric and rescaled scores sum to one.
expect_equal(res, rep(1 / 5, 3))

# `loops` toggles the adjacency diagonal of a path with a loop on vertex 2.
looped <- make_graph(c(1, 2, 2, 3, 2, 2), directed = FALSE)
expect_false(isTRUE(all.equal(
power_centrality(looped, loops = TRUE, sparse = FALSE),
power_centrality(looped, loops = FALSE, sparse = FALSE)
)))

lifecycle::expect_deprecated(
res_legacy <- power_centrality(looped, V(looped), TRUE)
)
expect_identical(
res_legacy,
power_centrality(looped, V(looped), loops = TRUE)
)
})

test_that("alpha_centrality() covers migrated tail args and positional recovery", {
rlang::local_options(lifecycle_verbosity = "warning")
# A small DAG with a loop on vertex 3 and a decoy weight attribute.
dag <- make_graph(c(1, 3, 2, 3, 3, 4, 4, 5, 3, 3))
E(dag)$weight <- rep(7, 5)

base <- alpha_centrality(
dag,
alpha = 0.5,
loops = TRUE,
weights = NA,
tol = 1e-8,
sparse = FALSE
)
expect_equal(base, c(1, 1, 4, 3, 2.5))
# The scores are linear in the exogenous input.
res <- alpha_centrality(
dag,
nodes = V(dag)[1:3],
alpha = 0.5,
loops = TRUE,
exo = 2,
weights = NA,
tol = 1e-8,
sparse = FALSE
)
expect_equal(res, 2 * base[1:3])
# Ignoring the loop changes the scores.
expect_false(isTRUE(all.equal(
base,
alpha_centrality(
dag,
alpha = 0.5,
loops = FALSE,
weights = NA,
sparse = FALSE
)
)))

lifecycle::expect_deprecated(
res_legacy <- alpha_centrality(dag, V(dag), 0.75)
)
expect_identical(res_legacy, alpha_centrality(dag, V(dag), alpha = 0.75))
})
Loading
Loading