nx_kda.nx source
↩ module page · 57 lines · 3089 B
1// nx_kda.nx -- KDA LANE SUPPORT: the KDA:MLA interleave schedule. Deliberately does NOT reimplement the
2// KDA kernel.
3//
4// WHY THIS FILE IS SMALL. An earlier pass this session built a full KDA numeric core here, then found that
5// _hdl_build/nx_nofloat_kda.nx already implements it -- and better: Q16 not Q10, a whole-sequence forward
6// rather than single steps, scratch hoisted out of the step loop, DRY reuse of nx_nofloat_linattn. The
7// duplicate was removed rather than left to rot beside it. It was also a live hazard: both files defined
8// kda_write and kda_step with DIFFERENT signatures, so any organ importing both would have broken.
9//
10// CORRECTION (same session, after the above was written): the schedule below is ALSO a duplicate. It was
11// claimed here as "the part nobody had built", and that was wrong -- `_hdl_build/nx_nofloat_k3interleave.nx`
12// implements the 3:1 structure more completely, assembling a real [KDA,KDA,KDA,MLA] stack from the proven
13// KDA and MLA organs, and its gate T5 asserts the schedule mechanically (6 KDA : 2 MLA over 8 layers, MLA
14// at l=3,7). That organ is now BUILT and RUN, 6/6 GREEN.
15//
16// THE AUTHORITATIVE ORGANS ARE THEIRS, NOT THIS FILE. Do not adopt the schedule below for new work; use
17// nx_nofloat_k3interleave. What survives here that is genuinely NOT covered elsewhere is only the
18// FACTORISATION IDENTITY proved in nx_kda_gate T1-T3, plus kdasched_kv_cut_permille, which turns the
19// reported 75% KV cut into a computed number (750 permille) rather than a claim. The schedule functions
20// remain solely because that permille calculation is built on them.
21//
22// Kept deliberately small and clearly labelled rather than silently left to rot beside the real thing.
23//
24// Names are prefixed kdasched_ so this can never collide with the kernel's kda_* symbols.
25// Kernel: _hdl_build/nx_nofloat_kda.nx (gate 5/5 GREEN, first ever built + run 2026-07-31).
26// license_tier: ORIGINAL No hw writes (Rule 26).
27import "nx_syscalls.nx"
28
29const KDASCHED_LINEAR: i64 = 0
30const KDASCHED_FULL: i64 = 1
31
32// Which attention kind sits at depth `layer` for `ratio` linear layers per 1 full layer?
33// Every (ratio+1)-th layer is full attention; the rest are linear (KDA).
34func kdasched_kind(layer: i64, ratio: i64) -> i64 {
35 if ratio <= 0 { return KDASCHED_FULL }
36 if ((layer + 1) % (ratio + 1)) == 0 { return KDASCHED_FULL }
37 return KDASCHED_LINEAR
38}
39
40// how many of n_layers still keep a KV cache that GROWS with sequence length
41func kdasched_full_layers(n_layers: i64, ratio: i64) -> i64 {
42 var c: i64 = 0
43 var l: i64 = 0
44 while l < n_layers {
45 if kdasched_kind(l, ratio) == KDASCHED_FULL { c = c + 1 }
46 l = l + 1
47 }
48 return c
49}
50
51// KV-growth reduction in permille vs an all-full-attention stack of the same depth.
52// This is the schedule's whole point, so it is a function and not a comment.
53func kdasched_kv_cut_permille(n_layers: i64, ratio: i64) -> i64 {
54 if n_layers <= 0 { return 0 }
55 let full: i64 = kdasched_full_layers(n_layers, ratio)
56 return ((n_layers - full) * 1000) / n_layers
57}