nx_token_merge.nx
buildroot/runtime/nx_token_merge.nx
about
nx_token_merge.nx -- H8 token merging plan (bits-up).
Per NISHI_ELDER_AI_OFF_DOCKER_2026_05_20.md ยง2.1 H8: token
merging (ToMe, Bolya 2022 "Token Merging: Your ViT But Faster")
shortens the attention sequence by merging the top-K most
similar token pairs at layer boundaries. Used in ViT and
Stable Diffusion to drop 30-50% of tokens with minimal quality
loss. Linear-time savings: shrinking seq from N to N*(1-r)
at every L layers cuts overall attention FLOPs ~(1-r)^L.
V1 mechanics: substrate primitive does NOT compute the
similarity matrix. It accepts a pre-computed array of
(left_idx, right_idx, score_q16) triples sorted by descending
score, and a target_merges count. It greedily walks the
sorted list, merging each pair where BOTH tokens are still
"kept" (no prior merge), until target_merges is reached or
the list is exhausted. Returns the actual merges executed
(which can be less than requested if not enough non-conflicting
pairs were available).
Composition path:
- Consumer kernel computes cosine sim between adjacent tokens
(substrate Q16-mul + dot product primitives)
- Consumer sorts the resulting (i, j, score) triples by
score desc using shipped nx_mergesort
- nx_token_merge_apply(plan, sorted_pairs, n_pairs, target)
populates the assignment table
- Downstream attention layer reads target_for(idx) to know
which slot each token routes to; merged tokens are dropped
from the active sequence
Pure substrate logic. No Linux features. Composes with shipped
nx_mergesort (consumer-side sort dependency).
V1 honest scope:
- Caller pre-sorts; substrate does NOT sort internally (would
duplicate nx_mergesort and force a bigger primitive)
- Greedy merge (top-down) -- the published ToMe paper proves
this matches bipartite matching within a fraction of a
percent on real model quality, at half the implementation
dependencies 1 imports · 2 importers
imports: nx_syscalls.nx
imported by: nx_hackers_algo_compose_test.nxnx_token_merge_test.nx
structs
| 103 | struct NxTokenMergePlan |
consts
| 78 | const NX_MAGIC_65536: i64 = 65536 |
| 81 | const NX_TOMERGE_MAX_TOKENS: i64 = 4096 |
| 84 | const NX_TOMERGE_PAIR_STRIDE: i64 = 3 // (left, right, score) |
| 87 | const NX_TOMERGE_OK: i64 = 0 |
| 88 | const NX_TOMERGE_BAD_INPUT: i64 = 1 |
| 89 | const NX_TOMERGE_TAMPER: i64 = 2 |
| 90 | const NX_TOMERGE_N_VERDICTS: i64 = 3 |
| 99 | const NX_TOMERGE_CANARY_PRE: i64 = 0x546F4D67506C617A // "ToMgPlaz" |
| 100 | const NX_TOMERGE_CANARY_POST: i64 = 0x506C616E45314433 // "PlanE1D3" |
functions
| 92 | func nx_tomerge_verdict_is_valid(v: i64) -> i64 called by 1: main |
| 112 | func nx_token_merge_plan_is_valid(p: *NxTokenMergePlan) -> i64 |
| 126 | func nx_token_merge_plan_new(n_tokens: i64) -> *NxTokenMergePlan |
| 160 | func nx_token_merge_apply(p: *NxTokenMergePlan, sorted_pairs: *i64, n_pairs: i64, target_merges: i64) -> i64 |
| 201 | func nx_token_merge_target_for(p: *NxTokenMergePlan, idx: i64) -> i64 |
| 208 | func nx_token_merge_is_kept(p: *NxTokenMergePlan, idx: i64) -> i64 |
| 216 | func nx_token_merge_n_kept(p: *NxTokenMergePlan) -> i64 |
| 221 | func nx_token_merge_n_merged(p: *NxTokenMergePlan) -> i64 |
| 226 | func nx_token_merge_n_tokens(p: *NxTokenMergePlan) -> i64 |
| 232 | func nx_token_merge_reduction_q16(p: *NxTokenMergePlan) -> i64 |