code wiki / (root) / nx_colorsci_cat_gate.nx

nx_colorsci_cat_gate.nx

buildroot/runtime/nx_colorsci_cat_gate.nx

10249 B186 linesdepth 4pulls 7 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_colorsci_cat_gate.nx -- THE GATE FOR CHROMATIC ADAPTATION in the colour-science ruler, 2026-09-03. WHY THIS EXISTS. The ICC PCS is D50 by the spec and real captures are made under other illuminants, most often D65. The profile path in nx_colorsci_lib applies matrix plus TRC only, so before this rung a colour measured under a non-PCS white carried a white-point error into every downstream gamut and CIEDE2000 judgement. The error never announced itself: every number stayed in range and merely read slightly wrong. cs_cat_* closes that, and this gate is what makes the closure evidence rather than a claim. SUBJECT: cs_cat_cone, cs_cat_build, cs_cat_apply and cs_cat_xyz in-process (the lib has no main). Teeth, in order: T1 Bradford D65 to D50 builds at all. T2 KAT: all NINE coefficients against the published Bradford D65-to-D50 matrix. A mistyped cone matrix or a transposed multiply cannot pass nine independent coefficients. T3 THE DEFINING INVARIANT: the transform carries the SOURCE white exactly onto the DESTINATION white. This one needs no external table -- it is what chromatic adaptation MEANS, so it holds even if every published digit above were mistyped, and the two teeth therefore fail independently. T4 adapting a white to ITSELF is the identity matrix (the diagonal gain degenerates to one). T5 round trip: D65 to D50 and back returns the probe. T6 ANTI-VACUITY NEG-CONTROL: CAT02 must NOT equal Bradford. Without this a cs_cat_cone that ignored its argument and always wrote Bradford would pass every other tooth on this page. T7 the invariant of T3 holds for CAT02 too, so T6 cannot pass by CAT02 being merely wrong. T8 NEG-CONTROL: an unknown transform id REFUSES (returns 0) instead of defaulting to Bradford. T9 NEG-CONTROL: a zero source white REFUSES instead of dividing by zero or emitting an identity. Tolerance is the half-ulp of the published seven-decimal matrix widened for Q30 rounding; the coefficients of the two transforms differ by ~1e-2, two orders above it, so T6 cannot pass on rounding. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_colorsci_lib.nx nx_colorsci_cat_gate.nx

imports: nx_syscalls.nxnx_gate_verdict.nxnx_colorsci_lib.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_ctr sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ gv_head gv_puts sys_write ↻ sys_mmap ↻ cgc_q fq_div fq_from_int cs_cat_build sys_mmap ↻ cs_cat_cone cs_cat_q fq_div ↻ fq_from_int ↻ cs_inv3 fq_mul fq_div ↻ cs_cat_apply fq_mul ↻ fq_div ↻ cs_cat_mul3 fq_mul ↻ gv_puts ↻ gv_num

structs

none

consts

31const CGC_SLOT: i64 = 8
32const CGC_M: i64 = 9
33const CGC_V: i64 = 3
34const CGC_MICRO: i64 = 1000000
35const CGC_TOL_MICRO: i64 = 500
36const CGC_RT_TOL_MICRO: i64 = 500
38const CGC_D65_X: i64 = 950470
39const CGC_D65_Y: i64 = 1000000
40const CGC_D65_Z: i64 = 1088830
41const CGC_D50_X: i64 = 964220
42const CGC_D50_Y: i64 = 1000000
43const CGC_D50_Z: i64 = 825210
45const CGC_KAT_0: i64 = 1047811
46const CGC_KAT_1: i64 = 22887
47const CGC_KAT_2: i64 = 0 - 50127
48const CGC_KAT_3: i64 = 29542
49const CGC_KAT_4: i64 = 990484
50const CGC_KAT_5: i64 = 0 - 17049
51const CGC_KAT_6: i64 = 0 - 9235
52const CGC_KAT_7: i64 = 15044
53const CGC_KAT_8: i64 = 752132
54const CGC_BAD_ID: i64 = 99
55const CGC_PROBE_X: i64 = 400000
56const CGC_PROBE_Y: i64 = 350000
57const CGC_PROBE_Z: i64 = 300000

functions

59func cgc_q(micro: i64) -> i64 { return fq_div(fq_from_int(micro), fq_from_int(CGC_MICRO)) }
called by 1: main calls 2: fq_divfq_from_int
60func cgc_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
called by 2: cgc_withinmain
61func cgc_within(q: i64, micro: i64, tol: i64) -> i64
called by 1: main calls 2: cgc_absfq_to_micro
66func main(argc: i64, argv: *i64) -> i64