diff --git a/R/centrality.R b/R/centrality.R index 8c0a855d026..a8ff9ae41be 100644 --- a/R/centrality.R +++ b/R/centrality.R @@ -1716,9 +1716,10 @@ diversity <- function( #' scores are the same as authority scores. #' #' @param graph The input graph. -#' @param scale Logical, whether to scale the result to have a maximum -#' score of one. If no scaling is used then the result vector has unit length -#' in the Euclidean norm. +#' @param scale `r lifecycle::badge("superseded")` Logical, whether to scale +#' the result to have a maximum score of one, which the C core now always does. +#' With `FALSE`, the result vector is rescaled to unit length in the Euclidean norm, +#' except for graphs without (nonzero) edges, where all scores stay one. #' @param weights Optional positive weight vector for calculating weighted #' scores. If the graph has a `weight` edge attribute, then this is used #' by default. Pass `NA` to ignore the weight attribute. This function diff --git a/R/community.R b/R/community.R index 33dad0f2777..e0a8b015568 100644 --- a/R/community.R +++ b/R/community.R @@ -2283,6 +2283,20 @@ cluster_edge_betweenness <- function( as.logical(modularity), as.logical(membership) ) + # igraph 0.10 warned about weighted runs in the C core, which no longer does; + # only the first of its two warnings reached R. + if (!is.null(weights)) { + if (isTRUE(as.logical(membership))) { + cli::cli_warn( + "Membership vector will be selected based on the highest modularity score." + ) + } else if (isTRUE(as.logical(modularity))) { + cli::cli_warn(paste( + "Modularity calculation with weighted edge betweenness community detection might not make sense --", + "modularity treats edge weights as similarities while edge betweenness treats them as distances." + )) + } + } if (igraph_opt("add.vertex.names") && is_named(graph)) { res$names <- V(graph)$name } diff --git a/R/paths.R b/R/paths.R index b994d791c2e..92650d5944c 100644 --- a/R/paths.R +++ b/R/paths.R @@ -450,16 +450,6 @@ graph_center <- function( ) } -# Upstream merged the weighted `_dijkstra` variants into the base functions, -# which take their weights argument (krlmlr/igraph@d8febb1): the -# `_dijkstra_impl()` names stay, as aliases with the same arguments. -average_path_length_dijkstra_impl <- average_path_length_impl -diameter_dijkstra_impl <- diameter_impl -eccentricity_dijkstra_impl <- eccentricity_impl -graph_center_dijkstra_impl <- graph_center_impl -pseudo_diameter_dijkstra_impl <- pseudo_diameter_impl -radius_dijkstra_impl <- radius_impl - #' @rdname distances #' @inheritParams rlang::args_dots_empty #' @param directed Whether to consider directed paths in directed graphs, diff --git a/man/hits_scores.Rd b/man/hits_scores.Rd index ee1440b68c5..56a8c681300 100644 --- a/man/hits_scores.Rd +++ b/man/hits_scores.Rd @@ -11,9 +11,10 @@ hits_scores(graph, ..., scale = TRUE, weights = NULL, options = NULL) \item{...}{These dots are for future extensions and must be empty.} -\item{scale}{Logical, whether to scale the result to have a maximum -score of one. If no scaling is used then the result vector has unit length -in the Euclidean norm.} +\item{scale}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} Logical, whether to scale +the result to have a maximum score of one, which the C core now always does. +With \code{FALSE}, the result vector is rescaled to unit length in the Euclidean norm, +except for graphs without (nonzero) edges, where all scores stay one.} \item{weights}{Optional positive weight vector for calculating weighted scores. If the graph has a \code{weight} edge attribute, then this is used diff --git a/src/rinterface_extra.c b/src/rinterface_extra.c index 303844cd0b9..dfc199e37a0 100644 --- a/src/rinterface_extra.c +++ b/src/rinterface_extra.c @@ -6001,20 +6001,10 @@ SEXP Rx_igraph_community_edge_betweenness(SEXP graph, SEXP pweights, * weights as path lengths for the betweenness, and to weigh the modularity * that picks the membership. So the edges are removed by lengths, and the * merges, modularity and membership come from - * igraph_community_eb_get_merges() with the weights, as igraph 0.10 did, - * with the warnings it gave. */ + * igraph_community_eb_get_merges() with the weights, as igraph 0.10 did. + * The warnings igraph 0.10 gave here are raised by cluster_edge_betweenness(). */ if (ppweights) { IGRAPH_R_CHECK(igraph_community_edge_betweenness(&g, &res, ppeb, 0, 0, 0, 0, directed, /* weights = */ 0, /* lengths = */ ppweights)); - if (ppmembership) { - IGRAPH_WARNING("Membership vector will be selected based on the highest " - "modularity score."); - } - if (ppmodularity || ppmembership) { - IGRAPH_WARNING("Modularity calculation with weighted edge betweenness " - "community detection might not make sense -- modularity treats edge " - "weights as similarities while edge betwenness treats them as " - "distances."); - } if (ppmerges || ppbridges || ppmodularity || ppmembership) { IGRAPH_R_CHECK(igraph_community_eb_get_merges(&g, directed, &res, ppweights, ppmerges, ppbridges, ppmodularity, ppmembership)); } diff --git a/tests/testthat/_snaps/aaa-auto.md b/tests/testthat/_snaps/aaa-auto.md index 89ee4cde420..c251ea20cab 100644 --- a/tests/testthat/_snaps/aaa-auto.md +++ b/tests/testthat/_snaps/aaa-auto.md @@ -3689,32 +3689,32 @@ Error in `ensure_igraph()`: ! Must provide a graph object (provided `NULL`). -# eccentricity_dijkstra_impl basic +# eccentricity_impl modes Code - eccentricity_dijkstra_impl(graph = g) + eccentricity_impl(graph = g) Output [1] 2 1 2 --- Code - eccentricity_dijkstra_impl(graph = g, mode = "in") + eccentricity_impl(graph = g, mode = "in") Output [1] 2 1 2 -# eccentricity_dijkstra_impl errors +# eccentricity_impl errors Code - eccentricity_dijkstra_impl(graph = NULL) + eccentricity_impl(graph = NULL) Condition Error in `ensure_igraph()`: ! Must provide a graph object (provided `NULL`). -# graph_center_dijkstra_impl basic +# graph_center_impl modes Code - graph_center_dijkstra_impl(graph = g) + graph_center_impl(graph = g) Output + 1/3 vertex: [1] 2 @@ -3722,37 +3722,37 @@ --- Code - graph_center_dijkstra_impl(graph = g, mode = "in") + graph_center_impl(graph = g, mode = "in") Output + 1/3 vertex: [1] 2 -# graph_center_dijkstra_impl errors +# graph_center_impl errors Code - graph_center_dijkstra_impl(graph = NULL) + graph_center_impl(graph = NULL) Condition Error in `ensure_igraph()`: ! Must provide a graph object (provided `NULL`). -# radius_dijkstra_impl basic +# radius_impl modes Code - radius_dijkstra_impl(graph = g) + radius_impl(graph = g) Output [1] 1 --- Code - radius_dijkstra_impl(graph = g, mode = "in") + radius_impl(graph = g, mode = "in") Output [1] 1 -# radius_dijkstra_impl errors +# radius_impl errors Code - radius_dijkstra_impl(graph = NULL) + radius_impl(graph = NULL) Condition Error in `ensure_igraph()`: ! Must provide a graph object (provided `NULL`). @@ -3795,45 +3795,6 @@ Error in `ensure_igraph()`: ! Must provide a graph object (provided `NULL`). -# pseudo_diameter_dijkstra_impl basic - - Code - pseudo_diameter_dijkstra_impl(graph = g, start_vid = 1) - Output - $diameter - [1] 2 - - $from - [1] 0 - - $to - [1] 2 - - ---- - - Code - pseudo_diameter_dijkstra_impl(graph = g, start_vid = 1, directed = FALSE, - unconnected = FALSE) - Output - $diameter - [1] 2 - - $from - [1] 0 - - $to - [1] 2 - - -# pseudo_diameter_dijkstra_impl errors - - Code - pseudo_diameter_dijkstra_impl(graph = NULL, start_vid = 1) - Condition - Error in `ensure_igraph()`: - ! Must provide a graph object (provided `NULL`). - # diversity_impl basic Code diff --git a/tests/testthat/test-aaa-auto.R b/tests/testthat/test-aaa-auto.R index 34095875e31..96803516c03 100644 --- a/tests/testthat/test-aaa-auto.R +++ b/tests/testthat/test-aaa-auto.R @@ -3827,92 +3827,92 @@ test_that("contract_vertices_impl errors", { )) }) -# 150. eccentricity_dijkstra_impl +# 150. eccentricity_impl -test_that("eccentricity_dijkstra_impl basic", { +test_that("eccentricity_impl modes", { igraph_local_seed(20250909) g <- path_graph_impl( n = 3 ) - expect_snapshot(eccentricity_dijkstra_impl( + expect_snapshot(eccentricity_impl( graph = g )) - expect_snapshot(eccentricity_dijkstra_impl( + expect_snapshot(eccentricity_impl( graph = g, mode = "in" )) # Structured tests - result <- eccentricity_dijkstra_impl( + result <- eccentricity_impl( graph = g ) expect_true(is.numeric(result)) }) -test_that("eccentricity_dijkstra_impl errors", { +test_that("eccentricity_impl errors", { igraph_local_seed(20250909) - expect_snapshot_igraph_error(eccentricity_dijkstra_impl( + expect_snapshot_igraph_error(eccentricity_impl( graph = NULL )) }) -# 151. graph_center_dijkstra_impl +# 151. graph_center_impl -test_that("graph_center_dijkstra_impl basic", { +test_that("graph_center_impl modes", { igraph_local_seed(20250909) g <- path_graph_impl( n = 3 ) - expect_snapshot(graph_center_dijkstra_impl( + expect_snapshot(graph_center_impl( graph = g )) - expect_snapshot(graph_center_dijkstra_impl( + expect_snapshot(graph_center_impl( graph = g, mode = "in" )) # Structured tests - result <- graph_center_dijkstra_impl( + result <- graph_center_impl( graph = g ) expect_s3_class(result, "igraph.vs") }) -test_that("graph_center_dijkstra_impl errors", { +test_that("graph_center_impl errors", { igraph_local_seed(20250909) - expect_snapshot_igraph_error(graph_center_dijkstra_impl( + expect_snapshot_igraph_error(graph_center_impl( graph = NULL )) }) -# 152. radius_dijkstra_impl +# 152. radius_impl -test_that("radius_dijkstra_impl basic", { +test_that("radius_impl modes", { igraph_local_seed(20250909) g <- path_graph_impl( n = 3 ) - expect_snapshot(radius_dijkstra_impl( + expect_snapshot(radius_impl( graph = g )) - expect_snapshot(radius_dijkstra_impl( + expect_snapshot(radius_impl( graph = g, mode = "in" )) # Structured tests - result <- radius_dijkstra_impl( + result <- radius_impl( graph = g ) expect_true(is.numeric(result)) }) -test_that("radius_dijkstra_impl errors", { +test_that("radius_impl errors", { igraph_local_seed(20250909) - expect_snapshot_igraph_error(radius_dijkstra_impl( + expect_snapshot_igraph_error(radius_impl( graph = NULL )) }) @@ -3952,43 +3952,6 @@ test_that("pseudo_diameter_impl errors", { )) }) -# 154. pseudo_diameter_dijkstra_impl - -test_that("pseudo_diameter_dijkstra_impl basic", { - igraph_local_seed(20250909) - g <- path_graph_impl( - n = 3 - ) - - expect_snapshot(pseudo_diameter_dijkstra_impl( - graph = g, - start_vid = 1 - )) - expect_snapshot(pseudo_diameter_dijkstra_impl( - graph = g, - start_vid = 1, - directed = FALSE, - unconnected = FALSE - )) - - # Structured tests - result <- pseudo_diameter_dijkstra_impl( - graph = g, - start_vid = 1 - ) - expect_type(result, "list") -}) - -test_that("pseudo_diameter_dijkstra_impl errors", { - igraph_local_seed(20250909) - expect_snapshot_igraph_error( - pseudo_diameter_dijkstra_impl( - graph = NULL, - start_vid = 1 - ) - ) -}) - # 155. diversity_impl test_that("diversity_impl basic", { diff --git a/tests/testthat/test-centrality.R b/tests/testthat/test-centrality.R index 3e36af6a327..2f763829093 100644 --- a/tests/testthat/test-centrality.R +++ b/tests/testthat/test-centrality.R @@ -594,9 +594,20 @@ test_that("eigen_centrality() works", { expect_ev(M, v, lambda, eps) } + # Most of these graphs are disconnected, and warn that some centralities + # are nearly zero; no other warning is expected. for (i in 1:1000) { G <- sample_gnm(10, sample(1:20, 1)) - ev <- eigen_centrality(G) + ev <- withCallingHandlers( + eigen_centrality(G), + warning = function(w) { + expect_match( + conditionMessage(w), + "eigenvector centralities are nearly zero" + ) + invokeRestart("muffleWarning") + } + ) expect_good( as_adjacency_matrix(G, sparse = FALSE), ev$vector, diff --git a/tools/stimulus/functions-R.yaml b/tools/stimulus/functions-R.yaml index d0a78940ab7..f70aa6ca4a3 100644 --- a/tools/stimulus/functions-R.yaml +++ b/tools/stimulus/functions-R.yaml @@ -297,15 +297,6 @@ igraph_personalized_pagerank: PARAM_NAMES: reset: personalized -igraph_personalized_pagerank_vs: - DEPS: vids ON graph, weights ON graph, vector ON graph vids, - options ON algo, reset_vids ON graph - -igraph_rewire: - R: - DEFAULTS: - mode: 0L - igraph_average_path_length: PARAM_NAMES: unconn_pairs: unconnected