code wiki / _hdl_build / nx_ng_volrender.nx

nx_ng_volrender.nx source

↩ module page · 149 lines · 7690 B

1// nx_ng_volrender.nx -- CAP-VOLUME-RENDER, generation 7 on the neural-graphics ladder (nx_ng_gap named it 2// the next missing generation after CAP-DIFF-RENDER). The volumetric ALPHA-OVER compositing operator that is 3// the actual render op of NeRF (after the density->alpha map) AND the core of 3D Gaussian Splatting: 4// T_0 = 1 ; C = sum_i T_i * alpha_i * c_i ; T_{i+1} = T_i * (1 - alpha_i) 5// i.e. front-to-back "over" compositing along a ray. Q16 fixed-point, no float, sovereign syscalls only. 6// 7// Honest gated proof (HARD evidence per the genealogy ladder): 8// T1 FORWARD correctness -- opaque front occludes the rest (C==c0); all-transparent shows background (C==0); 9// half-opaque samples composite to the hand-checked weighted sum (transmittance chain is right). 10// T2 DIFFERENTIABLE -- the per-sample compositing weight w_i = T_i*alpha_i IS dC/dc_i; GD on the sample 11// colors drives the composited C -> a target C*, loss -> ~0 (gradients flow through the render). 12// T3 NEG-CONTROL -- ascending that gradient DIVERGES (the gradient has correct direction/teeth). 13// T4 GRADCHECK -- sign(analytic dLoss/dc0) == sign(L(c0+e)-L(c0-e)). 14// NOTE: the NeRF density form alpha=1-exp(-sigma*delta) is a thin wrapper over this (exp helper already in 15// nx_nofloat_autograd); the alpha/sigma gradient is the follow-on rung. license_tier: ORIGINAL expect_exit: 0 16import "nx_syscalls.nx" 17const K_MAGIC_13107: i64 = 13107 18const K_MAGIC_26214: i64 = 26214 19const K_MAGIC_39321: i64 = 39321 20const K_MAGIC_52429: i64 = 52429 21const K_MAGIC_49000: i64 = 49000 22const K_MAGIC_49300: i64 = 49300 23const K_MAGIC_104856: i64 = 104856 24 25const Q: i64 = 65536 26const H: i64 = 32768 // 0.5 27const NS: i64 = 4 // samples along the ray 28const LR: i64 = 65536 // 1.0 (Q16); composite is linear in c -> stable 29const NSTEP: i64 = 40 30const NASC: i64 = 6 // neg-control ascent steps (bounded: ascent grows error ~1.66x/step -> avoid i64 overflow) 31const CSTAR: i64 = 26214 // target composited color = 0.4 32const EPS: i64 = 655 // finite-diff step = 0.01 33 34func vp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 35func vpn(v: i64) -> i64 { 36 let bb: *u8 = sys_mmap(28); var m: i64 = v 37 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 38 let t: *u8 = sys_mmap(28); var k: i64 = 0 39 if m == 0 { t[0] = 48 as u8; k = 1 } 40 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 41 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 42 sys_write(1, bb, k); return 0 43} 44func vqm(a: i64, b: i64) -> i64 { return (a * b) >> 16 } 45 46// front-to-back over-compositing. fills w[i] = T_i*alpha_i (the compositing weight = dC/dc_i). returns C. 47func vr_forward(alpha: *i64, col: *i64, w: *i64) -> i64 { 48 var T: i64 = Q; var C: i64 = 0; var i: i64 = 0 49 while i < NS { 50 let wi: i64 = vqm(T, alpha[i]) 51 w[i] = wi 52 C = C + vqm(wi, col[i]) 53 T = vqm(T, Q - alpha[i]) 54 i = i + 1 55 } 56 return C 57} 58func vr_loss(C: i64, cstar: i64) -> i64 { let d: i64 = C - cstar; return vqm(d, d) } 59 60func main() -> i64 { 61 vp("=== nx_ng_volrender: CAP-VOLUME-RENDER -- differentiable alpha-over compositing (Q16, no float) ===\n" as *u8) 62 let alpha: *i64 = sys_mmap(8 * NS) 63 let col: *i64 = sys_mmap(8 * NS) 64 let w: *i64 = sys_mmap(8 * NS) 65 66 // ---- T1 FORWARD correctness ---- 67 // T1a: opaque front (alpha0=1) -> C == col0 (front fully occludes the rest) 68 alpha[0] = Q; alpha[1] = 0; alpha[2] = 0; alpha[3] = 0 69 col[0] = K_MAGIC_13107; col[1] = K_MAGIC_26214; col[2] = K_MAGIC_39321; col[3] = K_MAGIC_52429 70 let Ca: i64 = vr_forward(alpha, col, w) 71 let t1a: i64 = (Ca == K_MAGIC_13107) 72 // T1b: all transparent -> C == 0 (background) 73 alpha[0] = 0; alpha[1] = 0; alpha[2] = 0; alpha[3] = 0 74 let Cb: i64 = vr_forward(alpha, col, w) 75 let t1b: i64 = (Cb == 0) 76 // T1c: all half-opaque, col=0.8 -> weighted over-composite (~0.9375*0.8 = 0.75 = 49152, fixed-pt ~49150) 77 alpha[0] = H; alpha[1] = H; alpha[2] = H; alpha[3] = H 78 col[0] = K_MAGIC_52429; col[1] = K_MAGIC_52429; col[2] = K_MAGIC_52429; col[3] = K_MAGIC_52429 79 let Cc: i64 = vr_forward(alpha, col, w) 80 var t1c: i64 = 0 81 if Cc > K_MAGIC_49000 { if Cc < K_MAGIC_49300 { t1c = 1 } } 82 vp(" T1 FORWARD: opaque-front C=" as *u8); vpn(Ca); vp(" (==col0 13107? " as *u8); vpn(t1a) 83 vp(") transparent C=" as *u8); vpn(Cb); vp(" (==0? " as *u8); vpn(t1b) 84 vp(") half-opaque C=" as *u8); vpn(Cc); vp(" (~49150? " as *u8); vpn(t1c); vp(")\n" as *u8) 85 86 // ---- T2 DIFFERENTIABLE: GD on sample colors to hit target C* ---- 87 alpha[0] = H; alpha[1] = H; alpha[2] = H; alpha[3] = H 88 col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0 89 var C0: i64 = vr_forward(alpha, col, w) 90 let loss0: i64 = vr_loss(C0, CSTAR) 91 var step: i64 = 0 92 while step < NSTEP { 93 let C: i64 = vr_forward(alpha, col, w) 94 let dc: i64 = C - CSTAR 95 var i: i64 = 0 96 while i < NS { col[i] = col[i] - vqm(LR, 2 * vqm(dc, w[i])); i = i + 1 } 97 step = step + 1 98 if step % 10 == 0 { vp(" step " as *u8); vpn(step); vp(" C=" as *u8); vpn(vr_forward(alpha, col, w)); vp(" loss=" as *u8); vpn(vr_loss(vr_forward(alpha, col, w), CSTAR)); vp("\n" as *u8) } 99 } 100 let CN: i64 = vr_forward(alpha, col, w) 101 let lossN: i64 = vr_loss(CN, CSTAR) 102 var dCN: i64 = CN - CSTAR 103 if dCN < 0 { dCN = 0 - dCN } 104 var converged: i64 = 0 105 if lossN * 50 < loss0 { if dCN < 327 { converged = 1 } } 106 vp(" T2 DESCENT: target C*=" as *u8); vpn(CSTAR); vp(" final C=" as *u8); vpn(CN); vp(" loss " as *u8); vpn(loss0); vp("->" as *u8); vpn(lossN); vp(" converged=" as *u8); vpn(converged); vp("\n" as *u8) 107 108 // ---- T4 GRADCHECK (sign) at col=0 state ---- 109 col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0 110 let Cg: i64 = vr_forward(alpha, col, w) 111 let ga: i64 = 2 * vqm(Cg - CSTAR, w[0]) 112 col[0] = EPS; let lp: i64 = vr_loss(vr_forward(alpha, col, w), CSTAR) 113 col[0] = 0 - EPS; let lm: i64 = vr_loss(vr_forward(alpha, col, w), CSTAR) 114 let fd: i64 = lp - lm 115 var sign_ok: i64 = 0 116 if ga > 0 { if fd > 0 { sign_ok = 1 } } 117 if ga < 0 { if fd < 0 { sign_ok = 1 } } 118 if ga == 0 { if fd == 0 { sign_ok = 1 } } 119 vp(" T4 GRADCHECK(sign): analytic=" as *u8); vpn(ga); vp(" finite-diff=" as *u8); vpn(fd); vp(" match=" as *u8); vpn(sign_ok); vp("\n" as *u8) 120 121 // ---- T3 NEG-CONTROL: ascend the gradient (bounded steps) -> error must GROW (loss would overflow i64) ---- 122 col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0 123 var s2: i64 = 0 124 while s2 < NASC { 125 let C: i64 = vr_forward(alpha, col, w) 126 let dc: i64 = C - CSTAR 127 var i: i64 = 0 128 while i < NS { col[i] = col[i] + vqm(LR, 2 * vqm(dc, w[i])); i = i + 1 } 129 s2 = s2 + 1 130 } 131 let Casc: i64 = vr_forward(alpha, col, w) 132 var errA: i64 = Casc - CSTAR 133 if errA < 0 { errA = 0 - errA } 134 var diverged: i64 = 0 135 if errA > K_MAGIC_104856 { diverged = 1 } 136 vp(" T3 ASCENT(neg-control): C=" as *u8); vpn(Casc); vp(" |C-C*|=" as *u8); vpn(errA); vp(" diverged=" as *u8); vpn(diverged); vp(" (init err=26214, thr=104856)\n" as *u8) 137 138 var ok: i64 = 1 139 if t1a != 1 { ok = 0 } 140 if t1b != 1 { ok = 0 } 141 if t1c != 1 { ok = 0 } 142 if converged != 1 { ok = 0 } 143 if sign_ok != 1 { ok = 0 } 144 if diverged != 1 { ok = 0 } 145 vp(" verdict=" as *u8) 146 if ok == 1 { vp("GREEN (over-compositing correct + differentiable: GD hits C*, ascent diverges, gradcheck signs match)\n" as *u8); sys_exit(0); return 0 } 147 vp("RED\n" as *u8) 148 sys_exit(1); return 1 149}