code wiki / _hdl_build / nx_ng_diffrender.nx

nx_ng_diffrender.nx source

↩ module page · 114 lines · 6214 B

1// nx_ng_diffrender.nx -- CAP-DIFF-RENDER, the next missing generation past the sovereign-raster substrate 2// (nx_ng_gap: prereqs CAP-RASTER + CAP-NF-AUTOGRAD BUILT -> this is the adjacent-possible build). The FIRST 3// rung of differentiable rendering: gradients of rendered PIXELS w.r.t. a SCENE PARAMETER, the substrate 4// NeRF / 3D-Gaussian-Splatting optimization is built on. 5// 6// Minimal honest proof (operator: measured, no wave; HARD evidence per the genealogy ladder): a 1D soft-edge 7// rasterizer renders an image from one scene param p (the edge position) in Q16 fixed-point. We then OPTIMIZE 8// p by gradient descent to match a target image (rendered at p*). Correctness is proven the rigorous way: 9// T1 DESCENT converges -- GD on p drives loss -> ~0 and p -> p* (the gradient points the right way), 10// T2 NEG-CONTROL diverges -- ASCENDING the same gradient INCREASES loss (the gradient has teeth/direction), 11// T3 finite-difference SIGN check -- sign(analytic dLoss/dp) == sign((L(p+e)-L(p-e))) (the gradient is real), 12// T4 zero-at-optimum -- loss(p*) == 0 (the render + loss are consistent). 13// Q16 fixed-point only (no float), sovereign syscalls only. license_tier: ORIGINAL expect_exit: 0 14import "nx_syscalls.nx" 15 16const Q: i64 = 65536 // 1.0 in Q16 17const HALF: i64 = 32768 // 0.5 18const NPX: i64 = 16 // canvas pixels 19const INVS: i64 = 16384 // 1/s with softness s=4 px (Q16/4) 20const PSTAR: i64 = 524288 // target edge position = 8.0 px 21const P0: i64 = 196608 // initial guess = 3.0 px 22const LR: i64 = 4096 // learning rate = 0.0625 (Q16) 23const NSTEP: i64 = 120 24const EPS: i64 = 16384 // finite-diff step = 0.25 px 25const PCHK: i64 = 393216 // sign-check point = 6.0 px 26const TOL: i64 = 32768 // convergence tolerance = 0.5 px 27 28func dp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 29func dpn(v: i64) -> i64 { 30 let bb: *u8 = sys_mmap(28); var m: i64 = v 31 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 32 let t: *u8 = sys_mmap(28); var k: i64 = 0 33 if m == 0 { t[0] = 48 as u8; k = 1 } 34 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 35 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 36 sys_write(1, bb, k); return 0 37} 38func dr_qm(a: i64, b: i64) -> i64 { return (a * b) >> 16 } 39func dr_clamp(u: i64) -> i64 { if u < 0 { return 0 } if u > Q { return Q } return u } 40// soft-edge coverage of pixel i for edge position p (Q16): cov = clamp((i-p)/s + 0.5, 0, 1) 41func dr_cov(i: i64, p: i64) -> i64 { let di: i64 = i * Q - p; let u: i64 = dr_qm(di, INVS) + HALF; return dr_clamp(u) } 42// is pixel i in the differentiable transition band (0<u<1) for p? (where dcov/dp != 0) 43func dr_active(i: i64, p: i64) -> i64 { let di: i64 = i * Q - p; let u: i64 = dr_qm(di, INVS) + HALF; if u > 0 { if u < Q { return 1 } } return 0 } 44func dr_render(p: i64, out: *i64) -> i64 { var i: i64 = 0; while i < NPX { out[i] = dr_cov(i, p); i = i + 1 } return 0 } 45func dr_loss(p: i64, tgt: *i64) -> i64 { var s: i64 = 0; var i: i64 = 0; while i < NPX { let d: i64 = dr_cov(i, p) - tgt[i]; s = s + dr_qm(d, d); i = i + 1 } return s } 46// analytic dLoss/dp = sum_i 2*(cov_i - tgt_i)*dcov_i/dp ; dcov/dp = -1/s = -INVS (Q16) on the active band, else 0 47func dr_grad(p: i64, tgt: *i64) -> i64 { 48 var g: i64 = 0; var i: i64 = 0 49 while i < NPX { 50 let cov: i64 = dr_cov(i, p) 51 var dcov: i64 = 0 52 if dr_active(i, p) == 1 { dcov = 0 - INVS } 53 let d: i64 = cov - tgt[i] 54 g = g + 2 * dr_qm(d, dcov) 55 i = i + 1 56 } 57 return g 58} 59 60func main() -> i64 { 61 dp("=== nx_ng_diffrender: CAP-DIFF-RENDER -- gradients through a 1D soft-raster (Q16, no float) ===\n" as *u8) 62 let tgt: *i64 = sys_mmap(8 * NPX) 63 dr_render(PSTAR, tgt) 64 let loss0: i64 = dr_loss(P0, tgt) 65 dp(" target p*=" as *u8); dpn(PSTAR >> 16); dp(".0px init p0=" as *u8); dpn(P0 >> 16); dp(".0px loss0=" as *u8); dpn(loss0); dp("\n" as *u8) 66 67 // T1: gradient DESCENT on the scene param 68 var p: i64 = P0 69 var step: i64 = 0 70 while step < NSTEP { 71 let g: i64 = dr_grad(p, tgt) 72 p = p - dr_qm(LR, g) 73 step = step + 1 74 if step % 30 == 0 { dp(" step " as *u8); dpn(step); dp(" loss=" as *u8); dpn(dr_loss(p, tgt)); dp(" p=" as *u8); dpn(p >> 16); dp("(.q" as *u8); dpn(p); dp(")\n" as *u8) } 75 } 76 let lossN: i64 = dr_loss(p, tgt) 77 var dpos: i64 = p - PSTAR 78 if dpos < 0 { dpos = 0 - dpos } 79 dp(" T1 DESCENT: final loss=" as *u8); dpn(lossN); dp(" p=" as *u8); dpn(p); dp(" |p-p*|=" as *u8); dpn(dpos); dp("\n" as *u8) 80 81 // T2: NEG-CONTROL -- ASCEND the gradient (wrong sign) -> must diverge 82 var pa: i64 = P0 83 var s2: i64 = 0 84 while s2 < NSTEP { let g2: i64 = dr_grad(pa, tgt); pa = pa + dr_qm(LR, g2); s2 = s2 + 1 } 85 let lossA: i64 = dr_loss(pa, tgt) 86 dp(" T2 ASCENT(neg-control): final loss=" as *u8); dpn(lossA); dp(" (must be > loss0)\n" as *u8) 87 88 // T3: finite-difference SIGN check at p=PCHK 89 let ga: i64 = dr_grad(PCHK, tgt) 90 let lp: i64 = dr_loss(PCHK + EPS, tgt) 91 let lm: i64 = dr_loss(PCHK - EPS, tgt) 92 let fd: i64 = lp - lm 93 var sign_ok: i64 = 0 94 if ga > 0 { if fd > 0 { sign_ok = 1 } } 95 if ga < 0 { if fd < 0 { sign_ok = 1 } } 96 if ga == 0 { if fd == 0 { sign_ok = 1 } } 97 dp(" T3 GRADCHECK(sign): analytic=" as *u8); dpn(ga); dp(" finite-diff=" as *u8); dpn(fd); dp(" match=" as *u8); dpn(sign_ok); dp("\n" as *u8) 98 99 // T4: zero at optimum 100 let loss_star: i64 = dr_loss(PSTAR, tgt) 101 dp(" T4 loss(p*)=" as *u8); dpn(loss_star); dp(" (must be 0)\n" as *u8) 102 103 var converged: i64 = 0 104 if lossN * 50 < loss0 { if dpos < TOL { converged = 1 } } 105 var ok: i64 = 1 106 if converged != 1 { ok = 0 } 107 if lossA <= loss0 { ok = 0 } 108 if sign_ok != 1 { ok = 0 } 109 if loss_star != 0 { ok = 0 } 110 dp(" converged=" as *u8); dpn(converged); dp("\n verdict=" as *u8) 111 if ok == 1 { dp("GREEN (descent converges, ascent diverges, grad sign matches finite-diff, zero at optimum = real differentiable render)\n" as *u8); sys_exit(0); return 0 } 112 dp("RED\n" as *u8) 113 sys_exit(1); return 1 114}