|
| 1 | +# rSpectral modularity() now auto-uses the "weight" edge attribute |
| 2 | +# Issue: rSpectral's stored test graphs carry a "weight" attribute. Previously |
| 3 | +# modularity() ignored it unless weights = E(g)$weight was passed explicitly; |
| 4 | +# now modularity() auto-detects and uses the attribute, changing the computed |
| 5 | +# values and breaking baseline assertions. |
| 6 | + |
| 7 | +library(igraph) |
| 8 | + |
| 9 | +# A small graph with a weight attribute |
| 10 | +g <- make_ring(5) |
| 11 | +E(g)$weight <- c(1, 2, 3, 4, 5) |
| 12 | + |
| 13 | +# Same membership, two different modularity calls |
| 14 | +membership <- c(1, 1, 2, 2, 2) |
| 15 | + |
| 16 | +# Old behaviour (ignored weights unless passed explicitly): |
| 17 | +# the value below is what modularity() returned before the change |
| 18 | +modularity(g, membership, weights = rep(1, ecount(g))) |
| 19 | + |
| 20 | +# New behaviour (auto-detects $weight): |
| 21 | +modularity(g, membership) |
| 22 | + |
| 23 | +# These two now differ -- which is exactly what breaks rSpectral's tests. |
| 24 | + |
| 25 | +# Root cause: |
| 26 | +# - Around igraph 2.2.1.9004, modularity() was changed to use the "weight" |
| 27 | +# edge attribute automatically when present: |
| 28 | +# if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { |
| 29 | +# weights <- E(graph)$weight |
| 30 | +# } |
| 31 | +# - rSpectral's stored test graphs carry a "weight" attribute that was not |
| 32 | +# intended to be consumed by modularity(). |
| 33 | + |
| 34 | +# Assessment: |
| 35 | +# - Behavioural change in igraph. Inadvertent semantics shift for callers |
| 36 | +# that did not intend to use weights. There is currently no clean |
| 37 | +# `weights = NA` opt-out. |
| 38 | + |
| 39 | +# Recommendation: |
| 40 | +# - For igraph (action required before notifying rSpectral): provide a clean |
| 41 | +# opt-out -- e.g. accept `weights = NA` to disable auto-detection -- and |
| 42 | +# document the contract change in NEWS.md. |
| 43 | +# - For rSpectral (once an opt-out exists, or after igraph adjusts): |
| 44 | +# 1. Determine whether the stored graphs were intended to carry $weight. |
| 45 | +# 2. If not: g <- igraph::delete_edge_attr(g, "weight") before modularity() |
| 46 | +# and run igraph::upgrade_graph() on stored graph objects. |
| 47 | +# 3. If yes: update the expected modularity baselines. |
| 48 | + |
| 49 | +# Workaround that happens to disable auto-detection today (DO NOT recommend |
| 50 | +# to downstream maintainers -- relies on implementation detail): |
| 51 | +# modularity(g, membership, weights = numeric()) |
0 commit comments