Skip to content

python-math #22: feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy) - #2650

Draft
jucor wants to merge 1 commit into
spr/edge/0add28f3from
spr/edge/d5f1f51d
Draft

python-math #22: feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy)#2650
jucor wants to merge 1 commit into
spr/edge/0add28f3from
spr/edge/d5f1f51d

Conversation

@jucor

@jucor jucor commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

What

The greedy floor (conversation.clj:259-268) — the legacy rule that admits the top voters into in-conv (the set of participants included in clustering) when too few meet the vote threshold — sorts the user-vote-counts hash-map with a STABLE sort by count descending, so equal-count ties follow Clojure's PersistentHashMap ITERATION ORDER. That order is deterministic: keys sort by successive 5-bit chunks (low first) of Murmur3 hashLong (Clojure's hasheq for Long keys). Validated against three recorded-blob oracles (the raw key order of user-vote-counts: vw front-loaded6 n=18, vw uniform8 n=30, biodiversity n=98 — all exact).

Why

The PR-E port (#2623) assumed this order was non-deterministic and substituted matrix row order. On vw front-loaded6 step 0 that admits pid 14 where Clojure admits pid 17 (a five-way 1-vote tie at the floor boundary), seeding an in-conv / base-cluster membership divergence that cascades through every downstream key — the battery's last diverging entry.

How it works

Adds polismath/utils/clj_hash.py (hashLong + HAMT key order; integer keys only, with a documented row-order fallback otherwise) and applies it to the legacy greedy candidate order. Clojure's array-map (used for maps of <=8 entries, insertion-ordered) cannot affect the pick: ties only matter with >=16 participants, which guarantees a hash-map. improved mode (the engine setting that keeps Python's corrected behavior) is unchanged.

commit-id:d5f1f51d


Stack:


⚠️ Part of a stack created by spr. Do not merge manually using the UI - doing so may have unexpected results.

This was referenced Jul 22, 2026
@jucor
jucor force-pushed the spr/edge/0add28f3 branch from f5a2c36 to aa5a214 Compare July 22, 2026 02:31
@jucor
jucor force-pushed the spr/edge/d5f1f51d branch from 16a2920 to 1f33fd2 Compare July 22, 2026 02:31
@jucor jucor changed the title feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy) feat(math): Clojure hash-map iteration order for the in-conv greedy t… Jul 22, 2026
@jucor
jucor changed the base branch from spr/edge/0add28f3 to edge July 22, 2026 03:54
@jucor
jucor force-pushed the spr/edge/d5f1f51d branch from 1f33fd2 to 288f984 Compare July 22, 2026 03:54
@jucor jucor changed the title feat(math): Clojure hash-map iteration order for the in-conv greedy t… feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy) Jul 22, 2026
@jucor
jucor changed the base branch from edge to spr/edge/0add28f3 July 22, 2026 03:54
This was referenced Jul 27, 2026
@jucor
jucor force-pushed the spr/edge/0add28f3 branch from 5e139c1 to f870240 Compare July 28, 2026 00:11
@jucor
jucor force-pushed the spr/edge/d5f1f51d branch from 5bf8560 to b0ec0c4 Compare July 28, 2026 00:11
@jucor jucor changed the title feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy) python-math #22: feat(math): Clojure hash-map iteration order for the in-conv greedy tie-break (legacy) Jul 28, 2026
… in-conv greedy tie-break (legacy)

## What

The greedy floor (conversation.clj:259-268) — the legacy rule that admits the top voters into in-conv (the set of participants included in clustering) when too few meet the vote threshold — sorts the user-vote-counts hash-map with a STABLE sort by count descending, so equal-count ties follow Clojure's PersistentHashMap ITERATION ORDER. That order is deterministic: keys sort by successive 5-bit chunks (low first) of Murmur3 hashLong (Clojure's hasheq for Long keys). Validated against three recorded-blob oracles (the raw key order of user-vote-counts: vw front-loaded6 n=18, vw uniform8 n=30, biodiversity n=98 — all exact).

## Why

The PR-E port (#2623) assumed this order was non-deterministic and substituted matrix row order. On vw front-loaded6 step 0 that admits pid 14 where Clojure admits pid 17 (a five-way 1-vote tie at the floor boundary), seeding an in-conv / base-cluster membership divergence that cascades through every downstream key — the battery's last diverging entry.

## How it works

Adds `polismath/utils/clj_hash.py` (hashLong + HAMT key order; integer keys only, with a documented row-order fallback otherwise) and applies it to the legacy greedy candidate order. Clojure's array-map (used for maps of <=8 entries, insertion-ordered) cannot affect the pick: ties only matter with >=16 participants, which guarantees a hash-map. improved mode (the engine setting that keeps Python's corrected behavior) is unchanged.

commit-id:d5f1f51d
@jucor
jucor force-pushed the spr/edge/0add28f3 branch from f870240 to f907436 Compare July 28, 2026 01:10
@jucor
jucor force-pushed the spr/edge/d5f1f51d branch from b0ec0c4 to fb8cc7a Compare July 28, 2026 01:10
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