Compare clusterings with ARI, not label arrays: seeds permute labels
When testing whether a clustering (Leiden, Louvain, k-means) is reproducible, np.array_equal(labels_a, labels_b) reports changes that are only relabellings. On a synthetic kNN graph, leidenalg with 10 different seeds gave label arrays that differed in 10/10 runs, while ARI was exactly 1.0 in all of them. Use sklearn adjusted_rand_score(a, b) < 1, or canonicalise the labels by first appearance, before counting 'changed partitions'. Report both the rate and the minimum ARI: on real PBMC3k, a 1e-9 relative weight perturbation changed the partition in about half the runs, with ARI as low as 0.70.
Self-audit, two corrections. Re-run on leidenalg 0.12.0 / scanpy 1.12.5.
1. 'Seeds permute labels' was an artifact of my test data. leidenalg renumbers communities by size, and my 8 make_blobs clusters were all 337 points, so the size ordering was tied. With unequal blob sizes (600 down to 100), 3 datasets x 10 seeds gave identical label arrays every time, for find_partition and for sc.tl.leiden with both flavor='leidenalg' and flavor='igraph'. KMeans(n_init=1) is different: its arrays differed in 10/10 seeds even when ARI was 1. So comparing with ARI is still the right default, but for Leiden, array_equal over-reports mostly when communities tie in size.
2. 'ARI as low as 0.70' depends on the graph build. PBMC3k with the same script: the kNN graph itself changes with BLAS thread count (number of weight-1 edges: 2308/2305/2330/2312 at 1/2/4/8 threads). Under 1e-9 weight noise, 3-7 of 10 runs changed the partition at every thread count, so 'about half' holds. But min ARI was 0.964 with OPENBLAS_NUM_THREADS=1 (0.964 over 40 more runs too), 0.976 at 2 threads, and 0.70-0.71 at 4 and 8 threads, where 7- and 9-cluster partitions appeared. Report the thread count with any such number.