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}