From cb1a2cb117094cc99060389b0d140ba99545deaa Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 8 Aug 2026 15:34:57 +0000 Subject: [PATCH] docs(revdep): Add reprexes for bootcluster, checked, htna and SEMdeep The four packages `revdep2` run 31048405399 flagged that the committed `revdep/` report does not. Each gets the two files this directory uses -- a runnable script and the reprex output -- and they turn out to be four different stories: * **bootcluster** calls `sample_degseq(method = "simple.no.multiple")` from `scheme2.exp()`. Defunct since 2.1.0, same as qgraph and degreenet. Still errors on 2.3.3.9029. CRAN lists no URL or BugReports for it, so it is an email to the maintainer. * **checked** passes `mode` positionally to `neighbors()`. That is soft-deprecated for 3.0.0 and only warns -- but the package's tests are snapshot tests, so 315 warnings become one failure. A one-word fix upstream. * **htna** cascades through `tna:::as.igraph.matrix()`, whose call to `graph_from_adjacency_matrix()` ends in a trailing comma. That empty argument used to reach the migration handler and error; it does not any more, so the reproducer passes and is kept as a regression test rather than sent anywhere. * **SEMdeep** fails inside `SEMgraph::SEMrun()` with a subscript out of bounds and no igraph function on the backtrace -- a silent result change, the same shape as SEMgraph's own open item. It is the one example here that is neither reduced nor rendered: SEMgraph needs Bioconductor packages that do not install where the others were rendered, so its `.md` carries the check log and a list of what to compare instead. Rendered with reprex against a locally built igraph 2.3.3.9029, so the outputs are what the current development version actually does. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DdNk5vJPSUidKGdnAYt7Dv --- revdep/examples/README.md | 12 +++ .../bootcluster-sample-degseq-method-issue.R | 35 ++++++++ .../bootcluster-sample-degseq-method-issue.md | 54 ++++++++++++ .../checked-neighbors-positional-issue.R | 33 +++++++ .../checked-neighbors-positional-issue.md | 52 +++++++++++ .../examples/htna-tna-empty-argument-issue.R | 41 +++++++++ .../examples/htna-tna-empty-argument-issue.md | 67 ++++++++++++++ .../examples/semdeep-semrun-subscript-issue.R | 54 ++++++++++++ .../semdeep-semrun-subscript-issue.md | 88 +++++++++++++++++++ 9 files changed, 436 insertions(+) create mode 100644 revdep/examples/bootcluster-sample-degseq-method-issue.R create mode 100644 revdep/examples/bootcluster-sample-degseq-method-issue.md create mode 100644 revdep/examples/checked-neighbors-positional-issue.R create mode 100644 revdep/examples/checked-neighbors-positional-issue.md create mode 100644 revdep/examples/htna-tna-empty-argument-issue.R create mode 100644 revdep/examples/htna-tna-empty-argument-issue.md create mode 100644 revdep/examples/semdeep-semrun-subscript-issue.R create mode 100644 revdep/examples/semdeep-semrun-subscript-issue.md diff --git a/revdep/examples/README.md b/revdep/examples/README.md index 4f5404cc4cc..77aa543b0af 100644 --- a/revdep/examples/README.md +++ b/revdep/examples/README.md @@ -35,6 +35,18 @@ Each issue has two files: #### Group F — `tkplot()` defunct (igraph 3.0.0) 13. **tkplot-defunct-issue** — shared reproducer for Boptbd, c3net, ggm, optbdmaeAT, optrcdmaeAT (all direct callers of `igraph::tkplot()`) +#### Group C (continued) — new in the `revdep2` run 31048405399 +14. **bootcluster-sample-degseq-method-issue** — `sample_degseq(method = "simple.no.multiple")` defunct, same as qgraph/degreenet + +#### Group G — Optional arguments passed positionally (deprecated for 3.0.0) +15. **checked-neighbors-positional-issue** — `neighbors(g, v, "out")` warns; snapshot tests turn 315 warnings into a failure + +#### Group H — igraph regressions from the ellipsis move +16. **htna-tna-empty-argument-issue** — a trailing comma reached the migration handler and errored; **fixed**, kept as the regression reproducer (htna cascades through tna) + +#### Group I — Silent result changes, not yet traced +17. **semdeep-semrun-subscript-issue** — `SEMml(algo = "sem")` → subscript out of bounds inside `SEMgraph::SEMrun()`; unreduced, and the only example here without rendered output (SEMgraph needs Bioconductor packages) + Three packages from the failure set (dci, ggraph, scistreer) are pure cascades through tidygraph and have no separate reproducer — see `tidygraph-bfs-father-issue` for the root cause. ## Running the Examples diff --git a/revdep/examples/bootcluster-sample-degseq-method-issue.R b/revdep/examples/bootcluster-sample-degseq-method-issue.R new file mode 100644 index 00000000000..e760459527d --- /dev/null +++ b/revdep/examples/bootcluster-sample-degseq-method-issue.R @@ -0,0 +1,35 @@ +# bootcluster sample_degseq(method = "simple.no.multiple") defunct +# Issue: bootcluster:::scheme2.exp() calls +# igraph::sample_degseq(out.deg = degree.seq, method = "simple.no.multiple"), +# which now hard-errors because the "simple.no.multiple" method value is +# defunct. Surfaces as an ERROR in the network.stability() example. + +library(igraph) + +deg <- rep(2, 10) # any graphical degree sequence + +# Old call -- defunct since igraph 2.1.0 +sample_degseq(out.deg = deg, method = "simple.no.multiple") + +# Working replacement -- new method name, same sampler +g <- sample_degseq(out.deg = deg, method = "fast.heur.simple") +vcount(g) +ecount(g) + +# Root cause: +# - sample_degseq() had three legacy method values renamed in 2.1.0: +# "simple" -> "configuration" +# "simple.no.multiple" -> "fast.heur.simple" +# "simple.no.multiple.uniform" -> "configuration.simple" +# - All three advanced from deprecate_warn to deprecate_stop in #2634 + +# Assessment: +# - Bug in bootcluster -- pinned to an obsolete method name. +# - Same root cause as qgraph and degreenet; see +# qgraph-sample-degseq-method-issue and degreenet-reedmolloy-issue. + +# Recommendation: +# - For bootcluster: switch to method = "fast.heur.simple" in scheme2.exp(). +# While there, the same example emits deprecation warnings for clusters(), +# induced.subgraph() and fastgreedy.community(); their replacements are +# components(), induced_subgraph() and cluster_fast_greedy(). diff --git a/revdep/examples/bootcluster-sample-degseq-method-issue.md b/revdep/examples/bootcluster-sample-degseq-method-issue.md new file mode 100644 index 00000000000..e1caa62095d --- /dev/null +++ b/revdep/examples/bootcluster-sample-degseq-method-issue.md @@ -0,0 +1,54 @@ +# bootcluster `sample_degseq(method = "simple.no.multiple")` defunct + +## Issue +`bootcluster:::scheme2.exp()` calls +`igraph::sample_degseq(out.deg = degree.seq, method = "simple.no.multiple")`, +which hard-errors because the `"simple.no.multiple"` method value is defunct as +of igraph 2.1.0. It surfaces as an ERROR in the `network.stability()` example. + +## Reproducible Example + +``` r +library(igraph) + +deg <- rep(2, 10) # any graphical degree sequence + +# Old call -- defunct since igraph 2.1.0 +sample_degseq(out.deg = deg, method = "simple.no.multiple") +#> Error: +#> ! The `method` argument of `sample_degseq()` must be fast.heur.simple +#> instead of simple.no.multiple as of igraph 2.1.0. + +# Working replacement -- new method name, same sampler +g <- sample_degseq(out.deg = deg, method = "fast.heur.simple") +vcount(g) +#> [1] 10 +ecount(g) +#> [1] 10 +``` + +## Root Cause +`sample_degseq()` had three legacy method values renamed in 2.1.0: + +| Old value | New value | +|---|---| +| `"simple"` | `"configuration"` | +| `"simple.no.multiple"` | `"fast.heur.simple"` | +| `"simple.no.multiple.uniform"` | `"configuration.simple"` | + +All three advanced from `deprecate_warn` to `deprecate_stop` in [#2634](https://github.com/igraph/rigraph/pull/2634). + +## Assessment +Bug in bootcluster — pinned to an obsolete method name. Same root cause as +qgraph and degreenet; see `qgraph-sample-degseq-method-issue` and +`degreenet-reedmolloy-issue`. + +## Recommendation +**For bootcluster**: switch to `method = "fast.heur.simple"` in +`scheme2.exp()`. The same example also emits deprecation warnings for +`clusters()`, `induced.subgraph()` and `fastgreedy.community()`; their +replacements are `components()`, `induced_subgraph()` and +`cluster_fast_greedy()`. + +CRAN has no URL or BugReports field for bootcluster, so this one goes to the +maintainer by email: Tianmou Liu <tianmouliu@outlook.com>. diff --git a/revdep/examples/checked-neighbors-positional-issue.R b/revdep/examples/checked-neighbors-positional-issue.R new file mode 100644 index 00000000000..544feb69bc5 --- /dev/null +++ b/revdep/examples/checked-neighbors-positional-issue.R @@ -0,0 +1,33 @@ +# checked neighbors(graph, v, mode) positional deprecation +# Issue: checked:::deduplicate_task_graph() calls +# igraph::neighbors(g, i, "out"), passing `mode` positionally. Since the +# optional arguments moved behind `...`, that call is soft-deprecated and +# warns. checked's tests are snapshot tests, so 315 warnings turn into a +# test failure -- the package itself still works. + +library(igraph) + +g <- make_ring(4, directed = TRUE) + +# Old call -- soft-deprecated for 3.0.0, warns under testthat +neighbors(g, 1, "out") + +# Working replacement -- name the argument +neighbors(g, 1, mode = "out") + +# Root cause: +# - neighbors() is now neighbors(graph, v, ..., mode = ...); everything after +# `...` has to be named. The generated argument handler recovers the old +# positional call and warns through lifecycle::deprecate_soft(). +# - deprecate_soft() is quiet in ordinary use and loud where it matters for a +# maintainer: under testthat, and in code run directly at the prompt. That +# is why this surfaces as a test failure rather than a user-visible warning. + +# Assessment: +# - Not a bug in checked -- the call is correct today and deprecated for +# 3.0.0. It is a one-word fix that also silences the warning for their users. + +# Recommendation: +# - For checked: `neighbors(g, i, mode = "out")` in deduplicate_task_graph(). +# The same rule applies to any other igraph call passing an optional +# argument positionally. diff --git a/revdep/examples/checked-neighbors-positional-issue.md b/revdep/examples/checked-neighbors-positional-issue.md new file mode 100644 index 00000000000..38449157a81 --- /dev/null +++ b/revdep/examples/checked-neighbors-positional-issue.md @@ -0,0 +1,52 @@ +# checked `neighbors(graph, v, mode)` positional deprecation + +## Issue +`checked:::deduplicate_task_graph()` calls `igraph::neighbors(g, i, "out")`, +passing `mode` positionally. Since the optional arguments moved behind `...`, +that call is soft-deprecated and warns. checked's tests are snapshot tests, so +315 warnings turn into `[ FAIL 1 | WARN 315 | SKIP 0 | PASS 171 ]` — the +package itself still works. + +## Reproducible Example + +``` r +library(igraph) + +g <- make_ring(4, directed = TRUE) + +# Old call -- soft-deprecated for 3.0.0, warns under testthat +neighbors(g, 1, "out") +#> Warning: Calling `neighbors()` with positional or abbreviated arguments was deprecated +#> in igraph 3.0.0. +#> ℹ Detected call: neighbors(graph, v, mode) +#> ℹ Use instead: neighbors(graph, v, mode = ) +#> This warning is displayed once per session. +#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was +#> generated. +#> ── 1/4 · from b36f274 ──────────────────────────────────────── +#> [1] 2 + +# Working replacement -- name the argument +neighbors(g, 1, mode = "out") +#> ── 1/4 · from b36f274 ──────────────────────────────────────── +#> [1] 2 +``` + +## Root Cause +`neighbors()` is now `neighbors(graph, v, ..., mode = ...)`: everything after +`...` has to be named. The generated argument handler recovers the old +positional call and warns through `lifecycle::deprecate_soft()`, which is quiet +in ordinary use and loud exactly where a maintainer will see it — under +testthat, and at the prompt. That is why this surfaces as a test failure rather +than as a user-visible warning. + +## Assessment +Not a bug in checked: the call is correct today and deprecated for 3.0.0. It is +a one-word fix that also silences the warning for their users ahead of time. + +## Recommendation +**For checked**: `neighbors(g, i, mode = "out")` in +`deduplicate_task_graph()`. The same rule applies to any other igraph call that +passes an optional argument positionally. + +File at . diff --git a/revdep/examples/htna-tna-empty-argument-issue.R b/revdep/examples/htna-tna-empty-argument-issue.R new file mode 100644 index 00000000000..a3306d0e8ba --- /dev/null +++ b/revdep/examples/htna-tna-empty-argument-issue.R @@ -0,0 +1,41 @@ +# htna: empty argument in `...` -- igraph regression, already fixed +# Issue: htna's tests call tna::estimate_cs(), which reaches +# tna:::as.igraph.matrix() -> igraph::graph_from_adjacency_matrix(). That call +# ends in a trailing comma, so an empty argument lands in `...`. In the +# ellipsis-move refactoring that reached migrate_recover_args() and errored +# with "argument is missing, with no default". +# +# This is an igraph bug, not an htna or tna one, and the current development +# version handles it -- the script below runs clean. It is kept as the +# regression reproducer. + +library(igraph) + +m <- matrix(c(0, 1, 1, 0), 2, dimnames = list(c("a", "b"), c("a", "b"))) + +# tna:::as.igraph.matrix(), reduced -- note the trailing comma +tna_shape <- function(x, mode = "directed", ...) { + igraph::graph_from_adjacency_matrix( + adjmatrix = x, + mode = mode, + weighted = TRUE, + ) +} +tna_shape(m) + +# The other form from the same class of failure: a skipped positional slot +graph_from_data_frame(data.frame(from = "a", to = "b"), , directed = FALSE) + +# Root cause: +# - Moving the optional arguments behind `...` made every call with an empty +# argument reach the migration handler, where forcing dots[[k]] errored. +# - Fixed by skipping missing dots; both forms above now work. + +# Assessment: +# - Ours, not theirs. Same root cause as tna, lagdynamics, modelbpp and +# NetSci in #2646, all tagged [IGRAPH BUG]. + +# Recommendation: +# - Nothing to send upstream. Re-check htna and tna against the current dev +# version to confirm they are green again; a trailing comma is legal R and +# igraph has to accept it. diff --git a/revdep/examples/htna-tna-empty-argument-issue.md b/revdep/examples/htna-tna-empty-argument-issue.md new file mode 100644 index 00000000000..c5747e0832a --- /dev/null +++ b/revdep/examples/htna-tna-empty-argument-issue.md @@ -0,0 +1,67 @@ +# htna — empty argument in `...` (igraph regression, fixed) + +## Issue +htna's tests call `tna::estimate_cs()`, which reaches +`tna:::as.igraph.matrix()` → `igraph::graph_from_adjacency_matrix()`. That call +ends in a trailing comma, so an empty argument lands in `...`. During the +ellipsis-move refactoring it reached `migrate_recover_args()` and errored with +`argument is missing, with no default`. + +**This is an igraph bug, not an htna or tna one, and it is already fixed** — +the example below runs clean on igraph 2.3.3.9029. It is kept as the regression +reproducer. + +## Reproducible Example + +``` r +library(igraph) + +m <- matrix(c(0, 1, 1, 0), 2, dimnames = list(c("a", "b"), c("a", "b"))) + +# tna:::as.igraph.matrix(), reduced -- note the trailing comma +tna_shape <- function(x, mode = "directed", ...) { + igraph::graph_from_adjacency_matrix( + adjmatrix = x, + mode = mode, + weighted = TRUE, + ) +} +tna_shape(m) +#> ── ───────────────────────────────────────────────────────── cb5ccda ── +#> ℹ directed · named · weighted +#> ℹ 2 vertices · 2 edges +#> +#> ── Attributes ────────────────────────────────────────────────────────────────── +#> → vertex: name +#> → edge: weight +#> +#> ── Edges (vertex names) ──────────────────────────────────────────────────────── +#> [1] a → b b → a + +# The other form from the same class of failure: a skipped positional slot +graph_from_data_frame(data.frame(from = "a", to = "b"), , directed = FALSE) +#> ── ───────────────────────────────────────────────────────── d5e4d69 ── +#> ℹ undirected · named +#> ℹ 2 vertices · 1 edges +#> +#> ── Attributes ────────────────────────────────────────────────────────────────── +#> → vertex: name +#> +#> ── Edges (vertex names) ──────────────────────────────────────────────────────── +#> [1] a ─ b +``` + +## Root Cause +Moving the optional arguments behind `...` made every call carrying an empty +argument reach the migration handler, where forcing `dots[[k]]` errored. The +handler now skips missing dots, and both forms above work again. + +## Assessment +Ours, not theirs. Same root cause as tna, lagdynamics, modelbpp and NetSci in +[#2646](https://github.com/igraph/rigraph/issues/2646), all tagged +`[IGRAPH BUG]`. + +## Recommendation +Nothing to send upstream. Re-check htna and tna against the current development +version to confirm they are green again — a trailing comma is legal R and +igraph has to accept it. diff --git a/revdep/examples/semdeep-semrun-subscript-issue.R b/revdep/examples/semdeep-semrun-subscript-issue.R new file mode 100644 index 00000000000..925c10411c8 --- /dev/null +++ b/revdep/examples/semdeep-semrun-subscript-issue.R @@ -0,0 +1,54 @@ +# SEMdeep SEMml(algo = "sem") -- subscript out of bounds [NEEDS TRIAGE] +# Issue: the SEMml() example fails at the algo = "sem" step with +# Error in x[, ii] : subscript out of bounds +# Calls: SEMml ... model.frame.default -> na.omit -> na.omit.data.frame +# The failing call is SEMgraph::SEMrun(dag, data, algo = "cggm"); no igraph +# function is on the backtrace, so this is a silent change in what igraph +# returns rather than a lifecycle error. +# +# Unlike the other examples here this one is NOT reduced to an igraph call +# yet -- it needs SEMgraph (and therefore Bioconductor's graph/Rgraphviz), +# which is why the .md beside it carries the check log rather than reprex +# output. + +library(SEMgraph) +library(igraph) + +# SEMml()'s own preprocessing, up to the call that fails +ig <- alsData$graph +data <- transformData(alsData$exprs)$data + +nodes <- colnames(data)[colnames(data) %in% V(ig)$name] +graph <- induced_subgraph(ig, vids = which(V(ig)$name %in% nodes)) +dag <- graph2dag(graph, data, bap = FALSE) +data <- data[, V(dag)$name] + +# SEMdeep::SEMml(..., algo = "sem") does exactly this: +fit <- SEMrun(dag, data = data, algo = "cggm") + +# Or, from the package itself: +# set.seed(123) +# train <- sample(1:nrow(data), 0.5 * nrow(data)) +# SEMml(alsData$graph, data[train, ], algo = "sem") + +# Triage notes -- what to compare between CRAN igraph and the dev version, +# since the error is a column subscript running past the end of a data frame: +# vcount(dag); ecount(dag) +# V(dag)$name # names and their order +# setdiff(V(dag)$name, colnames(data)) +# igraph::degree(dag, mode = "in") # SEMml() splits Vx/Vy on this +# is_dag(dag) +# A graph2dag() that now drops, renames or reorders vertices would produce +# exactly this failure downstream. + +# Assessment: +# - Not yet traced to a specific igraph change. It is the same shape as +# SEMgraph's own open item in #2646 (subscript out of bounds in +# buildLevels()), and SEMdeep Depends on SEMgraph, so one cause may explain +# both. + +# Recommendation: +# - Bisect against the ellipsis-move PRs (#2757-#2778, #2784) before +# contacting the maintainer: the shape of the failure -- a silently +# different result with no warning -- is what a positional argument no +# longer binding where it used to looks like. diff --git a/revdep/examples/semdeep-semrun-subscript-issue.md b/revdep/examples/semdeep-semrun-subscript-issue.md new file mode 100644 index 00000000000..98d7a222872 --- /dev/null +++ b/revdep/examples/semdeep-semrun-subscript-issue.md @@ -0,0 +1,88 @@ +# SEMdeep `SEMml(algo = "sem")` — subscript out of bounds + +## Issue + +`SEMdeep::SEMml()` fails at its `algo = "sem"` step. The first three algorithms +(`tree`, `rf`, `xgb`) complete normally in the same example, so the graph and +the data reach that point intact. + +## Evidence + +From the `revdep2` run [31048405399](https://github.com/igraph/rigraph/actions/runs/31048405399), +`SEMdeep 1.1.1` checked against igraph 2.3.3.9026, `--run-donttest` examples: + +```text +> res3<- SEMml(ig, data[train, ], algo="xgb", ncores = ncores) +Running SEM model via ML... + done. + +XGB solver ended normally after 23 iterations + + logL:69.930993 srmr:0.001418 +> +> # ... sem +> res4<- SEMml(ig, data[train, ], algo="sem") +Running SEM model via ML... +Error in x[, ii] : subscript out of bounds +Calls: SEMml ... model.frame.default -> na.omit -> na.omit.data.frame +Execution halted +``` + +No igraph function appears on the backtrace: the failure is `model.frame()` +being handed a data frame narrower than the formula it is given, inside +`SEMgraph::SEMrun(dag, data, algo = "cggm")` — which is what `SEMml()` calls +for `algo = "sem"`. + +## Reproducible example + +Not reduced to an igraph call yet, and unrendered: `SEMgraph` needs +Bioconductor's `graph` and `Rgraphviz`, which do not install in the +environment where the other examples in this directory were rendered. The +script is [`semdeep-semrun-subscript-issue.R`](semdeep-semrun-subscript-issue.R) +and runs anywhere SEMdeep itself installs: + +```r +library(SEMgraph) +library(igraph) + +ig <- alsData$graph +data <- transformData(alsData$exprs)$data + +nodes <- colnames(data)[colnames(data) %in% V(ig)$name] +graph <- induced_subgraph(ig, vids = which(V(ig)$name %in% nodes)) +dag <- graph2dag(graph, data, bap = FALSE) +data <- data[, V(dag)$name] + +SEMrun(dag, data = data, algo = "cggm") +``` + +## What to compare + +The error is a column subscript running past the end of a data frame, so the +question is whether `dag` still describes the same vertices in the same order +under the development version: + +```r +vcount(dag); ecount(dag) +V(dag)$name +setdiff(V(dag)$name, colnames(data)) +igraph::degree(dag, mode = "in") # SEMml() splits Vx/Vy on this +is_dag(dag) +``` + +A `graph2dag()` that now drops, renames or reorders vertices produces exactly +this failure downstream. + +## Assessment + +Not yet traced to a specific igraph change. It is the same shape as SEMgraph's +own open item in [#2646](https://github.com/igraph/rigraph/issues/2646) +(`SEMdag(LO = "TL")` → subscript out of bounds in `buildLevels()`), and +SEMdeep `Depends` on SEMgraph, so one cause may well explain both. + +## Recommendation + +Bisect against the ellipsis-move PRs (#2757–#2778, #2784) before contacting the +maintainer. A silently different result with no warning is what a positional +argument no longer binding where it used to looks like, and if the cause is +ours then SEMgraph, not SEMdeep, is where it should be fixed.