nx_render_target_match.nx source
↩ module page · 209 lines · 8498 B
1// nx_render_target_match.nx -- did the generated image match the target?
2//
3// Universal RENDERED-VS-TARGET verdict primitive. Given two 16-element
4// feature vectors (target image + rendered image), emits a sealed-enum
5// verdict + per-axis divergence + actionable next-axis pinpoint.
6//
7// USE CASES (all the same substrate, different target sources):
8//
9// 1. RETAIL VIRTUAL TRY-ON (Google Shopping AI Mode pattern):
10// target = product image (lingerie / dress / jacket / shoes)
11// render = model wearing the product (via gen-img)
12// verdict = did the rendered model faithfully wear the product?
13// action = which visual axis (color / texture / silhouette / etc.)
14// needs another iteration?
15//
16// 2. VIDEO-GAME ASSET RENDER:
17// target = concept art reference for a weapon / armor / character
18// render = in-engine model the procgen produced
19// verdict = does the asset match the brief?
20//
21// 3. STORY-DRIVEN SCENE RENDER (legal adult or all-ages):
22// target = reference image for the desired scene mood
23// render = generated scene image
24// verdict = does the render hit the mood?
25//
26// All three use the SAME primitive. Different in the prompt + concept-
27// embedding upstream; identical at the measure-the-output layer.
28//
29// COMPOSES:
30// nx_cosine_similarity -- overall vector alignment
31// per-axis delta math -- normalized |target - rendered| per axis
32// sealed verdict bands -- substrate-honest routing
33// worst-axis pinpoint -- which axis to refactor next render
34//
35// genealogy_id: salton_1971_smart + clip_score_hessel_2021 +
36// ip_adapter_ye_2023 + lpips_zhang_2018 +
37// fid_heusel_2017
38// lineage_id: render_target_match_q10
39
40// nx_safety_envelope:
41// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
42// sil_target: SIL1
43// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
44// verdict: NOT_YET_EVALUATED
45
46import "nx_syscalls.nx"
47import "nx_tier.nx"
48import "nx_image_feature_extract.nx"
49import "nx_cosine_similarity.nx"
50
51const NX_RTM_Q: nx_int = 1024
52
53// Sealed-enum verdicts (HIGH = better match)
54const NX_RTM_MATCH_FAILED: nx_int = 0 // cos < 256 or fidelity below floor
55const NX_RTM_MATCH_POOR: nx_int = 1 // 256 <= cos < 512
56const NX_RTM_MATCH_PARTIAL: nx_int = 2 // 512 <= cos < 768
57const NX_RTM_MATCH_GOOD: nx_int = 3 // 768 <= cos < 921
58const NX_RTM_MATCH_EXCELLENT: nx_int = 4 // cos >= 921 AND worst-axis-delta tight
59const NX_RTM_N_VERDICTS: nx_int = 5
60
61// Recommended next-action sealed enum (operator chooses based on
62// worst-axis pinpoint).
63const NX_RTM_ACTION_SHIP: nx_int = 0
64const NX_RTM_ACTION_REFINE_COLOR: nx_int = 1
65const NX_RTM_ACTION_REFINE_LIGHTING: nx_int = 2
66const NX_RTM_ACTION_REFINE_COMPOSITION: nx_int = 3
67const NX_RTM_ACTION_REFINE_CLARITY: nx_int = 4
68const NX_RTM_ACTION_REFINE_SHARPNESS: nx_int = 5
69const NX_RTM_ACTION_REFINE_FRACTAL: nx_int = 6
70const NX_RTM_ACTION_REFINE_SYMMETRY: nx_int = 7
71const NX_RTM_ACTION_RESTART_FROM_SCRATCH: nx_int = 8
72const NX_RTM_N_ACTIONS: nx_int = 9
73
74// Tolerance: a per-axis delta below this counts as "aligned."
75const NX_RTM_AXIS_TOLERANCE_Q10: nx_int = 200 // 20% of full scale
76
77// Worst-axis-delta ceiling for the EXCELLENT band -- even with high
78// cosine, if ANY single axis diverges this much, demote to GOOD.
79const NX_RTM_EXCELLENT_MAX_AXIS_DELTA: nx_int = 100
80
81struct RenderTargetMatchReport {
82 overall_cosine_q10: nx_int,
83 n_aligned_axes: nx_int, // axes with delta <= tolerance
84 n_diverged_axes: nx_int, // axes above tolerance
85 worst_axis_delta_q10: nx_int, // max per-axis delta
86 worst_axis_index: nx_int, // which axis (0..15)
87 actionable_axis: nx_int, // same as worst_axis_index in v1
88 recommended_action: nx_int, // NX_RTM_ACTION_*
89 verdict: nx_int, // NX_RTM_MATCH_*
90 fidelity_q10: nx_int,
91}
92
93// Map a feature-axis index to its recommended next-action.
94// Feature axes 0..5 = aesthetics; 6..8 = fractal; 9..15 = symmetry.
95func _rtm_axis_to_action(axis: nx_int) -> nx_int {
96 if axis == NX_IMG_FEAT_COLOR_HARMONY { return NX_RTM_ACTION_REFINE_COLOR }
97 if axis == NX_IMG_FEAT_LIGHTING { return NX_RTM_ACTION_REFINE_LIGHTING }
98 if axis == NX_IMG_FEAT_COMPOSITION { return NX_RTM_ACTION_REFINE_COMPOSITION }
99 if axis == NX_IMG_FEAT_CLARITY { return NX_RTM_ACTION_REFINE_CLARITY }
100 if axis == NX_IMG_FEAT_SHARPNESS { return NX_RTM_ACTION_REFINE_SHARPNESS }
101 if axis == NX_IMG_FEAT_AESTHETIC_COMPOSITE { return NX_RTM_ACTION_REFINE_COMPOSITION }
102 if axis == NX_IMG_FEAT_FRACTAL_DIM { return NX_RTM_ACTION_REFINE_FRACTAL }
103 if axis == NX_IMG_FEAT_FRACTAL_AESTHETIC { return NX_RTM_ACTION_REFINE_FRACTAL }
104 if axis == NX_IMG_FEAT_EDGE_DENSITY { return NX_RTM_ACTION_REFINE_SHARPNESS }
105 if axis >= NX_IMG_FEAT_SYM_COMPOSITE { return NX_RTM_ACTION_REFINE_SYMMETRY }
106 return NX_RTM_ACTION_RESTART_FROM_SCRATCH
107}
108
109// Absolute value helper.
110func _rtm_abs(x: nx_int) -> nx_int {
111 if x < 0 { return -x }
112 return x
113}
114
115// ===== Public compute ================================================
116
117func nx_render_target_match(target_features: *nx_int,
118 rendered_features: *nx_int,
119 report: *RenderTargetMatchReport) -> nx_int {
120 report.overall_cosine_q10 = 0
121 report.n_aligned_axes = 0
122 report.n_diverged_axes = 0
123 report.worst_axis_delta_q10 = 0
124 report.worst_axis_index = 0
125 report.actionable_axis = 0
126 report.recommended_action = NX_RTM_ACTION_SHIP
127 report.verdict = NX_RTM_MATCH_FAILED
128 report.fidelity_q10 = NX_RTM_Q
129
130 // Overall cosine over the two feature vectors.
131 let cos: nx_int = nx_cosine_similarity(
132 target_features, NX_IMAGE_FEATURE_LEN,
133 rendered_features, NX_IMAGE_FEATURE_LEN
134 )
135 report.overall_cosine_q10 = cos
136
137 // Per-axis delta + aligned/diverged tally + worst-axis pinpoint.
138 var worst_delta: nx_int = 0
139 var worst_idx: nx_int = 0
140 var n_aligned: nx_int = 0
141 var n_diverged: nx_int = 0
142 var i: nx_int = 0
143 while i < NX_IMAGE_FEATURE_LEN {
144 let t: nx_int = target_features[i]
145 let r: nx_int = rendered_features[i]
146 let d: nx_int = _rtm_abs(t - r)
147 if d <= NX_RTM_AXIS_TOLERANCE_Q10 {
148 n_aligned = n_aligned + 1
149 } else {
150 n_diverged = n_diverged + 1
151 }
152 if d > worst_delta {
153 worst_delta = d
154 worst_idx = i
155 }
156 i = i + 1
157 }
158 report.n_aligned_axes = n_aligned
159 report.n_diverged_axes = n_diverged
160 report.worst_axis_delta_q10 = worst_delta
161 report.worst_axis_index = worst_idx
162 report.actionable_axis = worst_idx
163 report.recommended_action = _rtm_axis_to_action(worst_idx)
164
165 // Sealed-enum verdict routing.
166 //
167 // EXCELLENT requires both high cosine AND tight worst-axis (no
168 // single axis blew the budget). GOOD/PARTIAL/POOR route on
169 // cosine alone. FAILED catches negative-cosine + low-fidelity
170 // cases.
171 if cos < 256 {
172 report.verdict = NX_RTM_MATCH_FAILED
173 return 0
174 }
175 if cos < 512 {
176 report.verdict = NX_RTM_MATCH_POOR
177 return 0
178 }
179 if cos < 768 {
180 report.verdict = NX_RTM_MATCH_PARTIAL
181 return 0
182 }
183 if cos < 921 {
184 report.verdict = NX_RTM_MATCH_GOOD
185 return 0
186 }
187 // cos >= 921: candidate for EXCELLENT pending worst-axis check.
188 if worst_delta > NX_RTM_EXCELLENT_MAX_AXIS_DELTA {
189 report.verdict = NX_RTM_MATCH_GOOD // close but not perfect
190 return 0
191 }
192 report.verdict = NX_RTM_MATCH_EXCELLENT
193 report.recommended_action = NX_RTM_ACTION_SHIP // ship the render
194 return 0
195}
196
197// ===== Sealed-enum validity =========================================
198
199func nx_render_target_match_verdict_is_valid(v: nx_int) -> nx_int {
200 if v < 0 { return 0 }
201 if v >= NX_RTM_N_VERDICTS { return 0 }
202 return 1
203}
204
205func nx_render_target_match_action_is_valid(a: nx_int) -> nx_int {
206 if a < 0 { return 0 }
207 if a >= NX_RTM_N_ACTIONS { return 0 }
208 return 1
209}