From f610c0940bdd1f4178d67ab932418ab6414002cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 17:35:42 +0000 Subject: [PATCH] refactor: replace .Call() with _impl() functions (subset of #2562) Agent-Logs-Url: https://github.com/igraph/rigraph/sessions/d6b7c067-26c4-4ec6-8d8c-1b56627b2277 Co-authored-by: krlmlr <1741643+krlmlr@users.noreply.github.com> --- R/bipartite.R | 38 +++--- R/cliques.R | 48 +++----- R/community.R | 52 ++++---- R/foreign.R | 44 +++---- R/interface.R | 8 +- R/iterators.R | 1 + R/layout.R | 246 +++++++++++++++++++------------------- R/operators.R | 3 +- R/structural-properties.R | 102 +++++----------- 9 files changed, 235 insertions(+), 307 deletions(-) diff --git a/R/bipartite.R b/R/bipartite.R index 5e640313588..1295b3b2920 100644 --- a/R/bipartite.R +++ b/R/bipartite.R @@ -184,43 +184,41 @@ bipartite_projection <- function( "false" = 1L, "true" = 2L ) - if (which != "both" && probe1 != -1) { + if (which != 0L && probe1 != -1) { cli::cli_warn("{.arg probe1} ignored if only one projection is requested.") } - on.exit(.Call(Rx_igraph_finalizer)) - # Function call - res <- .Call( - Rx_igraph_bipartite_projection, - graph, - types, - as.numeric(probe1), - which + # bipartite_projection_impl always computes both projections + res <- bipartite_projection_impl( + graph = graph, + types = types, + probe1 = probe1 ) + if (remove.type) { - if (is_igraph(res[[1]]) && "type" %in% vertex_attr_names(res[[1]])) { - res[[1]] <- delete_vertex_attr(res[[1]], "type") + if (is_igraph(res$proj1) && "type" %in% vertex_attr_names(res$proj1)) { + res$proj1 <- delete_vertex_attr(res$proj1, "type") } - if (is_igraph(res[[2]]) && "type" %in% vertex_attr_names(res[[2]])) { - res[[2]] <- delete_vertex_attr(res[[2]], "type") + if (is_igraph(res$proj2) && "type" %in% vertex_attr_names(res$proj2)) { + res$proj2 <- delete_vertex_attr(res$proj2, "type") } } if (which == 0L) { if (multiplicity) { - E(res[[1]])$weight <- res[[3]] - E(res[[2]])$weight <- res[[4]] + E(res$proj1)$weight <- res$multiplicity1 + E(res$proj2)$weight <- res$multiplicity2 } - res[1:2] + res[c("proj1", "proj2")] } else if (which == 1L) { if (multiplicity) { - E(res[[1]])$weight <- res[[3]] + E(res$proj1)$weight <- res$multiplicity1 } - res[[1]] + res$proj1 } else { if (multiplicity) { - E(res[[2]])$weight <- res[[4]] + E(res$proj2)$weight <- res$multiplicity2 } - res[[2]] + res$proj2 } } diff --git a/R/cliques.R b/R/cliques.R index 4bd6018334c..5e7434d89b6 100644 --- a/R/cliques.R +++ b/R/cliques.R @@ -396,14 +396,21 @@ count_max_cliques <- function(graph, min = NULL, max = NULL, subset = NULL) { max <- as.numeric(max) if (!is.null(subset)) { - subset <- as.numeric(as_igraph_vs(graph, subset) - 1) + # Use maximal_cliques_subset_impl when subset is provided + maximal_cliques_subset_impl( + graph = graph, + subset = subset, + min_size = min, + max_size = max, + details = TRUE + )$no + } else { + maximal_cliques_count_impl( + graph = graph, + min_size = min, + max_size = max + ) } - - on.exit(.Call(Rx_igraph_finalizer)) - # Function call - res <- .Call(Rx_igraph_maximal_cliques_count, graph, subset, min, max) - - res } #' @rdname cliques @@ -562,30 +569,11 @@ weighted_clique_num <- function(graph, vertex.weights = NULL) { #' #' length(max_ivs(g)) ivs <- function(graph, min = NULL, max = NULL) { - ensure_igraph(graph) - - if (is.null(min)) { - min <- 0 - } - - if (is.null(max)) { - max <- 0 - } - - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call( - Rx_igraph_independent_vertex_sets, - graph, - as.numeric(min), - as.numeric(max) + independent_vertex_sets_impl( + graph = graph, + min_size = min %||% 0, + max_size = max %||% 0 ) - res <- lapply(res, `+`, 1) - - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } - - res } #' @rdname ivs diff --git a/R/community.R b/R/community.R index 352f534ba11..514f0b2d734 100644 --- a/R/community.R +++ b/R/community.R @@ -1311,12 +1311,12 @@ show_trace <- function(communities) { ##################################################################### community.to.membership2 <- function(merges, vcount, steps) { - mode(merges) <- "numeric" - mode(vcount) <- "numeric" - mode(steps) <- "numeric" - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call(Rx_igraph_community_to_membership2, merges - 1, vcount, steps) - res + 1 + res <- community_to_membership_impl( + merges = merges - 1, + nodes = vcount, + steps = steps + ) + res$membership + 1 } ##################################################################### @@ -1480,19 +1480,18 @@ cluster_spinglass <- function( on.exit(.Call(Rx_igraph_finalizer)) if (is.null(vertex) || length(vertex) == 0) { - res <- .Call( - Rx_igraph_spinglass_community, - graph, - weights, - as.numeric(spins), - as.logical(parupdate), - as.numeric(start.temp), - as.numeric(stop.temp), - as.numeric(cool.fact), - as.numeric(update.rule), - as.numeric(gamma), - as.numeric(implementation), - as.numeric(gamma.minus) + res <- community_spinglass_impl( + graph = graph, + weights = weights, + spins = spins, + parupdate = parupdate, + starttemp = start.temp, + stoptemp = stop.temp, + coolfact = cool.fact, + update_rule = if (update.rule == 0) "simple" else "config", + gamma = gamma, + implementation = if (implementation == 0) "orig" else "neg", + lambda = gamma.minus ) res$algorithm <- "spinglass" res$vcount <- vcount(graph) @@ -1502,14 +1501,13 @@ cluster_spinglass <- function( } class(res) <- "communities" } else { - res <- .Call( - Rx_igraph_spinglass_my_community, - graph, - weights, - as_igraph_vs(graph, vertex) - 1, - as.numeric(spins), - as.numeric(update.rule), - as.numeric(gamma) + res <- community_spinglass_single_impl( + graph = graph, + weights = weights, + vertex = as_igraph_vs(graph, vertex) - 1, + spins = spins, + update_rule = if (update.rule == 0) "simple" else "config", + gamma = gamma ) res$community <- res$community + 1 } diff --git a/R/foreign.R b/R/foreign.R index ebf9280b01d..d9a0b0efc8f 100644 --- a/R/foreign.R +++ b/R/foreign.R @@ -518,12 +518,10 @@ write_graph <- function( ################################################################ read.graph.edgelist <- function(file, n = 0, directed = TRUE) { - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_read_graph_edgelist, - file, - as.numeric(n), - as.logical(directed) + read_graph_edgelist_impl( + instream = file, + n = n, + directed = directed ) } @@ -593,19 +591,12 @@ read.graph.lgl <- function( weights = c("auto", "yes", "no"), directed = FALSE ) { - weights <- switch( - igraph_match_arg(weights), - "no" = 0L, - "yes" = 1L, - "auto" = 2L - ) - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_read_graph_lgl, - file, - as.logical(names), - weights, - as.logical(directed) + weights <- igraph_match_arg(weights) + read_graph_lgl_impl( + instream = file, + names = names, + weights = weights, + directed = directed ) } @@ -656,6 +647,7 @@ write.graph.pajek <- function(graph, file) { } read.graph.dimacs <- function(file, directed = TRUE) { + on.exit(.Call(Rx_igraph_finalizer)) res <- .Call(Rx_igraph_read_graph_dimacs, file, as.logical(directed)) if (res[[1]][1] == "max") { graph <- res[[2]] @@ -689,14 +681,12 @@ write.graph.dimacs <- function( capacity <- E(graph)$capacity } - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_write_graph_dimacs, - graph, - file, - as.numeric(source), - as.numeric(target), - as.numeric(capacity) + write_graph_dimacs_flow_impl( + graph = graph, + outstream = file, + source = source, + target = target, + capacity = capacity ) } diff --git a/R/interface.R b/R/interface.R index 7533cfb8285..8da93b68323 100644 --- a/R/interface.R +++ b/R/interface.R @@ -150,11 +150,9 @@ add_edges <- function(graph, edges, ..., attr = list()) { } edges.orig <- ecount(graph) - on.exit(.Call(Rx_igraph_finalizer)) - graph <- .Call( - Rx_igraph_add_edges_manual, - graph, - as_igraph_vs(graph, edges) - 1 + graph <- add_edges_impl( + graph = graph, + edges = edges ) edges.new <- ecount(graph) diff --git a/R/iterators.R b/R/iterators.R index 2cfd3101348..6bed843824c 100644 --- a/R/iterators.R +++ b/R/iterators.R @@ -84,6 +84,7 @@ get_es_graph_id <- get_vs_graph_id <- function(seq) { #' @export identical_graphs <- function(g1, g2, attrs = TRUE) { stopifnot(is_igraph(g1), is_igraph(g2)) + on.exit(.Call(Rx_igraph_finalizer)) .Call(Rx_igraph_identical_graphs, g1, g2, as.logical(attrs)) } diff --git a/R/layout.R b/R/layout.R index 1f14bbe0fb6..5be6ba8888a 100644 --- a/R/layout.R +++ b/R/layout.R @@ -848,24 +848,24 @@ layout_as_tree <- function( root <- as_igraph_vs(graph, root) - 1 circular <- as.logical(circular) rootlevel <- as.double(rootlevel) - mode <- switch( - igraph_match_arg(mode), - "out" = 1, - "in" = 2, - "all" = 3, - "total" = 3 - ) + mode <- igraph_match_arg(mode) flip.y <- as.logical(flip.y) - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call( - Rx_igraph_layout_reingold_tilford, - graph, - root, - mode, - rootlevel, - circular - ) + if (circular) { + res <- layout_reingold_tilford_circular_impl( + graph = graph, + mode = mode, + roots = root, + rootlevel = rootlevel + ) + } else { + res <- layout_reingold_tilford_impl( + graph = graph, + mode = mode, + roots = root, + rootlevel = rootlevel + ) + } if (flip.y && vcount(graph) > 0) { res[, 2] <- max(res[, 2]) - res[, 2] } @@ -1517,8 +1517,15 @@ layout_with_fr <- function( ) { # Argument checks ensure_igraph(graph) - coords[] <- as.numeric(coords) dim <- igraph_match_arg(dim) + use_seed <- !is.null(coords) + if (is.null(coords)) { + # Initialize coords with zeros - will be ignored if use_seed=FALSE + n <- vcount(graph) + dim_n <- if (dim == "2") 2 else 3 + coords <- matrix(0, n, dim_n) + } + coords[] <- as.numeric(coords) if (!missing(niter) && !missing(maxiter)) { cli::cli_abort(c( "{.arg niter} and {.arg maxiter} must not be specified at the same time.", @@ -1532,16 +1539,9 @@ layout_with_fr <- function( start.temp <- as.numeric(start.temp) grid <- igraph_match_arg(grid) - grid <- switch(grid, "grid" = 0L, "nogrid" = 1L, "auto" = 2L) - if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { - weights <- E(graph)$weight - } - if (!is.null(weights) && any(!is.na(weights))) { - weights <- as.numeric(weights) - } else { - weights <- NULL - } + # Let _impl handle default weights from edge attribute + # Pass weights as-is (including NA to signal "no weights") if (!is.null(minx)) { minx <- as.numeric(minx) } @@ -1573,35 +1573,34 @@ layout_with_fr <- function( lifecycle::deprecate_stop("0.8.0", "layout_with_fr(repulserad = )") } - on.exit(.Call(Rx_igraph_finalizer)) if (dim == 2) { - res <- .Call( - Rx_igraph_layout_fruchterman_reingold, - graph, - coords, - niter, - start.temp, - weights, - minx, - maxx, - miny, - maxy, - grid + res <- layout_fruchterman_reingold_impl( + graph = graph, + coords = coords, + use_seed = use_seed, + niter = niter, + start_temp = start.temp, + grid = grid, + weights = weights, + minx = minx, + maxx = maxx, + miny = miny, + maxy = maxy ) } else { - res <- .Call( - Rx_igraph_layout_fruchterman_reingold_3d, - graph, - coords, - niter, - start.temp, - weights, - minx, - maxx, - miny, - maxy, - minz, - maxz + res <- layout_fruchterman_reingold_3d_impl( + graph = graph, + coords = coords, + use_seed = use_seed, + niter = niter, + start_temp = start.temp, + weights = weights, + minx = minx, + maxx = maxx, + miny = miny, + maxy = maxy, + minz = minz, + maxz = maxz ) } res @@ -1758,6 +1757,11 @@ layout_with_graphopt <- function( max.sa.movement = 5 ) { ensure_igraph(graph) + use_seed <- !is.null(start) + if (is.null(start)) { + # Initialize with zeros - will be ignored if use_seed=FALSE + start <- matrix(0, vcount(graph), 2) + } start[] <- as.numeric(start) niter <- as.double(niter) charge <- as.double(charge) @@ -1766,17 +1770,16 @@ layout_with_graphopt <- function( spring.constant <- as.double(spring.constant) max.sa.movement <- as.double(max.sa.movement) - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_layout_graphopt, - graph, - niter, - charge, - mass, - spring.length, - spring.constant, - max.sa.movement, - start + layout_graphopt_impl( + graph = graph, + res = start, + niter = niter, + node_charge = charge, + node_mass = mass, + spring_length = spring.length, + spring_constant = spring.constant, + max_sa_movement = max.sa.movement, + use_seed = use_seed ) } @@ -1881,8 +1884,15 @@ layout_with_kk <- function( } ensure_igraph(graph) - coords[] <- as.numeric(coords) dim <- igraph_match_arg(dim) + use_seed <- !is.null(coords) + if (is.null(coords)) { + # Initialize coords with zeros - will be ignored if use_seed=FALSE + n <- vcount(graph) + dim_n <- if (dim == "2") 2 else 3 + coords <- matrix(0, n, dim_n) + } + coords[] <- as.numeric(coords) maxiter <- as.numeric(maxiter) epsilon <- as.numeric(epsilon) @@ -1927,37 +1937,36 @@ layout_with_kk <- function( lifecycle::deprecate_stop("0.8.0", "layout_with_kk(coolexp = )") } - on.exit(.Call(Rx_igraph_finalizer)) # Function call if (dim == 2) { - res <- .Call( - Rx_igraph_layout_kamada_kawai, - graph, - coords, - maxiter, - epsilon, - kkconst, - weights, - minx, - maxx, - miny, - maxy + res <- layout_kamada_kawai_impl( + graph = graph, + coords = coords, + use_seed = use_seed, + maxiter = maxiter, + epsilon = epsilon, + kkconst = kkconst, + weights = weights, + minx = minx, + maxx = maxx, + miny = miny, + maxy = maxy ) } else { - res <- .Call( - Rx_igraph_layout_kamada_kawai_3d, - graph, - coords, - maxiter, - epsilon, - kkconst, - weights, - minx, - maxx, - miny, - maxy, - minz, - maxz + res <- layout_kamada_kawai_3d_impl( + graph = graph, + coords = coords, + use_seed = use_seed, + maxiter = maxiter, + epsilon = epsilon, + kkconst = kkconst, + weights = weights, + minx = minx, + maxx = maxx, + miny = miny, + maxy = maxy, + minz = minz, + maxz = maxz ) } @@ -2037,17 +2046,15 @@ layout_with_lgl <- function( root <- as_igraph_vs(graph, root) - 1 } - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_layout_lgl, - graph, - as.double(maxiter), - as.double(maxdelta), - as.double(area), - as.double(coolexp), - as.double(repulserad), - as.double(cellsize), - root + layout_lgl_impl( + graph = graph, + maxiter = maxiter, + maxdelta = maxdelta, + area = area, + coolexp = coolexp, + repulserad = repulserad, + cellsize = cellsize, + root = root ) } @@ -2549,11 +2556,9 @@ merge_coords <- function(graphs, layouts, method = "dla") { cli::cli_abort("{.arg method} must be {.str dla}, not {.str {method}}.") } - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_layout_merge_dla, - graphs, - layouts + layout_merge_dla_impl( + graphs = graphs, + coords = layouts ) } @@ -2891,24 +2896,21 @@ layout_with_drl <- function( weights <- NULL } - on.exit(.Call(Rx_igraph_finalizer)) if (dim == 2) { - res <- .Call( - Rx_igraph_layout_drl, - graph, - seed, - use.seed, - options, - weights + res <- layout_drl_impl( + graph = graph, + res = seed, + use_seed = use.seed, + options = options, + weights = weights ) } else { - res <- .Call( - Rx_igraph_layout_drl_3d, - graph, - seed, - use.seed, - options, - weights + res <- layout_drl_3d_impl( + graph = graph, + res = seed, + use_seed = use.seed, + options = options, + weights = weights ) } res diff --git a/R/operators.R b/R/operators.R index 4c3161dc775..b1c4d2f6671 100644 --- a/R/operators.R +++ b/R/operators.R @@ -228,8 +228,7 @@ disjoint_union <- function(...) { ) lapply(graphs, ensure_igraph) - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call(Rx_igraph_disjoint_union, graphs) + res <- disjoint_union_many_impl(graphs = graphs) ## Graph attributes graph.attributes(res) <- rename.attr.if.needed("g", graphs) diff --git a/R/structural-properties.R b/R/structural-properties.R index c6c99025cf1..11328767b39 100644 --- a/R/structural-properties.R +++ b/R/structural-properties.R @@ -1518,24 +1518,11 @@ k_shortest_paths <- function( #' subcomponent(g, 1, "out") #' subcomponent(g, 1, "all") subcomponent <- function(graph, v, mode = c("all", "out", "in")) { - ensure_igraph(graph) - mode <- igraph_match_arg(mode) - mode <- switch(mode, "out" = 1, "in" = 2, "all" = 3) - - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call( - Rx_igraph_subcomponent, - graph, - as_igraph_vs(graph, v) - 1, - as.numeric(mode) - ) + - 1L - - if (igraph_opt("return.vs.es")) { - res <- create_vs(graph, res) - } - - res + subcomponent_impl( + graph = graph, + vid = v, + mode = mode + ) } #' Subgraph of a graph @@ -2050,19 +2037,12 @@ ego_size <- function( mode = c("all", "out", "in"), mindist = 0 ) { - ensure_igraph(graph) - mode <- igraph_match_arg(mode) - mode <- switch(mode, "out" = 1, "in" = 2, "all" = 3) - mindist <- as.numeric(mindist) - - on.exit(.Call(Rx_igraph_finalizer)) - .Call( - Rx_igraph_neighborhood_size, - graph, - as_igraph_vs(graph, nodes) - 1, - as.numeric(order), - as.numeric(mode), - mindist + neighborhood_size_impl( + graph = graph, + vids = nodes, + order = order, + mode = mode, + mindist = mindist ) } @@ -2164,27 +2144,13 @@ ego <- function( mode = c("all", "out", "in"), mindist = 0 ) { - ensure_igraph(graph) - mode <- igraph_match_arg(mode) - mode <- switch(mode, "out" = 1, "in" = 2, "all" = 3) - mindist <- as.numeric(mindist) - - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call( - Rx_igraph_neighborhood, - graph, - as_igraph_vs(graph, nodes) - 1, - as.numeric(order), - as.numeric(mode), - mindist + neighborhood_impl( + graph = graph, + vids = nodes, + order = order, + mode = mode, + mindist = mindist ) - res <- lapply(res, function(x) x + 1) - - if (igraph_opt("return.vs.es")) { - res <- lapply(res, unsafe_create_vs, graph = graph, verts = V(graph)) - } - - res } #' @export @@ -2199,21 +2165,13 @@ make_ego_graph <- function( mode = c("all", "out", "in"), mindist = 0 ) { - ensure_igraph(graph) - mode <- igraph_match_arg(mode) - mode <- switch(mode, "out" = 1L, "in" = 2L, "all" = 3L) - mindist <- as.numeric(mindist) - - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call( - Rx_igraph_neighborhood_graphs, - graph, - as_igraph_vs(graph, nodes) - 1, - as.numeric(order), - as.integer(mode), - mindist + neighborhood_graphs_impl( + graph = graph, + vids = nodes, + order = order, + mode = mode, + mindist = mindist ) - res } #' @export @@ -2441,15 +2399,13 @@ feedback_vertex_set <- function(graph, weights = NULL, algo = c("exact_ip")) { #' girth(g) #' girth <- function(graph, circle = TRUE) { - ensure_igraph(graph) - - on.exit(.Call(Rx_igraph_finalizer)) - res <- .Call(Rx_igraph_girth, graph, as.logical(circle)) + # girth_impl always computes circle; slightly less efficient when circle=FALSE + res <- girth_impl(graph = graph) if (res$girth == 0) { res$girth <- Inf } - if (igraph_opt("return.vs.es") && circle) { - res$circle <- create_vs(graph, res$circle) + if (!circle) { + res$circle <- NULL } res } @@ -3165,10 +3121,8 @@ is_connected <- function(graph, mode = c("weak", "strong")) { count_components <- function(graph, mode = c("weak", "strong")) { ensure_igraph(graph) mode <- igraph_match_arg(mode) - mode <- switch(mode, "weak" = 1L, "strong" = 2L) - on.exit(.Call(Rx_igraph_finalizer)) - .Call(Rx_igraph_no_components, graph, mode) + connected_components_impl(graph, mode = mode, details = TRUE)$no } #' Count reachable vertices