From f5f3a1cc5995efa744c451f9d51eba6b48dac1c0 Mon Sep 17 00:00:00 2001 From: Safi Date: Mon, 1 Jun 2026 21:54:11 +0100 Subject: [PATCH] stabilize community IDs so identical groupings get identical labels (#1090) Follow-up to the file-ordering fix. The from-scratch build writes each node's community field straight from cluster()'s enumerate() after a STABLE size-sort, so the hundreds of equal-sized small communities in a sparse graph were ordered by the partitioner's (not seed-stable) enumeration order. Their integer IDs permuted run-to-run, which reads as 77-88% "community churn" in a per-node cid diff even though the actual grouping is reproducible. Add a tuple(sorted(nodes)) tiebreak to make the sort a total order, so an identical grouping always yields identical community IDs. Verified: with the partition returned in shuffled order across 5 runs, the node->cid map is now identical. (A separate ~0.06% community-count drift remains - likely non-canonical edge weights upstream - tracked separately.) Co-Authored-By: Claude Opus 4.8 --- graphify/cluster.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/graphify/cluster.py b/graphify/cluster.py index a567e0cc..82f063d2 100644 --- a/graphify/cluster.py +++ b/graphify/cluster.py @@ -178,8 +178,13 @@ def cluster( second_pass.append(nodes) final_communities = second_pass - # Re-index by size descending for deterministic ordering - final_communities.sort(key=len, reverse=True) + # Re-index by size descending. The tuple(sorted(nodes)) tiebreak makes this a + # TOTAL order, so an identical grouping always gets identical community IDs. + # Without it, the hundreds of equal-sized small communities are ordered by the + # partitioner's (not seed-stable) enumeration order, so their integer IDs + # permute run-to-run - which reads as massive "community churn" in a per-node + # cid diff even though the actual grouping is reproducible (#1090 follow-up). + final_communities.sort(key=lambda nodes: (-len(nodes), tuple(sorted(map(str, nodes))))) return {i: sorted(nodes) for i, nodes in enumerate(final_communities)}