code wiki / (root) / nx_twinfit.nx

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}