nx_twinfit.nx source
↩ module page · 480 lines · 29863 B
1// nx_twinfit.nx -- aesthetictwin AT34 (2026-09-17): THE TWIN LOOP'S FIRST RUNG, the reachable axis envelope. The photo ruler
2// (nx_photomark_lib) reads a reference still and the estate's own face render through one instrument; this organ asks the
3// question the fit loop stands on: over the morph basis the generator exposes today (nx_faceanat canon face + the seven
4// persongen morphs), which of the card's scale-free axes can a render REACH at all? Each gene is swept to its declared floor,
5// middle and ceiling with the others at middle (nx_twinfit_lib does the build, render and in-process measurement); per axis
6// the min and max over the sweep is the envelope, and a target read from a file (rows axis|<name>|<value>|<err>) is REACHABLE
7// when its error band meets the envelope, else UNREACHABLE -- which names the morph the generator is missing (the build
8// order for AT29), never a fit that quietly stops short.
9// nx_twinfit envelope [target-file] [skin_r skin_g skin_b] -> one row per render, one row per axis, a summary whose partition sums
10// nx_twinfit axes <w> <l> <j> <e> <p> <n> <c> [skin_r skin_g skin_b] -> one render at those seven percents, its axes
11// nx_twinfit truthref [seed_hi] [seed_lo] [sweep 1|0] -> AT39: the ruler judged per canthus against the render's own landmark truth (the 21-cell gene sweep, then persongen seeds 1..n), signed bias per landmark, a partition that sums; AT44: a TRUTHLIP line per render judging the ruler's five mouth landmarks against the lip unit's stated truth, with the mouth's own partition
12// nx_twinfit fit <target-file> -> AT40: solve the seven morphs and six eye genes against a card's axes from the STATED landmarks (no render), name genes at a range limit, confirm on the surface
13// nx_twinfit truth <w> <l> <j> <e> <p> <n> <c> -> AT39: no render; the built face is asked where its canthi are (reasons by name, model units, projected deci-pixels, asymmetry)
14// The skin tone defaults to persongen's fair-medium family; passing one moves the render's albedo while the geometry stays,
15// which is how the ruler's tone sensitivity on renders is measured rather than guessed.
16// exit: 0 every render measured | 1 some render UNMEASURED (envelope partial, said so) | 2 usage | 3 cascades not loaded
17// license_tier: ORIGINAL No hw writes (Rule 26).
18import "nx_syscalls.nx"
19import "nx_twinfit_lib.nx"
20
21const TWC_EXIT_USAGE: i64 = 2
22const TWC_EXIT_PARTIAL: i64 = 1
23const TWC_EXIT_NOCASCADE: i64 = 3
24const TWC_ARGC_ENVELOPE: i64 = 2
25const TWC_ARGC_ENVELOPE_TARGET: i64 = 3
26const TWC_ARGC_ENVELOPE_SKIN: i64 = 6
27const TWC_ARGC_AXES: i64 = 9
28const TWC_ARGC_AXES_SKIN: i64 = 12
29const TWC_ARGC_TRUTHSEED: i64 = 3
30const TWC_ARGC_FIT: i64 = 3
31
32func twc_usage() -> i64 {
33 ri_puts("usage: nx_twinfit envelope [target-file] [skin_r skin_g skin_b] | axes <width> <length> <jaw> <eyes> <lips> <nose> <cheek> [skin_r skin_g skin_b] | truthref [seeds] | truth <width> <length> <jaw> <eyes> <lips> <nose> <cheek>\n" as *u8)
34 return TWC_EXIT_USAGE
35}
36func twc_print_skin(skin: *i64) -> i64 {
37 tw_kv("TWINFIT skin=" as *u8, skin[TW_SKIN_SLOT_R]); tw_kv("," as *u8, skin[TW_SKIN_SLOT_G]); tw_kv("," as *u8, skin[TW_SKIN_SLOT_B]); ri_puts("\n" as *u8)
38 return 0
39}
40// ---- AT39: the ruler judged against the render's own landmark truth ----------------------------------------------------------
41const TWC_TR_SEEDS_DEFAULT: i64 = 8
42const TWC_ARGC_TRUTHREF_SEEDS: i64 = 3
43const TWC_ARGC_TRUTHREF_LO: i64 = 4
44const TWC_ARGC_TRUTHREF_SWEEP: i64 = 5
45const TWC_ACC_FIELDS: i64 = 2 // per landmark: the summed signed dx and dy
46// one judged row's tail: truth state, the judge's numbers, both tilt pairs, the verdict; updates the tallies in tal
47const TWC_TAL_FOUND: i64 = 0
48const TWC_TAL_OFF: i64 = 1
49const TWC_TAL_UNMEASURED: i64 = 2
50const TWC_TAL_NOTRUTH: i64 = 3
51const TWC_TAL_NMAX_SUM: i64 = 4
52const TWC_TAL_TILT_ERR_SUM: i64 = 5
53// AT44: the mouth's own partition beside the canthi's, and each canthus's summed NME so the summary can name the landmark that
54// keeps a render from passing
55const TWC_TAL_LIP_FOUND: i64 = 8
56const TWC_TAL_LIP_OFF: i64 = 9
57const TWC_TAL_LIP_UNMEASURED: i64 = 10
58const TWC_TAL_LIP_NOTRUTH: i64 = 11
59const TWC_TAL_LIP_NMEAN_SUM: i64 = 12
60const TWC_TAL_LIP_RATIO_ERR_SUM: i64 = 13
61const TWC_TAL_LIP_NMAX_SUM: i64 = 14
62const TWC_TAL_NME_LM: i64 = 16 // + k for canthus k
63// the mouth anchored on the render's own stated canthi (pm_mouth_anchored): the mouth ruler judged on every render, eye pair or not
64const TWC_TAL_ALIP_FOUND: i64 = 20
65const TWC_TAL_ALIP_OFF: i64 = 21
66const TWC_TAL_ALIP_UNMEASURED: i64 = 22
67const TWC_TAL_ALIP_NMEAN_SUM: i64 = 23
68const TWC_TAL_ALIP_RATIO_ERR_SUM: i64 = 24
69const TWC_TAL_N: i64 = 28
70const TWC_LACC_FIELDS: i64 = 3 // per lip landmark: the summed signed dx, dy and the summed NME
71func twc_truth_row(base: i64, rc: i64, res: *i64, t: *i64, j: *i64, acc: *i64, tal: *i64) -> i64 {
72 let have: i64 = tw_truth_landmarks(base, TW_YAW_FRONTAL, t)
73 tw_kv(" rc=" as *u8, rc)
74 if have == 0 {
75 tw_kv(" truth=NONE reason_R=" as *u8, t[TW_T_REASON_R]); tw_kv(" reason_L=" as *u8, t[TW_T_REASON_L])
76 ri_puts(" verdict=NO-TRUTH\n" as *u8)
77 tal[TWC_TAL_NOTRUTH] = tal[TWC_TAL_NOTRUTH] + 1
78 return 0
79 }
80 tw_kv(" truth=OK exo_deci=" as *u8, t[TW_T_EXO]); tw_kv(" tilt_truth=" as *u8, t[TW_T_TILT_R]); tw_kv("," as *u8, t[TW_T_TILT_L])
81 if rc != PM_OK {
82 tw_kv(" eyes=" as *u8, res[PM_R_EYES]); tw_kv(" pair_fail=" as *u8, res[PM_R_PAIR_FAIL])
83 ri_puts(" verdict=UNMEASURED\n" as *u8)
84 tal[TWC_TAL_UNMEASURED] = tal[TWC_TAL_UNMEASURED] + 1
85 return 0
86 }
87 let nmax: i64 = tw_judge(res, t, j)
88 tw_kv(" tilt_ruler=" as *u8, res[PM_R_TILT_R_RAW]); tw_kv("," as *u8, res[PM_R_TILT_L_RAW])
89 tw_kv(" nmax=" as *u8, nmax); tw_kv(" nmean=" as *u8, j[TW_J_NMEAN])
90 var k: i64 = 0
91 while k < TW_LANDMARKS {
92 ri_puts(" " as *u8); ri_puts(tw_landmark_name(k))
93 tw_kv("=" as *u8, j[k * TW_J_FIELDS + TW_J_DX]); tw_kv("," as *u8, j[k * TW_J_FIELDS + TW_J_DY])
94 acc[k * TWC_ACC_FIELDS] = acc[k * TWC_ACC_FIELDS] + j[k * TW_J_FIELDS + TW_J_DX]
95 acc[k * TWC_ACC_FIELDS + 1] = acc[k * TWC_ACC_FIELDS + 1] + j[k * TW_J_FIELDS + TW_J_DY]
96 k = k + 1
97 }
98 tal[TWC_TAL_NMAX_SUM] = tal[TWC_TAL_NMAX_SUM] + nmax
99 tal[TWC_TAL_TILT_ERR_SUM] = tal[TWC_TAL_TILT_ERR_SUM] + pm_abs(res[PM_R_TILT_R_RAW] - t[TW_T_TILT_R]) + pm_abs(res[PM_R_TILT_L_RAW] - t[TW_T_TILT_L])
100 k = 0
101 while k < TW_LANDMARKS { tal[TWC_TAL_NME_LM + k] = tal[TWC_TAL_NME_LM + k] + j[k * TW_J_FIELDS + TW_J_NME]; k = k + 1 }
102 if nmax <= PM_NME_FOUND_PERMIL { ri_puts(" verdict=FOUND\n" as *u8); tal[TWC_TAL_FOUND] = tal[TWC_TAL_FOUND] + 1; return 1 }
103 ri_puts(" verdict=PLACED-OFF\n" as *u8)
104 tal[TWC_TAL_OFF] = tal[TWC_TAL_OFF] + 1
105 return 1
106}
107// AT44: the same render's MOUTH against the lip unit's stated truth, one TRUTHLIP line per render after its canthi line. The ruler
108// looks for a mouth only once it has placed both eyes, so a render whose eyes were refused is UNMEASURED here too, by name
109// the mouth anchored on the render's own stated canthi, judged against the lip truth: one TRUTHLIP-ANCHORED line per render
110func twc_lip_anchored(base: i64, rgb: *u8, lt: *i64, lj: *i64, tal: *i64) -> i64 {
111 ri_puts("TRUTHLIP-ANCHORED" as *u8)
112 let st: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
113 let ares: *i64 = sys_mmap(PM_R_N * TW_I64) as *i64
114 let c8: *i64 = sys_mmap(PM_CANTHI_XY * TW_I64) as *i64
115 var ok: i64 = tw_stated_landmarks(base, TW_YAW_FRONTAL, st)
116 if lt[TW_LT_OK] != 1 { ok = 0 }
117 if ok == 0 { ri_puts(" anch_lip_verdict=NO-TRUTH\n" as *u8); tal[TWC_TAL_ALIP_UNMEASURED] = tal[TWC_TAL_ALIP_UNMEASURED] + 1; return 0 }
118 var k: i64 = 0
119 while k < PM_CANTHI_XY { c8[k] = (st[TW_T_RLAT_X + k] + TW_PIX_CENTRE_DECI) / TW_DECI; k = k + 1 }
120 pm_mouth_anchored(rgb, ww(), hh(), c8, ares)
121 if ares[PM_R_MOUTH] != 1 {
122 ri_puts(" anch_mouth_why=" as *u8); ri_puts(pm_mouth_why_name(ares[PM_R_MOUTH_WHY])); ri_puts(" anch_lip_verdict=UNMEASURED\n" as *u8)
123 tal[TWC_TAL_ALIP_UNMEASURED] = tal[TWC_TAL_ALIP_UNMEASURED] + 1
124 return 0
125 }
126 let nmax: i64 = tw_lip_judge(ares, lt, lj)
127 tw_kv(" anch_lip_ruler=" as *u8, lj[TW_LJ_RATIO_RULER]); tw_kv(" lip_pixel_truth=" as *u8, lj[TW_LJ_RATIO_TRUTH]); tw_kv(" anch_lnmax=" as *u8, nmax); tw_kv(" anch_lnmean=" as *u8, lj[TW_LJ_NMEAN])
128 tal[TWC_TAL_ALIP_NMEAN_SUM] = tal[TWC_TAL_ALIP_NMEAN_SUM] + lj[TW_LJ_NMEAN]
129 tal[TWC_TAL_ALIP_RATIO_ERR_SUM] = tal[TWC_TAL_ALIP_RATIO_ERR_SUM] + pm_abs(lj[TW_LJ_RATIO_RULER] - lj[TW_LJ_RATIO_TRUTH])
130 if nmax <= PM_NME_FOUND_PERMIL { ri_puts(" anch_lip_verdict=FOUND\n" as *u8); tal[TWC_TAL_ALIP_FOUND] = tal[TWC_TAL_ALIP_FOUND] + 1; return 1 }
131 ri_puts(" anch_lip_verdict=PLACED-OFF\n" as *u8)
132 tal[TWC_TAL_ALIP_OFF] = tal[TWC_TAL_ALIP_OFF] + 1
133 return 1
134}
135func twc_lip_row(base: i64, rc: i64, res: *i64, lt: *i64, lj: *i64, lacc: *i64, tal: *i64) -> i64 {
136 ri_puts("TRUTHLIP" as *u8)
137 let have: i64 = tw_lip_truth(base, TW_YAW_FRONTAL, lt)
138 tw_print_lip_truth(lt)
139 if have == 0 { ri_puts(" lip_verdict=NO-TRUTH\n" as *u8); tal[TWC_TAL_LIP_NOTRUTH] = tal[TWC_TAL_LIP_NOTRUTH] + 1; return 0 }
140 var seen: i64 = 1
141 if rc != PM_OK { seen = 0 }
142 if res[PM_R_MOUTH] != 1 { seen = 0 }
143 tw_kv(" ruler_mouth=" as *u8, res[PM_R_MOUTH])
144 if seen == 0 {
145 // publish what the ruler found before its refusal: the reason by name and the landmarks it had placed
146 if rc == PM_OK {
147 ri_puts(" mouth_why=" as *u8); ri_puts(pm_mouth_why_name(res[PM_R_MOUTH_WHY]))
148 var q: i64 = 0
149 while q < TW_LIP_LANDMARKS { ri_puts(" r_" as *u8); ri_puts(tw_lip_landmark_name(q)); tw_kv("=" as *u8, res[PM_R_LS_X + q * TW_XY]); tw_kv("," as *u8, res[PM_R_LS_X + q * TW_XY + 1]); q = q + 1 }
150 }
151 ri_puts(" lip_verdict=UNMEASURED\n" as *u8); tal[TWC_TAL_LIP_UNMEASURED] = tal[TWC_TAL_LIP_UNMEASURED] + 1; return 0
152 }
153 let nmax: i64 = tw_lip_judge(res, lt, lj)
154 tw_kv(" lip_ruler=" as *u8, lj[TW_LJ_RATIO_RULER]); tw_kv(" lip_pixel_truth=" as *u8, lj[TW_LJ_RATIO_TRUTH])
155 tw_kv(" lnmax=" as *u8, nmax); tw_kv(" lnmean=" as *u8, lj[TW_LJ_NMEAN])
156 var k: i64 = 0
157 while k < TW_LIP_LANDMARKS {
158 ri_puts(" " as *u8); ri_puts(tw_lip_landmark_name(k))
159 tw_kv("=" as *u8, lj[k * TW_J_FIELDS + TW_J_DX]); tw_kv("," as *u8, lj[k * TW_J_FIELDS + TW_J_DY]); tw_kv(":" as *u8, lj[k * TW_J_FIELDS + TW_J_NME])
160 lacc[k * TWC_LACC_FIELDS] = lacc[k * TWC_LACC_FIELDS] + lj[k * TW_J_FIELDS + TW_J_DX]
161 lacc[k * TWC_LACC_FIELDS + 1] = lacc[k * TWC_LACC_FIELDS + 1] + lj[k * TW_J_FIELDS + TW_J_DY]
162 lacc[k * TWC_LACC_FIELDS + 2] = lacc[k * TWC_LACC_FIELDS + 2] + lj[k * TW_J_FIELDS + TW_J_NME]
163 k = k + 1
164 }
165 tal[TWC_TAL_LIP_NMAX_SUM] = tal[TWC_TAL_LIP_NMAX_SUM] + nmax
166 tal[TWC_TAL_LIP_NMEAN_SUM] = tal[TWC_TAL_LIP_NMEAN_SUM] + lj[TW_LJ_NMEAN]
167 tal[TWC_TAL_LIP_RATIO_ERR_SUM] = tal[TWC_TAL_LIP_RATIO_ERR_SUM] + pm_abs(lj[TW_LJ_RATIO_RULER] - lj[TW_LJ_RATIO_TRUTH])
168 if nmax <= PM_NME_FOUND_PERMIL { ri_puts(" lip_verdict=FOUND\n" as *u8); tal[TWC_TAL_LIP_FOUND] = tal[TWC_TAL_LIP_FOUND] + 1; return 1 }
169 ri_puts(" lip_verdict=PLACED-OFF\n" as *u8)
170 tal[TWC_TAL_LIP_OFF] = tal[TWC_TAL_LIP_OFF] + 1
171 return 1
172}
173// the two populations the generator can emit today: the 21-cell gene sweep at the default tone, then persongen seeds 1..n,
174// each with its own identity and tone. Every row is judged per landmark; the summary carries the SIGNED bias per canthus
175func twc_truthref(seed_lo: i64, seeds: i64, sweep: i64, base: i64, rgb: *u8, res: *i64, g: *i64, skin: *i64, face_c: *HaarCascade, eye_c: *HaarCascade) -> i64 {
176 let t: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
177 let j: *i64 = sys_mmap(TW_J_N * TW_I64) as *i64
178 let acc: *i64 = sys_mmap(TW_LANDMARKS * TWC_ACC_FIELDS * TW_I64) as *i64
179 let tal: *i64 = sys_mmap(TWC_TAL_N * TW_I64) as *i64
180 let idv: *i64 = sys_mmap(TW_SLOTS * TW_I64) as *i64
181 let lt: *i64 = sys_mmap(TW_LT_N * TW_I64) as *i64
182 let lj: *i64 = sys_mmap(TW_LJ_N * TW_I64) as *i64
183 let lacc: *i64 = sys_mmap(TW_LIP_LANDMARKS * TWC_LACC_FIELDS * TW_I64) as *i64
184 var renders: i64 = 0
185 var k: i64 = 0
186 while k < TW_GENES * sweep { // sweep is 1 or 0: the 21-cell gene sweep runs, or only the seeds do
187 var l: i64 = 0
188 while l < TW_LEVELS {
189 var q: i64 = 0
190 while q < TW_GENES { g[q] = tw_mid(q); q = q + 1 }
191 g[k] = tw_level_pct(k, l)
192 let rc: i64 = tw_measure(base, g, skin, rgb, res, face_c, eye_c)
193 renders = renders + 1
194 ri_puts("TRUTHREF pop=gene gene=" as *u8); ri_puts(tw_gene_name(k)); ri_puts(" level=" as *u8); ri_puts(tw_level_name(l)); tw_kv(" pct=" as *u8, g[k])
195 twc_truth_row(base, rc, res, t, j, acc, tal)
196 twc_lip_row(base, rc, res, lt, lj, lacc, tal)
197 twc_lip_anchored(base, rgb, lt, lj, tal)
198 l = l + 1
199 }
200 k = k + 1
201 }
202 var s: i64 = seed_lo
203 while s <= seeds {
204 let rc2: i64 = tw_measure_seed(base, s, skin, idv, rgb, res, face_c, eye_c)
205 renders = renders + 1
206 tw_kv("TRUTHREF pop=seed seed=" as *u8, s); tw_kv(" skin=" as *u8, skin[TW_SKIN_SLOT_R]); tw_kv("," as *u8, skin[TW_SKIN_SLOT_G]); tw_kv("," as *u8, skin[TW_SKIN_SLOT_B])
207 twc_truth_row(base, rc2, res, t, j, acc, tal)
208 twc_lip_row(base, rc2, res, lt, lj, lacc, tal)
209 twc_lip_anchored(base, rgb, lt, lj, tal)
210 s = s + 1
211 }
212 let judged: i64 = tal[TWC_TAL_FOUND] + tal[TWC_TAL_OFF]
213 tw_kv("TRUTHREF-SUMMARY renders=" as *u8, renders); tw_kv(" found=" as *u8, tal[TWC_TAL_FOUND]); tw_kv(" placed_off=" as *u8, tal[TWC_TAL_OFF])
214 tw_kv(" unmeasured=" as *u8, tal[TWC_TAL_UNMEASURED]); tw_kv(" no_truth=" as *u8, tal[TWC_TAL_NOTRUTH])
215 tw_kv(" partition_sum=" as *u8, judged + tal[TWC_TAL_UNMEASURED] + tal[TWC_TAL_NOTRUTH]); tw_kv(" judged=" as *u8, judged)
216 tw_kv(" mean_nmax=" as *u8, tal[TWC_TAL_NMAX_SUM] / pm_max(judged, 1))
217 k = 0
218 while k < TW_LANDMARKS {
219 ri_puts(" bias_deci_" as *u8); ri_puts(tw_landmark_name(k))
220 tw_kv("=" as *u8, acc[k * TWC_ACC_FIELDS] / pm_max(judged, 1)); tw_kv("," as *u8, acc[k * TWC_ACC_FIELDS + 1] / pm_max(judged, 1))
221 k = k + 1
222 }
223 tw_kv(" tilt_abs_err_mean_deg10=" as *u8, tal[TWC_TAL_TILT_ERR_SUM] / pm_max(judged * 2, 1)); tw_kv(" found_bar_permil=" as *u8, PM_NME_FOUND_PERMIL)
224 k = 0
225 while k < TW_LANDMARKS { ri_puts(" mean_nme_" as *u8); ri_puts(tw_landmark_name(k)); tw_kv("=" as *u8, tal[TWC_TAL_NME_LM + k] / pm_max(judged, 1)); k = k + 1 }
226 // AT44: the mouth's partition sums to the renders on its own
227 let ljudged: i64 = tal[TWC_TAL_LIP_FOUND] + tal[TWC_TAL_LIP_OFF]
228 tw_kv(" lip_found=" as *u8, tal[TWC_TAL_LIP_FOUND]); tw_kv(" lip_placed_off=" as *u8, tal[TWC_TAL_LIP_OFF]); tw_kv(" lip_unmeasured=" as *u8, tal[TWC_TAL_LIP_UNMEASURED]); tw_kv(" lip_no_truth=" as *u8, tal[TWC_TAL_LIP_NOTRUTH])
229 tw_kv(" lip_partition_sum=" as *u8, ljudged + tal[TWC_TAL_LIP_UNMEASURED] + tal[TWC_TAL_LIP_NOTRUTH]); tw_kv(" lip_judged=" as *u8, ljudged)
230 tw_kv(" lip_mean_nmax=" as *u8, tal[TWC_TAL_LIP_NMAX_SUM] / pm_max(ljudged, 1)); tw_kv(" lip_mean_nmean=" as *u8, tal[TWC_TAL_LIP_NMEAN_SUM] / pm_max(ljudged, 1))
231 tw_kv(" lip_ratio_abs_err_mean_permil=" as *u8, tal[TWC_TAL_LIP_RATIO_ERR_SUM] / pm_max(ljudged, 1))
232 let ajudged: i64 = tal[TWC_TAL_ALIP_FOUND] + tal[TWC_TAL_ALIP_OFF]
233 tw_kv(" anchored_lip_found=" as *u8, tal[TWC_TAL_ALIP_FOUND]); tw_kv(" anchored_lip_placed_off=" as *u8, tal[TWC_TAL_ALIP_OFF]); tw_kv(" anchored_lip_unmeasured=" as *u8, tal[TWC_TAL_ALIP_UNMEASURED])
234 tw_kv(" anchored_lip_partition_sum=" as *u8, ajudged + tal[TWC_TAL_ALIP_UNMEASURED]); tw_kv(" anchored_lip_mean_nmean=" as *u8, tal[TWC_TAL_ALIP_NMEAN_SUM] / pm_max(ajudged, 1))
235 tw_kv(" anchored_lip_ratio_abs_err_mean_permil=" as *u8, tal[TWC_TAL_ALIP_RATIO_ERR_SUM] / pm_max(ajudged, 1))
236 k = 0
237 while k < TW_LIP_LANDMARKS {
238 ri_puts(" lip_bias_deci_" as *u8); ri_puts(tw_lip_landmark_name(k))
239 tw_kv("=" as *u8, lacc[k * TWC_LACC_FIELDS] / pm_max(ljudged, 1)); tw_kv("," as *u8, lacc[k * TWC_LACC_FIELDS + 1] / pm_max(ljudged, 1)); tw_kv(":" as *u8, lacc[k * TWC_LACC_FIELDS + 2] / pm_max(ljudged, 1))
240 k = k + 1
241 }
242 if tal[TWC_TAL_FOUND] == renders { ri_puts(" verdict=ALL-FOUND\n" as *u8); return 0 }
243 ri_puts(" verdict=PARTIAL\n" as *u8)
244 return TWC_EXIT_PARTIAL
245}
246func main(argc: i64, argv: **u8) -> i64 {
247 if argc < TWC_ARGC_ENVELOPE { return twc_usage() }
248 let verb: *u8 = argv[1]
249 let cs: *i64 = sys_mmap(2 * TW_I64) as *i64
250 let loaded: i64 = tw_load_cascades(cs)
251 tw_kv("TWINFIT cascades_loaded=" as *u8, loaded); ri_puts("\n" as *u8)
252 if loaded == 0 { ri_puts("TWINFIT the cascade arm is not loaded -- the render route has no eye finder without it\n" as *u8); return TWC_EXIT_NOCASCADE }
253 let face_c: *HaarCascade = cs[0] as *HaarCascade
254 let eye_c: *HaarCascade = cs[1] as *HaarCascade
255 let base: i64 = sys_mmap(sdf_bytes()) as i64
256 let rgb: *u8 = sys_mmap(ww() * hh() * TW_RGB_BPP)
257 let res: *i64 = sys_mmap(PM_R_N * TW_I64) as *i64
258 let g: *i64 = sys_mmap(TW_SLOTS * TW_I64) as *i64
259 let skin: *i64 = sys_mmap(TW_SLOTS * TW_I64) as *i64
260 tw_skin_default(skin)
261 if ri_streq(verb, "axes" as *u8) == 1 {
262 if argc < TWC_ARGC_AXES { return twc_usage() }
263 var k: i64 = 0
264 while k < TW_GENES { g[k] = tw_atoi(argv[2 + k]); k = k + 1 }
265 if argc >= TWC_ARGC_AXES_SKIN { k = 0; while k < TW_SKIN_FIELDS { skin[k] = tw_atoi(argv[TWC_ARGC_AXES + k]); k = k + 1 } }
266 twc_print_skin(skin)
267 let r: i64 = tw_measure(base, g, skin, rgb, res, face_c, eye_c)
268 ri_puts("TWINFIT genome=" as *u8)
269 k = 0
270 while k < TW_GENES { if k > 0 { ri_puts("," as *u8) } ri_putn(g[k]); k = k + 1 }
271 tw_kv(" rc=" as *u8, r); tw_print_axes(res)
272 if r == PM_OK { ri_puts(" verdict=MEASURED\n" as *u8); return 0 }
273 ri_puts(" verdict=UNMEASURED\n" as *u8)
274 return TWC_EXIT_PARTIAL
275 }
276 if ri_streq(verb, "fit" as *u8) == 1 {
277 // AT40: solve the thirteen genes against a card's axes from the STATED landmarks, then confirm the answer on the surface
278 if argc < TWC_ARGC_FIT { return twc_usage() }
279 let ftv: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
280 let fte: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
281 let nt: i64 = tw_load_target(argv[2], ftv, fte)
282 tw_kv("TWINFIT target_axes_read=" as *u8, nt); ri_puts("\n" as *u8)
283 if nt == 0 { ri_puts("TWINFIT-FIT verdict=NO-TARGET the target file carries no axis row this organ knows\n" as *u8); return TWC_EXIT_USAGE }
284 let ga: *i64 = sys_mmap(TW_ALL_GENES * TW_I64) as *i64
285 let fax: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
286 let fcost: *i64 = sys_mmap(TW_I64) as *i64
287 tw_all_canon_fill(ga)
288 let fax0: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
289 let ft0: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
290 let cost0: i64 = tw_fit_eval(base, ga, ftv, fte, ft0, fax0)
291 let evals: i64 = tw_fit(base, ftv, fte, ga, fax, fcost)
292 var kg: i64 = 0
293 var at_limit: i64 = 0
294 while kg < TW_ALL_GENES {
295 ri_puts("FIT gene=" as *u8); ri_puts(tw_all_name(kg)); tw_kv(" value=" as *u8, ga[kg]); tw_kv(" canon=" as *u8, tw_all_canon(kg))
296 tw_kv(" lo=" as *u8, tw_all_lo(kg)); tw_kv(" hi=" as *u8, tw_all_hi(kg))
297 var lim: i64 = 0
298 if ga[kg] == tw_all_lo(kg) { lim = 1 }
299 if ga[kg] == tw_all_hi(kg) { lim = 1 }
300 if lim == 1 { ri_puts(" AT-RANGE-LIMIT" as *u8); at_limit = at_limit + 1 }
301 ri_puts("\n" as *u8)
302 kg = kg + 1
303 }
304 var reached: i64 = 0
305 var unreached: i64 = 0
306 var unstated: i64 = 0
307 var notarget: i64 = 0
308 var fa2: i64 = 0
309 while fa2 < TW_AXES {
310 let st: i64 = tw_axis_state(fax, ftv, fte, fa2)
311 ri_puts("FIT axis=" as *u8); ri_puts(tw_axis_name(fa2))
312 if ftv[fa2] != TW_UNSET { tw_kv(" target=" as *u8, ftv[fa2]); tw_kv(" err=" as *u8, fte[fa2]) }
313 if fax[fa2] != TW_UNSET { tw_kv(" canon_face=" as *u8, fax0[fa2]); tw_kv(" fitted=" as *u8, fax[fa2]) }
314 if st == TW_AXIS_REACHED { reached = reached + 1 }
315 if st == TW_AXIS_UNREACHED { unreached = unreached + 1 }
316 if st == TW_AXIS_UNSTATED { unstated = unstated + 1 }
317 if st == TW_AXIS_NO_TARGET { notarget = notarget + 1 }
318 ri_puts(" state=" as *u8); ri_puts(tw_axis_state_name(st)); ri_puts("\n" as *u8)
319 fa2 = fa2 + 1
320 }
321 // the answer, confirmed once on the surface
322 tw_build_all(base, ga)
323 let ftt: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
324 let confirmed: i64 = tw_truth_landmarks(base, TW_YAW_FRONTAL, ftt)
325 tw_kv("TWINFIT-FIT evals=" as *u8, evals); tw_kv(" cost_canon=" as *u8, cost0); tw_kv(" cost_fitted=" as *u8, fcost[0])
326 tw_kv(" reached=" as *u8, reached); tw_kv(" unreached=" as *u8, unreached); tw_kv(" unstated=" as *u8, unstated); tw_kv(" no_target=" as *u8, notarget)
327 tw_kv(" axis_partition_sum=" as *u8, reached + unreached + unstated + notarget); tw_kv(" genes_at_range_limit=" as *u8, at_limit)
328 tw_kv(" surface_confirmed=" as *u8, confirmed); tw_kv(" surface_gap=" as *u8, ftt[TW_T_MODEL_R + TW_TM_GAP]); tw_kv("," as *u8, ftt[TW_T_MODEL_L + TW_TM_GAP])
329 ri_puts(" genome=" as *u8)
330 kg = 0
331 while kg < TW_ALL_GENES { if kg > 0 { ri_puts("," as *u8) } ri_putn(ga[kg]); kg = kg + 1 }
332 if unreached + unstated == 0 { if confirmed == 1 { ri_puts(" verdict=FIT\n" as *u8); return 0 } }
333 ri_puts(" verdict=PARTIAL\n" as *u8)
334 return TWC_EXIT_PARTIAL
335 }
336 if ri_streq(verb, "truthcols" as *u8) == 1 {
337 // the fissure scan's own columns for one persongen identity, image-left eye: what each column measured, so a rule about
338 // where the opening ends is written from the data and not from a guess
339 if argc < TWC_ARGC_TRUTHSEED { return twc_usage() }
340 let cs_seed: i64 = tw_atoi(argv[2])
341 let cidv: *i64 = sys_mmap(TW_SLOTS * TW_I64) as *i64
342 let ceg: *i64 = sys_mmap(FA_EG_N * TW_I64) as *i64
343 persongen_build_eye(base, cs_seed, skin, cidv, ceg)
344 let cpp: *i64 = (base + O_PARTS) as *i64
345 let ccx: i64 = cpp[FA_GLOBE_L * FA_PART_FIELDS + FA_F_CX]
346 let ccy: i64 = cpp[FA_GLOBE_L * FA_PART_FIELDS + FA_F_CY]
347 let cytop: i64 = ccy + (FA_PF_Y_TOP - FA_EYE_CY)
348 let czs: *i64 = sys_mmap(FA_PF_NS * TW_I64 + FA_LIP_SLACK) as *i64
349 let cdy: *i64 = sys_mmap(FA_PF_DY_SLOTS * TW_I64 + FA_LIP_SLACK) as *i64
350 tw_kv("TRUTHCOLS seed=" as *u8, cs_seed); tw_kv(" globe_cx=" as *u8, ccx); tw_kv(" globe_cy=" as *u8, ccy); tw_kv(" ytop=" as *u8, cytop)
351 tw_kv(" halfw=" as *u8, sdf_get_prim(base, FA_LID_L, SDF_PR_HALFW)); tw_kv(" up=" as *u8, sdf_get_prim(base, FA_LID_L, SDF_PR_UP)); tw_kv(" low=" as *u8, sdf_get_prim(base, FA_LID_L, SDF_PR_LOW)); ri_puts("\n" as *u8)
352 var cj: i64 = 0
353 let csteps: i64 = (FA_PF_XSPAN * 2) / FA_PF_XSTEP
354 while cj <= csteps {
355 let cxx: i64 = ccx - FA_PF_XSPAN + cj * FA_PF_XSTEP
356 let cd: i64 = fa_pf_column(base, cxx, cytop, czs, cdy)
357 tw_kv("COL x=" as *u8, cxx); tw_kv(" d=" as *u8, cd)
358 if cd != FA_LIP_UNMEASURED { tw_kv(" floor_y=" as *u8, cdy[FA_PF_DY_FLOOR]); tw_kv(" up_y=" as *u8, cdy[FA_PF_DY_UP]); tw_kv(" dn_y=" as *u8, cdy[FA_PF_DY_DN]) }
359 ri_puts("\n" as *u8)
360 cj = cj + 1
361 }
362 return 0
363 }
364 if ri_streq(verb, "truthseed" as *u8) == 1 {
365 // no render: a persongen identity is grown and its own surface is asked where the canthi are; the eye genes print beside it
366 if argc < TWC_ARGC_TRUTHSEED { return twc_usage() }
367 let sd: i64 = tw_atoi(argv[2])
368 let sidv: *i64 = sys_mmap(TW_SLOTS * TW_I64) as *i64
369 let seg: *i64 = sys_mmap(FA_EG_N * TW_I64) as *i64
370 persongen_build_eye(base, sd, skin, sidv, seg)
371 let st2: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
372 let have_s: i64 = tw_truth_landmarks(base, TW_YAW_FRONTAL, st2)
373 tw_kv("TRUTH seed=" as *u8, sd)
374 var ke: i64 = 0
375 while ke < FA_EG_N { ri_puts(" " as *u8); ri_puts(fa_eye_gene_name(ke)); tw_kv("=" as *u8, seg[ke]); ke = ke + 1 }
376 tw_print_truth(st2)
377 let slt: *i64 = sys_mmap(TW_LT_N * TW_I64) as *i64
378 tw_lip_truth(base, TW_YAW_FRONTAL, slt)
379 tw_print_lip_truth(slt)
380 if have_s == 1 { ri_puts(" verdict=TRUTH\n" as *u8); return 0 }
381 ri_puts(" verdict=NO-TRUTH\n" as *u8)
382 return TWC_EXIT_PARTIAL
383 }
384 if ri_streq(verb, "truth" as *u8) == 1 {
385 // no render: the face is built and its own surface is asked where the canthi are
386 if argc < TWC_ARGC_AXES { return twc_usage() }
387 var kt: i64 = 0
388 while kt < TW_GENES { g[kt] = tw_atoi(argv[2 + kt]); kt = kt + 1 }
389 tw_build(base, g)
390 let tt: *i64 = sys_mmap(TW_T_N * TW_I64) as *i64
391 let have_t: i64 = tw_truth_landmarks(base, TW_YAW_FRONTAL, tt)
392 ri_puts("TRUTH genome=" as *u8)
393 kt = 0
394 while kt < TW_GENES { if kt > 0 { ri_puts("," as *u8) } ri_putn(g[kt]); kt = kt + 1 }
395 tw_print_truth(tt)
396 if have_t == 1 { ri_puts(" verdict=TRUTH\n" as *u8); return 0 }
397 ri_puts(" verdict=NO-TRUTH\n" as *u8)
398 return TWC_EXIT_PARTIAL
399 }
400 if ri_streq(verb, "truthref" as *u8) == 1 {
401 var seeds: i64 = TWC_TR_SEEDS_DEFAULT
402 if argc >= TWC_ARGC_TRUTHREF_SEEDS { seeds = tw_atoi(argv[2]) }
403 twc_print_skin(skin)
404 var seed_lo: i64 = 1
405 var sweep: i64 = 1
406 if argc >= TWC_ARGC_TRUTHREF_LO { seed_lo = tw_atoi(argv[3]) }
407 if argc >= TWC_ARGC_TRUTHREF_SWEEP { sweep = tw_atoi(argv[4]) }
408 return twc_truthref(seed_lo, seeds, sweep, base, rgb, res, g, skin, face_c, eye_c)
409 }
410 if ri_streq(verb, "envelope" as *u8) == 0 { return twc_usage() }
411 let tv: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
412 let te: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
413 tw_target_clear(tv, te)
414 if argc >= TWC_ARGC_ENVELOPE_TARGET { let targets: i64 = tw_load_target(argv[2], tv, te); tw_kv("TWINFIT target_axes_read=" as *u8, targets); ri_puts("\n" as *u8) }
415 if argc >= TWC_ARGC_ENVELOPE_SKIN { var s0: i64 = 0; while s0 < TW_SKIN_FIELDS { skin[s0] = tw_atoi(argv[TWC_ARGC_ENVELOPE_TARGET + s0]); s0 = s0 + 1 } }
416 twc_print_skin(skin)
417 let amin: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
418 let amax: *i64 = sys_mmap(TW_AXES * TW_I64) as *i64
419 var a: i64 = 0
420 while a < TW_AXES { amin[a] = TW_BIG; amax[a] = 0 - TW_BIG; a = a + 1 }
421 var renders: i64 = 0
422 var measured: i64 = 0
423 var unmeasured: i64 = 0
424 var k: i64 = 0
425 while k < TW_GENES {
426 var l: i64 = 0
427 while l < TW_LEVELS {
428 var j: i64 = 0
429 while j < TW_GENES { g[j] = tw_mid(j); j = j + 1 }
430 g[k] = tw_level_pct(k, l)
431 let r: i64 = tw_measure(base, g, skin, rgb, res, face_c, eye_c)
432 renders = renders + 1
433 ri_puts("TWINFIT gene=" as *u8); ri_puts(tw_gene_name(k)); ri_puts(" level=" as *u8); ri_puts(tw_level_name(l))
434 tw_kv(" pct=" as *u8, g[k]); tw_kv(" rc=" as *u8, r)
435 if r == PM_OK {
436 measured = measured + 1
437 tw_print_axes(res)
438 a = 0
439 while a < TW_AXES {
440 let v: i64 = tw_axis_value(res, a)
441 if v < amin[a] { amin[a] = v }
442 if v > amax[a] { amax[a] = v }
443 a = a + 1
444 }
445 ri_puts(" verdict=MEASURED\n" as *u8)
446 } else {
447 unmeasured = unmeasured + 1
448 tw_kv(" eyes=" as *u8, res[PM_R_EYES]); tw_kv(" pair_fail=" as *u8, res[PM_R_PAIR_FAIL])
449 ri_puts(" verdict=UNMEASURED\n" as *u8)
450 }
451 l = l + 1
452 }
453 k = k + 1
454 }
455 var reachable: i64 = 0
456 var unreachable: i64 = 0
457 var notarget: i64 = 0
458 a = 0
459 while a < TW_AXES {
460 ri_puts("TWINFIT axis=" as *u8); ri_puts(tw_axis_name(a))
461 if measured > 0 { tw_kv(" min=" as *u8, amin[a]); tw_kv(" max=" as *u8, amax[a]); tw_kv(" spread=" as *u8, amax[a] - amin[a]) }
462 else { ri_puts(" min=UNMEASURED max=UNMEASURED" as *u8) }
463 if tv[a] == TW_UNSET { ri_puts(" target=NONE reach=NO-TARGET\n" as *u8); notarget = notarget + 1 }
464 else {
465 tw_kv(" target=" as *u8, tv[a]); tw_kv(" err=" as *u8, te[a])
466 var reach: i64 = 0
467 if measured > 0 { reach = tw_reach(tv[a], te[a], amin[a], amax[a]) }
468 if reach == 1 { ri_puts(" reach=REACHABLE\n" as *u8); reachable = reachable + 1 }
469 else { ri_puts(" reach=UNREACHABLE\n" as *u8); unreachable = unreachable + 1 }
470 }
471 a = a + 1
472 }
473 tw_kv("TWINFIT-SUMMARY renders=" as *u8, renders); tw_kv(" measured=" as *u8, measured); tw_kv(" unmeasured=" as *u8, unmeasured)
474 tw_kv(" partition_sum=" as *u8, measured + unmeasured)
475 tw_kv(" axes=" as *u8, TW_AXES); tw_kv(" reachable=" as *u8, reachable); tw_kv(" unreachable=" as *u8, unreachable); tw_kv(" no_target=" as *u8, notarget)
476 tw_kv(" axis_partition_sum=" as *u8, reachable + unreachable + notarget)
477 if unmeasured > 0 { ri_puts(" verdict=ENVELOPE-PARTIAL\n" as *u8); return TWC_EXIT_PARTIAL }
478 ri_puts(" verdict=ENVELOPE\n" as *u8)
479 return 0
480}