nx_de_referee_lib.nx source
↩ module page · 128 lines · 5255 B
1// nx_de_referee_lib.nx -- THE PER-REGION CIEDE2000 REFEREE: rung ST1 of /compare/skintwin (2026-09-03)
2//
3// WHY THIS IS THE HIGHEST-VALUE RUNG ON THAT BOARD. nx_colorsci_lib has carried cs_de2000 -- the colour
4// difference the whole field states its errors in -- since 2026-08-24, and MEASURED with corpus_complete=1
5// it has ZERO adopters outside the garment-print lane. Until something in the render lane calls it, every
6// quality claim about a rendered human is an assertion about MECHANISM, not about appearance. The chromophore
7// stack can be perfectly derived and still look wrong, and nothing in the estate could say so in a number.
8// This file is the thing that can say so.
9//
10// IT COMPOSES, IT DOES NOT RE-RULE. The colour difference itself is cs_de2000, untouched: this file adds only
11// the AGGREGATION -- per region, worst region, mean, and a verdict against a declared tolerance. There is
12// exactly one CIEDE2000 in this estate and it is not here.
13//
14// THE THREE LAWS THIS FILE EXISTS TO ENFORCE, each of which the estate has been bitten by before:
15// 1. ABSTAIN, NEVER ACQUIT. A region with no samples is UNOBSERVED. It is not a pass. A referee that
16// silently counts an unmeasured region as agreement is worse than no referee, because its green is
17// indistinguishable from a real one.
18// 2. A TOOTH THAT PASSES ON THE EMPTY SET IS NOT A TOOTH. If nothing was measured, the verdict is ABSTAIN.
19// Zero regions must never return PASS, however tight the tolerance.
20// 3. THE DENOMINATOR TRAVELS WITH THE VERDICT. measured + unobserved always equals the declared region
21// count, and both halves are written to the output so a caller can reconcile them rather than trust a
22// bare number.
23//
24// The TOLERANCE is an ARGUMENT, not a constant. A bar for a print proof and a bar for a screen render are
25// different numbers with the same units, and a lib that picks one has decided something it has no standing
26// to decide. The caller declares it and the gate prints it.
27// license_tier: ORIGINAL No hw writes (Rule 26). LIB (no main).
28import "nx_syscalls.nx"
29import "nx_fixq30_lib.nx"
30import "nx_colorsci_lib.nx"
31
32const DR_REFUSED: i64 = 0 - 1
33// verdicts
34const DR_PASS: i64 = 0
35const DR_FAIL: i64 = 1
36const DR_ABSTAIN: i64 = 2
37// a region carrying no samples
38const DR_UNOBSERVED: i64 = 0 - 1
39
40// out slots
41const DR_O_VERDICT: i64 = 0
42const DR_O_WORST_IDX: i64 = 1
43const DR_O_WORST_DE: i64 = 2
44const DR_O_MEAN_DE: i64 = 3
45const DR_O_MEASURED: i64 = 4
46const DR_O_UNOBSERVED: i64 = 5
47const DR_O_DECLARED: i64 = 6
48const DR_O_SLOTS: i64 = 7
49const DR_SLOT: i64 = 8
50const DR_LAB: i64 = 3
51
52// The colour difference for ONE region, straight through the estate's single CIEDE2000.
53// ref3 and rnd3 are L*, a*, b* triples in Q30.
54func dr_region_de(cs: *i64, ref3: *i64, rnd3: *i64) -> i64 {
55 return cs_de2000(cs, ref3[0], ref3[1], ref3[2], rnd3[0], rnd3[1], rnd3[2])
56}
57
58// Judge a whole set of regions.
59// refs, rnds : n contiguous Lab triples each (3 slots per region)
60// counts : n sample counts; a count of zero marks the region UNOBSERVED
61// tol : the declared tolerance in Q30 CIEDE2000 units
62// Returns the verdict, and writes the full picture to out so nothing has to be inferred from it.
63func dr_run(cs: *i64, refs: *i64, rnds: *i64, counts: *i64, n: i64, tol: i64, out: *i64) -> i64 {
64 var z: i64 = 0
65 while z < DR_O_SLOTS {
66 out[z] = 0
67 z = z + 1
68 }
69 out[DR_O_WORST_IDX] = DR_UNOBSERVED
70 out[DR_O_DECLARED] = n
71 if n < 0 { return DR_REFUSED }
72 if tol <= 0 { return DR_REFUSED }
73
74 var measured: i64 = 0
75 var unobserved: i64 = 0
76 var worst: i64 = 0
77 var worst_i: i64 = DR_UNOBSERVED
78 var sum: i64 = 0
79 var i: i64 = 0
80 while i < n {
81 if counts[i] <= 0 {
82 unobserved = unobserved + 1
83 } else {
84 let base: i64 = i * DR_LAB
85 let de: i64 = dr_region_de(cs, (refs as i64 + base * DR_SLOT) as *i64,
86 (rnds as i64 + base * DR_SLOT) as *i64)
87 sum = sum + de
88 if measured == 0 {
89 worst = de
90 worst_i = i
91 } else {
92 if de > worst {
93 worst = de
94 worst_i = i
95 }
96 }
97 measured = measured + 1
98 }
99 i = i + 1
100 }
101
102 out[DR_O_MEASURED] = measured
103 out[DR_O_UNOBSERVED] = unobserved
104 out[DR_O_WORST_IDX] = worst_i
105 out[DR_O_WORST_DE] = worst
106 if measured > 0 { out[DR_O_MEAN_DE] = sum / measured }
107
108 // LAW 2: nothing measured is never a pass, however tight the tolerance.
109 if measured == 0 {
110 out[DR_O_VERDICT] = DR_ABSTAIN
111 return DR_ABSTAIN
112 }
113 // LAW 1: only MEASURED regions can fail it, and only measured regions can pass it. An unobserved region
114 // rescues nothing and condemns nothing.
115 if worst > tol {
116 out[DR_O_VERDICT] = DR_FAIL
117 return DR_FAIL
118 }
119 out[DR_O_VERDICT] = DR_PASS
120 return DR_PASS
121}
122
123func dr_verdict_name(v: i64) -> *u8 {
124 if v == DR_PASS { return "PASS" as *u8 }
125 if v == DR_FAIL { return "FAIL" as *u8 }
126 if v == DR_ABSTAIN { return "ABSTAIN" as *u8 }
127 return "REFUSED" as *u8
128}