nx_lowrank_attn.nx
buildroot/runtime/nx_lowrank_attn.nx
about
nx_lowrank_attn.nx -- M3: low-rank KV through a REAL softmax-attention forward (end-to-end quality proof).
module: nishi-core.ai.lowrank_attn capability: VRAM_REDUCTION (per-token low-rank KV, measured end-to-end)
M0/M1 measured COVARIANCE fidelity (K^T K) of an FD sketch. But softmax attention needs PER-TOKEN scores
Q.K[i], which an FD covariance sketch cannot give. The per-token low-rank compression that DOES work is
Eigen-Attention / SVD-projection: find the top-r right singular basis V_r [r x d] of K (top-r eigenvectors
of K^T K), store per-token coords[i] = K[i] @ V_r^T (n x r) + the shared basis (r x d), reconstruct
K[i] ~= coords[i] @ V_r. This PRESERVES per-token identity -> usable in real attention. The eigen-extraction
REUSES the M1 lesson: reorthogonalize (Gram-Schmidt twice) or the dominant direction leaks under f32.
PROOF: compare the attention OUTPUT (after softmax + value mixing) full-KV vs compressed-KV. For genuinely
rank-2 K/V, compressing to r>=2 reconstructs exactly -> output error ~0 (VRAM cut, quality kept end-to-end).
Sovereign: nx_f32_hw (SSE arith) + nx_f32_sqrt + nx_f32_softmax (reused). no gcc. HONEST: reference-scale d=8.
dependencies 4 imports · 0 importers
imports: nx_syscalls.nxnx_f32_hw.nxnx_f32.nxnx_f32_softmax.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 19 | const LA_MAGIC_1103515245: i64 = 1103515245 |
| 20 | const LA_MAGIC_12345: i64 = 12345 |
| 21 | const LA_MAGIC_2048: i64 = 2048 |
| 22 | const LA_MAGIC_4096: i64 = 4096 |
| 23 | const LA_MAGIC_99991: i64 = 99991 |
| 24 | const LA_MAGIC_11003: i64 = 11003 |
| 25 | const LA_MAGIC_22013: i64 = 22013 |
| 26 | const LA_MAGIC_33029: i64 = 33029 |
| 27 | const LA_MAGIC_44039: i64 = 44039 |
| 28 | const LA_MAGIC_55049: i64 = 55049 |
| 29 | const LA_MAGIC_60061: i64 = 60061 |
| 30 | const LA_MAGIC_70067: i64 = 70067 |
| 31 | const LA_MAGIC_80071: i64 = 80071 |
| 33 | const LA_POWER_ITERS: i64 = 64 |
functions
| 36 | func la_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: g_puts |
| 37 | func g_puts(s: *u8) -> i64 { sys_write(1, s, la_strlen(s)); return 0 } |
| 38 | func g_putn(v: i64) -> i64 |
| 50 | func la_is_zero(x: i64) -> i64 { if (x & 0x7fffffff) == 0 { return 1 } return 0 } |
| 52 | func f32frac(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } |
| 55 | func la_lcg(st: *i64) -> i64 { st[0] = st[0] * LA_MAGIC_1103515245 + LA_MAGIC_12345; return (st[0] >> 20) & 0xfff } |
| 58 | func la_build_rankr(M: *i64, n: i64, d: i64, r: i64, seed: i64) -> i64 |
| 83 | func la_dot(a: *i64, b: *i64, n: i64) -> i64 |
| 90 | func la_normalize(v: *i64, n: i64) -> i64 |
| 102 | func la_gmatvec(G: *i64, v: *i64, d: i64, out: *i64) -> i64 |
| 115 | func la_deflate_once(v: *i64, basis: *i64, found: i64, d: i64) -> i64 |
| 127 | func la_reorth(v: *i64, basis: *i64, found: i64, d: i64) -> i64 |
| 132 | func la_topr_basis(G: *i64, d: i64, r: i64, basis: *i64) -> i64 |
| 165 | func la_gram(M: *i64, n: i64, d: i64, G: *i64) -> i64 |
| 183 | func la_compress_reconstruct(M: *i64, n: i64, d: i64, r: i64, Mout: *i64) -> i64 |
| 214 | func la_attention(Q: *i64, Km: *i64, Vm: *i64, n: i64, d: i64, scale: i64, out: *i64) -> i64 |
| 238 | func la_rel_permille(a: *i64, b: *i64, d: i64) -> i64 |
| 254 | func la_run_compressed(Q: *i64, K: *i64, V: *i64, n: i64, d: i64, r: i64, scale: i64, out_full: *i64) -> i64 |
| 265 | func la_build_approx(M: *i64, n: i64, d: i64, base: i64, noise_num: i64, seed: i64) -> i64 |
| 274 | func main() -> i64 |