v0.2.50 — sdivi-rust v0.2.50 — Fix Leiden non-termination on pathological graphs
sdivi-rust v0.2.50 — Fix Leiden non-termination on pathological graphs
A correctness/reliability release (M49) that eliminates a non-termination path in
the native Leiden implementation. Certain small graphs with certain seeds could
make run_leiden — and therefore Pipeline::snapshot / detect_boundaries —
run for many minutes on inputs as small as 8 nodes. This is fixed, and the
regression is guarded so it cannot silently return.
snapshot_version stays "1.0". No public-API or config change. One caveat:
the fix changes the RNG draw order, so some inputs produce different — but
deterministic and quality-preserving — cluster assignments (see "Impact" below).
Highlights
- Leiden exponential-blowup fix (M49.2).
leiden_recursivepreviously descended
into the aggregated graph on every outer-loop iteration in which local moves
fired, compounding toO(max_iterations^depth)work — on the order of100^8for
an 8-node graph. It is now restructured to match Traag et al. 2019 Algorithm 1:
local moves run to convergence at each level, then the aggregate is descended into
at most once per invocation, bounding total work to
O(max_iterations × n × max_recursion_depth). The minimal reproducer found by
property testing (a K₁,₅ star, n=6, seed=0) now completes instantly. - The hang is now caught in seconds, not 30 minutes (M49.1).
proptest's
fork+timeoutfeatures are enabled for thesdivi-detectionrefinement
proptests with a per-case timeout, so any future non-terminating case fails fast
with its minimized input instead of hanging the CI runner to its job timeout. The
captured case is committed as a regression and guarded by a deterministic
termination test.
Impact on existing baselines
The category contract, snapshot schema, and config are all unchanged. The only
observable change is in community/cluster assignments for a subset of inputs:
- Inputs that previously converged in a single local-move sweep are unaffected.
- Inputs that required multiple sweeps may produce different cluster assignments
than pre-M49.2 — deterministic for a fixed seed, and within theverify-leiden
quality tolerance (modularity within 1%, community count within ±10%). - If you diff snapshots across the upgrade, re-baseline boundary/cluster fields.
SeeMIGRATION_NOTES.mdfor the full note.
What did not change
snapshot_versionis still"1.0". Snapshot JSON,pattern_metrics,
DivergenceSummary, and the 19-category contract are unchanged.- No public-API change, no new
.sdivi/config.tomlkeys. - Determinism contract holds: same repo state + same seed ⇒ bit-identical
Snapshot
(a different-but-stable output than pre-M49.2 for the affected inputs). - WASM dependency invariant (Rule 21) holds; the
.wasmstays size-optimised (~1.53 MB).
Install
# crates.io
cargo install sdivi-cli
# pre-built binary (Linux x86_64 example)
curl -Lo sdivi https://github.com/GeoffGodwin/sdivi-rust/releases/download/v0.2.50/sdivi-x86_64-unknown-linux-gnu
chmod +x sdivi && mv sdivi ~/.local/bin/
# WASM / npm
npm install @geoffgodwin/sdivi-wasm@0.2.50Documentation
- Migration notes: https://github.com/GeoffGodwin/sdivi-rust/blob/main/MIGRATION_NOTES.md
- CHANGELOG: https://github.com/GeoffGodwin/sdivi-rust/blob/main/CHANGELOG.md
Released under Apache 2.0.
Full Changelog: v0.2.48...v0.2.50