09_leiden

command
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 15 Imported by: 0

README

Example 09 — Leiden community detection

What it demonstrates

Modularity-optimising community detection with community.Leiden: build a graph that has a genuine, tunable community structure, freeze it into an immutable CSR snapshot, run Leiden, read the resulting Partition back, and measure how well Leiden recovered the planted structure by computing the Newman modularity Q of its output.

Domain / scenario

A seeded planted-partition graph (symmetric stochastic block model): -communities (K) equal-sized blocks of -community-size (s) nodes each. Every unordered node pair is offered an undirected edge independently — with probability -p-in when the two nodes share a block and -p-out when they do not. With p-in ≫ p-out the blocks are dense inside and sparse between, so a modularity-optimising method recovers them.

The default parameters place the partition about three times above the SBM detectability (Kesten–Stigum) threshold, deep in the regime where Leiden reliably recovers the planting. The generator guidance — the detectability threshold, the per-block Erdős–Rényi connectivity floor that validate() enforces, and the planted-partition modularity expectation — was supplied by the graph-theory-expert sub-agent and is recorded in the leading doc comment and the validate / computeModularity comments.

How to run

go run ./examples/09_leiden                                                       # small deterministic default
go run ./examples/09_leiden -communities 8 -community-size 500 -p-in 0.06 -p-out 0.0008 -seed 7  # observable-scale run

Scale and flags

Flag Meaning Default Representative large value
-communities number of planted communities K 4 8
-community-size nodes per community s 25 500
-p-in intra-community edge probability 0.55 0.06
-p-out inter-community edge probability 0.01 0.0008
-seed RNG seed (fixes the data shape exactly) 1 any int64

The default builds 100 nodes and ~700 edges and finishes in well under a second; it is the shape pinned by the regression test. The large invocation builds 4 000 nodes and ~130 000 edges, where the detection cost becomes observable. validate() rejects configurations that cannot produce a recoverable partition: p-in must exceed p-out, and p-in must clear the connectivity floor 2·ln(s)/(s−1) so a block cannot fragment into singletons and inflate the recovered community count.

Expected output

Bare lines are deterministic facts (reproducible for a fixed -seed); the rounded modularity is pinned to two decimals as a fact, with the full value reported as telemetry. Lines prefixed with # are volatile telemetry and vary per run and per machine.

config.communities=4
config.community_size=25
config.p_in=0.55
config.p_out=0.01
config.seed=1
nodes=100
edges=701
communities_found=4
modularity=0.69
# build.elapsed=352µs              # telemetry — varies per run/machine
# build.edge_rate=1991947 edges/s  # telemetry
# mem.heap_growth=14.36 KiB        # telemetry
# detect.elapsed=170µs             # telemetry
# detect.node_rate=587085 nodes/s  # telemetry
# modularity.exact=0.694232        # telemetry

Leiden's output is deterministic for a fixed input graph, so for the default seed the modularity is exactly 0.694232 run to run. Because Leiden is randomised internally by contract, the regression test asserts a lower bound (Q ≥ 0.55) and a community-count band (K ± 1, i.e. 4 here) rather than an exact float, so it survives an internal change that preserves partition quality.

Evidence it collects

For a community-detection subject the example reports (per the evidence taxonomy in docs/examples-standard.md):

  • Number of communities recovered vs. the planted K — the headline correctness signal.
  • Newman modularity Q of the returned partition — the objective Leiden maximises, computed directly over the CSR snapshot.
  • Build and detection wall-clock and throughput (# telemetry).
  • Live-heap growth of the graph snapshot (# telemetry).

When you scale it up (-communities 8 -community-size 500), watch the detection wall-clock and the recovered count: Leiden should still recover exactly K communities with Q ≈ 0.79, while # detect.elapsed grows with the graph. go test -bench=BenchmarkRun -benchmem ./examples/09_leiden runs the large configuration mechanically.

Key APIs

  • graph/adjlist.New / AdjList.AddNode / AddEdge — build the mutable, undirected planted-partition graph.
  • graph/csr.BuildFromAdjList — freeze the builder into an immutable CSR snapshot for analytics.
  • graph/csr.CSR.VerticesSlice / EdgesSlice / MaxNodeID — the offsets/edges arrays the modularity computation walks in O(V+E).
  • search/community.LeidenCtx / DefaultLeidenOptions — run context-aware Leiden community detection.
  • search/community.Partition — the result: NumCommunities and a NodeID-indexed Community slice whose ghost slots carry the sentinel -1.

Further reading

Documentation

Overview

Example 09_leiden — modularity-optimising community detection with community.Leiden over a realistic, seeded planted-partition graph.

It generates a symmetric stochastic block model (SBM) — K equal-sized planted communities with a high intra-community edge probability and a low inter-community edge probability — freezes it into an immutable CSR snapshot, runs Leiden, and reports how well Leiden recovers the planted structure: the number of communities found and the Newman modularity Q of the returned partition, alongside the volatile build/detect timing.

Model

The graph is undirected and unweighted. The N = communities × communitySize nodes are partitioned into K equal blocks. For every unordered node pair (i, j) an edge is drawn independently with probability pIn when i and j share a block and pOut when they do not. This is the planted-partition / symmetric-SBM construction; fixing -seed fixes the drawn edge set, hence the graph shape, exactly.

Why these parameters

The graph-theory-expert sub-agent supplied the regime (recorded inline at sbmParams and computeModularity):

  • Detectability follows the Kesten–Stigum / Decelle–Krzakala–Moore– Zdeborová threshold for the symmetric SBM: with intra-degree a = pIn·(s−1) and per-other-block inter-degree b = pOut·s over K blocks, weak recovery is possible iff SNR = (a−b)² / [K·(a + (K−1)·b)] > 1. The defaults sit ≈3× above that threshold, deep in the "easy" regime, so Leiden reliably recovers the planting.
  • Each block is an Erdős–Rényi G(s, pIn) subgraph; it stays internally connected with high probability when pIn·(s−1) ≥ 2·ln(s), which validate enforces so a planted community cannot fragment and inflate the community count.
  • The planted partition's expected modularity is Q ≈ (intra-edge fraction) − 1/K, which the small default targets at ≈0.70 (theoretical max 1 − 1/K = 0.75 for K=4).

Scale

Run with no flags, the example builds the small deterministic default — four communities of twenty-five nodes (100 nodes, ~700 edges) — which completes in well under a second and is pinned by the regression test. Every dimension is a flag, so the same binary scales up to a size where the detect cost is observable:

go run ./examples/09_leiden -communities 8 -community-size 500 -p-in 0.06 -p-out 0.0008 -seed 7

The deterministic facts (community count and the modularity reported to two decimals) are reproducible for a fixed -seed; only the telemetry (lines prefixed with "# ") varies between runs and machines.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL