gam_sae/
certificate_impls.rs1use gam_problem::topology_certificates::{Certificate, Claim, Evidence, Verdict};
15
16use crate::encode::EncodeResult;
17use crate::identifiability::ResidualGaugeReport;
18use crate::manifold::{CertificateInputs, GlobalOptimalityVerdict};
19
20fn put_finite(evidence: &mut Evidence, key: &'static str, value: f64) {
23 if value.is_finite() {
24 evidence.insert(key, value.into());
25 } else {
26 evidence.insert(key, "n/a".into());
27 }
28}
29
30impl Certificate for EncodeResult {
33 fn claim(&self) -> Claim {
34 Claim::new(
35 "encode-atlas",
36 "each encoded row carries a per-row Newton–Kantorovich certificate \
37 (h = β·η·L ≤ ½ at the start point); certified rows converge \
38 quadratically into the unique root, and uncertified rows are flagged \
39 for the exact multi-start fallback — never silently encoded wrong",
40 )
41 }
42
43 fn evidence(&self) -> Evidence {
44 let mut e = Evidence::new();
45 let n = self.certified.len();
46 let certified = n - self.encode_uncertified_count;
47 e.insert("rows", n.into());
48 e.insert("certified_rows", certified.into());
49 e.insert(
50 "encode_uncertified_count",
51 self.encode_uncertified_count.into(),
52 );
53 let frac = if n > 0 {
54 certified as f64 / n as f64
55 } else {
56 f64::NAN
57 };
58 put_finite(&mut e, "certified_fraction", frac);
59 e
60 }
61
62 fn verdict(&self) -> Verdict {
63 if self.certified.is_empty() {
68 Verdict::Unavailable
69 } else if self.encode_uncertified_count == 0 {
70 Verdict::Certified
71 } else {
72 Verdict::Insufficient
73 }
74 }
75}
76
77impl Certificate for ResidualGaugeReport {
80 fn claim(&self) -> Claim {
81 Claim::new(
82 "residual-gauge",
83 "the fit is identified up to a named residual gauge group: every \
84 generator was curvature-tested in the fit's own metric, the pinning \
85 span rank is reported, and any surviving (unpinned) freedom is \
86 enumerated rather than silently absorbed",
87 )
88 }
89
90 fn evidence(&self) -> Evidence {
91 let mut e = Evidence::new();
92 e.insert(
93 "metric_provenance",
94 format!("{:?}", self.metric_provenance).into(),
95 );
96 e.insert("group_signature", self.group_signature().into());
97 e.insert("pinning_rank", self.pinning_rank.into());
98 e.insert("residual_gauge_dim", self.residual_gauge_dim.into());
99 e.insert(
100 "diffeomorphism_unpinned",
101 self.diffeomorphism_unpinned.into(),
102 );
103 e.insert("generator_count", self.generators.len().into());
104 match self.sym_f_trivial_under_output_fisher {
105 Some(t) => e.insert("sym_f_trivial_under_output_fisher", t.into()),
106 None => e.insert("sym_f_trivial_under_output_fisher", "n/a".into()),
107 };
108 e.insert("summary", self.summary.clone().into());
109 e
110 }
111
112 fn verdict(&self) -> Verdict {
113 let pinned = self.residual_gauge_dim == 0
122 && !self.diffeomorphism_unpinned
123 && self.sym_f_trivial_under_output_fisher != Some(false);
124 if pinned {
125 Verdict::Certified
126 } else {
127 Verdict::Insufficient
128 }
129 }
130}
131
132impl Certificate for CertificateInputs {
135 fn claim(&self) -> Claim {
136 Claim::new(
137 "global-optimality",
138 "the fitted dictionary's basin stationary point is the unique global \
139 optimum up to the residual gauge group: a conservative sufficient \
140 condition on mutual coherence, per-atom curvature, activity floors, \
141 and reconstruction SNR holds with positive margin",
142 )
143 }
144
145 fn evidence(&self) -> Evidence {
146 let mut e = Evidence::new();
147 put_finite(&mut e, "mu_hat", self.mu_hat);
148 put_finite(&mut e, "mean_activity_floor", self.mean_activity_floor);
149 put_finite(&mut e, "peak_activity_floor", self.peak_activity_floor);
150 put_finite(&mut e, "snr_proxy", self.snr_proxy);
151 put_finite(&mut e, "dispersion", self.dispersion);
152 put_finite(
153 &mut e,
154 "global_optimality_margin",
155 self.global_optimality.margin(),
156 );
157 e.insert(
158 "global_optimality",
159 if self.global_optimality.is_certified() {
160 "certified_global"
161 } else {
162 "uncertified"
163 }
164 .into(),
165 );
166 e.insert("atom_count", self.per_atom_mean_activity.len().into());
167 e.insert("note", self.note.clone().into());
168 e
169 }
170
171 fn verdict(&self) -> Verdict {
172 match self.global_optimality {
177 GlobalOptimalityVerdict::CertifiedGlobal { .. } => Verdict::Certified,
178 GlobalOptimalityVerdict::Uncertified { .. } => Verdict::Insufficient,
179 }
180 }
181}