Skip to content

fix: Keep rejecting directed graphs in cluster_leiden(), and pin its reported quality - #2996

Merged
krlmlr merged 2 commits into
mainfrom
claude/f1-leiden-directed-tests
Oct 18, 2026
Merged

krlmlr merged 2 commits into
mainfrom
claude/f1-leiden-directed-tests

Conversation

@krlmlr

@krlmlr krlmlr commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

cluster_leiden() now rejects a directed graph in R, before it calls the C core, and three new tests pin what the function does today. This is the first of five stacked pull requests that bring work from the vendoring series to main ahead of the C core 1.0 upgrade.

What it changes

cluster_leiden() raises "Leiden algorithm is only implemented for undirected graphs." for a directed graph, right after ensure_igraph(graph). On main the vendored C core already raises the same message, so the behaviour does not change; only the error now comes from R. The C core accepts directed graphs from igraph 1.0 on, but this wrapper passes no in-weights and scales the resolution for undirected modularity, so on a directed graph it would silently optimize undirected modularity at twice the resolution, and its $quality would disagree with modularity(). The check keeps the behaviour of igraph 2.3.4 across the engine upgrade. Proper directed support would need the in-weights exposed and the resolution scaled by the edge count, which is beyond this fix.

The new tests in tests/testthat/test-community.R:

  • Directed input is rejected for the modularity and CPM objectives and for a weighted graph, matched by a regular expression on the message rather than a snapshot, so it holds for the C error and the R error alike.
  • On undirected graphs, the reported $quality of the modularity objective equals modularity() of the returned membership, at resolutions 0.5, 1 and 2 on the karate graph and on a weighted pair of triangles.
  • The resolution moves the partition between one community (0.01) and singletons (50).

man/cluster_leiden.Rd now also links igraph_is_directed() under "Related documentation in the C library", which the C-docs roclet derives from the new call.

This supersedes the series-side fix in draft #2991: the R check is the R side of 9ad4bcb on claude/f1-leiden-directed, without its tests, which this branch already carries.

Checks

devtools::document() produced the man/cluster_leiden.Rd change above, committed here; air format changes nothing. test-community.R passes all 36 blocks against a build of this branch, and the tests also pass on main without the R check.

LLM use: this PR was prepared with Claude Code (Claude Opus 5.5), at the maintainer's request. The tests and the R check come from the subsession https://claude.ai/code/session_015GouVEqbVWVYs6hH8zvrRc.

  • By submitting this pull request, I assign the copyright of my contribution to The igraph development team.

Generated by Claude Code

…lity

Directed input is rejected with the C core's error,
for the modularity and CPM objectives and for weighted graphs.
On undirected graphs, the reported `$quality` of the modularity objective
agrees with `modularity()` at the same resolution,
for an unweighted and a weighted graph,
and the resolution moves the partition between one community and singletons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GouVEqbVWVYs6hH8zvrRc
…C core

The C core accepts directed graphs from igraph 1.0 on,
but this wrapper passes no in-weights and scales the resolution for undirected modularity,
so on a directed graph it would silently optimize the wrong objective.
The check in R keeps the behaviour of igraph 2.3.4 across the engine upgrade,
with the message the C core raises today.

The R side of 9ad4bcb on `claude/f1-leiden-directed`, without its tests,
which this branch already carries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnA76zWTu4ZD8BQCSYRpk
@github-actions

Copy link
Copy Markdown
Contributor

This is how benchmark results would change (along with a 95% confidence interval in relative change) if c528af9 is merged into main:

  • ✔️E_named: 215ms -> 214ms [-0.69%, +0.29%]
  • ✔️V_named: 448ms -> 447ms [-0.75%, +0.29%]
  • ✔️all_simple_paths_named: 162ms -> 163ms [-0.08%, +0.89%]
  • ✔️as_adjacency_matrix: 211ms -> 210ms [-0.52%, +0.29%]
  • 🚀as_biadjacency_matrix: 249ms -> 247ms [-1.3%, -0.36%]
  • ✔️as_data_frame_both: 236ms -> 237ms [-0.09%, +0.78%]
  • ✔️as_long_data_frame: 208ms -> 207ms [-0.56%, +0.17%]
  • ✔️degree_few_vertices: 100ms -> 100ms [-0.42%, +0.68%]
  • ✔️ego_order2_named: 164ms -> 164ms [-0.6%, +0.36%]
  • ✔️es_attr_assign: 237ms -> 237ms [-0.39%, +0.55%]
  • ✔️es_attr_filter: 242ms -> 242ms [-0.68%, +0.09%]
  • ✔️graph_from_adjacency_matrix: 267ms -> 267ms [-0.22%, +0.44%]
  • 🚀graph_from_data_frame: 281ms -> 277ms [-1.99%, -0.81%]
  • ✔️head_of_named: 180ms -> 179ms [-1.51%, +0.43%]
  • 🚀incident_edges: 199ms -> 198ms [-0.92%, -0.01%]
  • 🚀max_cliques_named: 27.7ms -> 27.5ms [-1.25%, -0.15%]
  • ✔️neighbors_by_name: 205ms -> 205ms [-0.52%, +0.57%]
  • ✔️union_named: 234ms -> 233ms [-1.62%, +0.39%]
  • ✔️vs_attr_filter: 297ms -> 291ms [-5.68%, +1.53%]
  • ✔️vs_by_name: 257ms -> 257ms [-0.8%, +0.68%]
    Further explanation regarding interpretation and methodology can be found in the documentation.

@krlmlr
krlmlr merged commit 50fc7d4 into main Oct 18, 2026
12 checks passed
@krlmlr
krlmlr deleted the claude/f1-leiden-directed-tests branch October 18, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants