code wiki / _hdl_build / nx_quad_gaits_gate.nx

nx_quad_gaits_gate.nx source

↩ module page · 169 lines · 9658 B

1// nx_quad_gaits_gate.nx -- DIVERSIFY the animal motion: walk/trot/gallop as data on the quadruped rig, plus a 2// HORNED creature composition (quadruped + swap slots). Proves: 3// T1 the 3 gaits are DISTINCT (FR-foot phase differs: walk=diagonal-antiphase, gallop=rotary-near-phase) 4// T2 each gait produces MOTION (rendered frame checksums differ) 5// T3 horns compose (quad_add_horns adds parts on the head) 6// T4 valid APNGs written (gallop + a horned trot) 7// Emits knowledge/synth_gallop.png + knowledge/synth_horncreature.png. license_tier: ORIGINAL expect_exit: 0 8import "nx_syscalls.nx" 9import "nx_quadruped.nx" 10import "nx_apng.nx" 11import "nx_gate_verdict.nx" 12 13// MIGRATED off a hand-rolled verdict 2026-08-25. It printed "QUAD-GAITS-GATE 4/4 verdict=GREEN" itself, so 14// /api/promote refused it D001 and it had NEVER BEEN PROMOTED -- 128 KB of compiled proof that nothing could 15// run and nothing could read. Per-tooth gv_check also makes declared == executed by construction. 16// ⚠ QG_DISTINCT_MIN is INHERITED, NOT DERIVED: the original compared the walk-vs-gallop FR-foot phase gap 17// against a bare 150 with no stated basis. It is named here so it is visible and greppable rather than 18// buried in an expression, and it is flagged as owed: the honest bar is a measured separation from the rig 19// geometry, not a number someone liked. Naming it is not deriving it and this comment does not pretend it is. 20const QG_DISTINCT_MIN: i64 = 150 21// Fixed-point scales. These are not tunables at all -- they are the units the surrounding arithmetic 22// is written in, and changing either silently rescales geometry rather than adjusting a behaviour. 23const QG_TRIG_Q12: i64 = 4096 // MUST match it_sin4096/it_cos4096's output scale 24const QG_Q10_ONE: i64 = 1024 // q10 one, the scale the camera distance is expressed in 25const QG_CAM_UNITS: i64 = 5 // camera standoff, in world units 26// A CHECKSUM SEED IS ARBITRARY BY DESIGN, AND THAT IS EXACTLY WHY IT NEEDS A PURPOSE NAME. Any seed 27// produces a valid checksum, so there is no "correct" value to look up and no citation to chase -- the 28// only thing a reader needs to know is what it is FOR. Naming it for its digits would hide that the 29// arbitrariness here is legitimate, which is the opposite of the material-constant case where naming 30// for the digits hid that the arbitrariness was a defect. 31const QG_CKSUM_SEED: i64 = 1469598103 32 33func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 34func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 35func cks(fb: *i64, n: i64) -> i64 { var s: i64=QG_CKSUM_SEED; var i: i64=0; while i<n{s=(s*31+(fb[i]&0xffffff))&0x0fffffffffffffff;i=i+1} return s } 36func find4(buf: *u8, n: i64, a: i64, b: i64, c: i64, d: i64) -> i64 { var i: i64=0; while i+4<=n{ if (buf[i]&0xff)==a{ if (buf[i+1]&0xff)==b{ if (buf[i+2]&0xff)==c{ if (buf[i+3]&0xff)==d{return i}}}} i=i+1} return 0-1 } 37 38const RW: i64 = 144 39const RH: i64 = 96 40const RFOCAL: i64 = 164 41func gr_render(base: i64, fb: *i64, yaw: i64) -> i64 { 42 let R: i64 = QG_CAM_UNITS * QG_Q10_ONE 43 let cy4: i64 = it_cos4096(yaw); let sy4: i64 = it_sin4096(yaw) 44 let rox: i64 = 0 - sy4 * R / QG_TRIG_Q12; let roz: i64 = 0 - cy4 * R / QG_TRIG_Q12 45 var y: i64 = 0 46 while y < RH { 47 let mc1: i64 = 24 + y*30/RH; let mc2: i64 = 26 + y*28/RH; let mc3: i64 = 40 + y*26/RH 48 let misscol: i64 = mc1 + mc2*256 + mc3*65536 49 var x: i64 = 0 50 while x < RW { 51 let ndcx: i64 = (2*x+1-RW)*1024/(2*RFOCAL); let ndcy: i64 = (RH-(2*y+1))*1024/(2*RFOCAL) 52 let rl: i64 = sdf_isqrt(ndcx*ndcx + ndcy*ndcy + 1024*1024) 53 let vdx: i64 = ndcx*1024/rl; let rdy: i64 = ndcy*1024/rl; let vdz: i64 = 1024*1024/rl 54 let rdx: i64 = (cy4*vdx + sy4*vdz)/QG_TRIG_Q12; let rdz: i64 = (0-sy4*vdx + cy4*vdz)/QG_TRIG_Q12 55 let col: i64 = sdf_shade_ray(base, rox, 0, roz, rdx, rdy, rdz, 176, 158, 138, misscol) 56 fb[y*RW+x] = col 57 x = x + 1 58 } 59 y = y + 1 60 } 61 return 0 62} 63// Pose to a gait's peak, then ask the RIG for the swing. quad_leg_swing lives in nx_quadruped because two 64// gates needed it; this gate no longer carries its own copy of what a leg swing is. 65func leg_sig(sk: i64, gait: i64, foot: i64, hip: i64) -> i64 { 66 quad_gait_pose_g(sk, 1024, gait); sk_update(sk) 67 return quad_leg_swing(sk, foot, hip) 68} 69// FR foot swing signature -- delegates, so there is one signature function and not two. 70func fr_sig(sk: i64, gait: i64) -> i64 { return leg_sig(sk, gait, QR_FRFOOT, QR_FRHIP) } 71 72func main() -> i64 { 73 let ctr: *i64 = gv_ctr() 74 gv_head("nx_quad_gaits_gate -- walk/trot/gallop as data + horned creature" as *u8) 75 let base: i64 = sys_mmap(sdf_bytes()) as i64 76 let fb: *i64 = sys_mmap(RW*RH*8) as *i64 77 let sk: i64 = sys_mmap(sk_bytes()) as i64 78 quad_build(sk) 79 80 // T1 gaits distinct via FR-foot phase 81 let gw: i64 = fr_sig(sk, 0) 82 let gt: i64 = fr_sig(sk, 1) 83 let gg: i64 = fr_sig(sk, 2) 84 hw(" FR-foot swing @peak: walk="); pn(gw); hw(" trot="); pn(gt); hw(" gallop="); pn(gg); hw("\n" as *u8) 85 var d_wg: i64 = gw - gg; if d_wg < 0 { d_wg = 0 - d_wg } 86 var t1: i64 = 0 87 if d_wg > QG_DISTINCT_MIN { t1 = 1 } 88 // NAME NARROWED 2026-08-25. This tooth was called "the three gaits are DISTINCT" and tests exactly 89 // ONE PAIR. Measured on its first run ever: walk=-146 trot=-156 gallop=400 -- walk and trot are TEN 90 // APART on this signature, so the unqualified name was asserting something the tooth never checked. 91 gv_check("T1 WALK and GALLOP separate on front-right foot swing (this pair only -- see T5)" as *u8, t1, ctr) 92 93 // T5 THE PAIR T1 CANNOT SEE. A single foot's peak swing cannot tell a walk from a trot, because the 94 // difference between them is not how far one leg reaches -- it is WHICH LEGS MOVE TOGETHER. A trot is 95 // 2-beat with DIAGONAL pairs in phase; a walk is a 4-beat lateral sequence where they are not. So the 96 // discriminator is the sign relationship between the front-right and its diagonal, the hind-left. 97 // ASKS THE RIG, does not re-decide. quad_diag_phase is in nx_quadruped precisely because 98 // nx_wolf_walk_gate T3 already tested this same diagonal relationship -- two gates, one question. 99 quad_gait_pose_g(sk, 1024, 1); sk_update(sk) 100 let dp_trot: i64 = quad_diag_phase(sk) 101 quad_gait_pose_g(sk, 1024, 0); sk_update(sk) 102 let dp_walk: i64 = quad_diag_phase(sk) 103 hw(" diagonal FR/HL coupling @peak: trot="); pn(dp_trot); hw(" walk="); pn(dp_walk) 104 hw(" (+1 together, -1 opposed, 0 not swinging)\n" as *u8) 105 var t5: i64 = 0 106 if dp_trot == 1 { if dp_walk != 1 { t5 = 1 } } 107 gv_check("T5 WALK and TROT differ in DIAGONAL PHASE (trot moves FR+HL together, walk does not)" as *u8, t5, ctr) 108 109 // T3 horns compose 110 quad_gait_pose_g(sk, 0, 0); sk_update(sk) 111 let nbody: i64 = quadpose_fill(base, sk) 112 let nhorn: i64 = quad_add_horns(base, nbody, sk) 113 hw(" parts: body="); pn(nbody); hw(" with-horns="); pn(nhorn); hw("\n" as *u8) 114 var t3: i64 = 0 115 if nhorn == nbody + 2 { t3 = 1 } 116 gv_check("T3 horns COMPOSE onto the quadruped (two parts added on the head)" as *u8, t3, ctr) 117 118 // T2+T4 render gallop -> APNG, motion present 119 let apbuf: *u8 = sys_mmap(12*1024*1024) 120 let seq: *i64 = sys_mmap(8) as *i64 121 let nf: i64 = 8 122 var sum0: i64 = 0; var summid: i64 = 0 123 seq[0] = 0 124 var o: i64 = apng_open(apbuf, RW, RH, nf) 125 var f: i64 = 0 126 while f < nf { 127 quad_gait_pose_g(sk, f*QG_TRIG_Q12/nf, 2); sk_update(sk) 128 quadpose_fill(base, sk) 129 gr_render(base, fb, 220) 130 if f == 0 { sum0 = cks(fb, RW*RH) } 131 if f == nf/2 { summid = cks(fb, RW*RH) } 132 var first: i64 = 0; if f == 0 { first = 1 } 133 o = apng_frame(apbuf, o, seq, fb, RW, RH, 6, first) 134 f = f + 1 135 } 136 o = apng_close(apbuf, o) 137 let fd: i64 = sys_openat_wr("knowledge/synth_gallop.png" as *u8, 0x1a4) 138 if fd >= 0 { sys_write(fd, apbuf, o); sys_close(fd) } 139 hw(" wrote knowledge/synth_gallop.png bytes="); pn(o); hw("\n" as *u8) 140 var t2: i64 = 0 141 if sum0 != summid { t2 = 1 } 142 gv_check("T2 the gallop produces MOTION (rendered frame checksums differ across the cycle)" as *u8, t2, ctr) 143 var t4: i64 = 1 144 if find4(apbuf, o, 97, 99, 84, 76) < 0 { t4 = 0 } 145 146 // horned trot render 147 seq[0] = 0 148 var o2: i64 = apng_open(apbuf, RW, RH, nf) 149 f = 0 150 while f < nf { 151 quad_gait_pose_g(sk, f*QG_TRIG_Q12/nf, 1); sk_update(sk) 152 let nb: i64 = quadpose_fill(base, sk) 153 quad_add_horns(base, nb, sk) 154 gr_render(base, fb, 220) 155 var first2: i64 = 0; if f == 0 { first2 = 1 } 156 o2 = apng_frame(apbuf, o2, seq, fb, RW, RH, 6, first2) 157 f = f + 1 158 } 159 o2 = apng_close(apbuf, o2) 160 let fd2: i64 = sys_openat_wr("knowledge/synth_horncreature.png" as *u8, 0x1a4) 161 if fd2 >= 0 { sys_write(fd2, apbuf, o2); sys_close(fd2) } 162 hw(" wrote knowledge/synth_horncreature.png bytes="); pn(o2); hw("\n" as *u8) 163 if find4(apbuf, o2, 97, 99, 84, 76) < 0 { t4 = 0 } 164 gv_check("T4 both emitted APNGs are VALID (the acTL animation chunk is present in each)" as *u8, t4, ctr) 165 166 return gv_verdict("QUAD-GAITS" as *u8, ctr, 167 "walk/trot/gallop as data on one quadruped rig, plus a horned composition -- sovereign, and readable from outside for the first time" as *u8) 168} 169