nx_semruler_lib.nx source
↩ module page · 116 lines · 6472 B
1// nx_semruler_lib.nx -- THE SEMANTIC RULER'S DECISION CORE (/compare/mediaingest; nx_imgsearch's own
2// declared next step). license_tier: ORIGINAL
3//
4// WHY THIS EXISTS, IN THE SUBJECT ORGAN'S OWN WORDS. nx_imgsearch status publishes, honestly:
5// {"class":"semantic-lookalike","permille":-1,"status":"UNMEASURED",
6// "note":"-1 means NEVER MEASURED, not zero. No semantic class exists in the 17-transform ruler, so
7// the previous literal 0 was a CLAIM, not a result. Order: (1) build a semantic ruler from
8// labelled same-concept pairs, (2) measure the EXISTING descriptors as the honest baseline,
9// (3) only then a quantised learned image-embedding tier (NX_IT_KIND_SEMANTIC reserved)."
10// This lib is step (1)'s decision core, and it is deliberately TINY because steps of it already existed:
11//
12// NOT WRITTEN HERE, COMPOSED INSTEAD -- each one would have been a duplicate ruler:
13// nx_recall_eval the estate's IR scorecard (nDCG/MRR/Recall/P/AP). No rate math beyond the
14// one abstaining ratio below, which exists only to refuse the empty set.
15// it_copy_distance the copy tier's own bit-Hamming over the 64-bit dHash. The admissibility
16// floor is expressed in THAT metric so the bar and the tier it guards against
17// cannot drift apart. (nx_hamming is BYTE-wise and would have mis-scaled the
18// floor by 8x while still returning a plausible number.)
19// NX_IT_CLASS_IDENTITY / NX_IT_CLASS_SIMILAR
20// the tier partition is already a first-class concept in the base class; this
21// lib only NAMES the reading so a caller cannot mistake one for the other.
22//
23// THE ONE THING THAT DID NOT EXIST, AND THE WHOLE POINT OF THE FILE:
24// A "SAME-CONCEPT" PAIR THAT IS ACTUALLY A NEAR-DUPLICATE MEASURES THE COPY TIER, NOT SEMANTICS.
25// Tiers 0-2 are copy detectors and they are excellent -- 992 permil overall across rescale, crop,
26// watermark and recompress. Feed this ruler re-crops and re-encodes of one photograph and it will
27// report near 1000 permil and "prove" the engine is already semantic. The number would be real and
28// the SUBJECT would be wrong: that is the vacuous-test defect wearing a benchmark's clothes, and it
29// is the single most likely way this measurement gets faked without anyone lying.
30// sr_pair_admissible REFUSES such a pair. Its caller MUST publish the refusal count -- a ruler that
31// silently drops inadmissible pairs has chosen its own population, which is the same defect one
32// layer up.
33//
34// AND THE MIRROR CASE, WHICH THE OBVIOUS ONE-LINE VERSION GETS WRONG: a mirrored or quarter-turned
35// re-upload has a LARGE copy distance and a TINY orient distance, because tier 1 is dihedral-invariant
36// by construction. A predicate that tested only the copy distance would admit every mirrored duplicate
37// and quietly re-measure tier 1 while claiming to measure semantics. The floor is applied to the MINIMUM
38// of the two, i.e. "is this the same photograph under ANY dihedral transform".
39
40import "nx_syscalls.nx"
41import "nx_imgsearch_tier.nx"
42
43// A rate over zero admitted pairs is UNOBSERVABLE. It is NEVER 0 and NEVER 1000: an abstention that
44// acquits is the failure this whole organ exists to prevent, and a rate printed as 0 over no
45// observations is a lie in the direction nobody audits.
46const SR_UNOBSERVABLE: i64 = 0 - 1
47const SR_PERMIL: i64 = 1000
48
49// An unknown tier class is its OWN bucket. It must never fall into a known one -- the bucket it lands
50// in becomes the number somebody plans against.
51const SR_CLASS_UNKNOWN: i64 = 0
52
53func sr_min(a: i64, b: i64) -> i64 {
54 if a < b { return a }
55 return b
56}
57
58// 1 = this pair can carry semantic evidence . 0 = it is a duplicate under some dihedral transform and
59// would measure the copy/orient tiers instead. FAIL-CLOSED on an unknown distance: a pair whose
60// distance could not be computed is inadmissible, because admitting it would let an undecodable or
61// mis-strided record silently inflate the very number this ruler exists to keep honest.
62func sr_pair_admissible(copy_dist: i64, orient_dist: i64) -> i64 {
63 if copy_dist < 0 { return 0 }
64 if orient_dist < 0 { return 0 }
65 let d: i64 = sr_min(copy_dist, orient_dist)
66 if d <= NX_IT_COPY_THRESH { return 0 }
67 return 1
68}
69
70// Recall/precision-style rate over admitted pairs, in permil. ABSTAINS rather than clamps: an
71// impossible input (more hits than subjects) is a defect in the caller's counting and must surface as
72// UNOBSERVABLE, not be silently squashed to 1000 -- a clamp here would convert a counting bug into a
73// perfect score.
74func sr_rate_permil(hits: i64, admitted: i64) -> i64 {
75 if admitted <= 0 { return SR_UNOBSERVABLE }
76 if hits < 0 { return SR_UNOBSERVABLE }
77 if hits > admitted { return SR_UNOBSERVABLE }
78 return (hits * SR_PERMIL) / admitted
79}
80
81// Which class produced a hit. Named so a caller cannot read an identity-tier hit as semantic retrieval.
82func sr_hit_is_semantic(klass: i64) -> i64 {
83 if klass == NX_IT_CLASS_SIMILAR { return 1 }
84 return 0
85}
86
87func sr_hit_is_identity(klass: i64) -> i64 {
88 if klass == NX_IT_CLASS_IDENTITY { return 1 }
89 return 0
90}
91
92// An unrecognised class is neither, and says so.
93func sr_klass_known(klass: i64) -> i64 {
94 if klass == NX_IT_CLASS_IDENTITY { return 1 }
95 if klass == NX_IT_CLASS_SIMILAR { return 1 }
96 return 0
97}
98
99// A partition is a claim: check the parts SUM, and make the check callable so no consumer has to
100// remember to do it. Returns 1 iff the three buckets reconcile to the total.
101func sr_partition_sums(identity: i64, semantic: i64, unknown: i64, total: i64) -> i64 {
102 if identity < 0 { return 0 }
103 if semantic < 0 { return 0 }
104 if unknown < 0 { return 0 }
105 if total < 0 { return 0 }
106 if identity + semantic + unknown != total { return 0 }
107 return 1
108}
109
110// The headline this ruler exists to publish, kept in ONE place so the -1 sentinel cannot be respelled
111// by a consumer. Returns the semantic-lookalike figure in permil, or SR_UNOBSERVABLE when the admitted
112// population is empty -- which is the answer whenever a pair set is all near-duplicates, and is the
113// correct, loud outcome rather than a flattering one.
114func sr_semantic_permil(semantic_hits: i64, admitted: i64) -> i64 {
115 return sr_rate_permil(semantic_hits, admitted)
116}