qualia_core_db/container_10d/
metric_check.rs1use bytemuck::{Pod, Zeroable};
26
27use crate::container_10d::axis_role::COORDINATE_AXES;
28use crate::tensor::Tensor10D;
29use std::fmt;
30
31pub const METRIC_BRANCH_COUNT: usize = 4;
34
35pub const BOUNDARY_CLIQUE_BRANCH_INDEX: usize = 3;
37
38#[repr(u8)]
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum MetricKind {
43 Undefined = 0,
45 Euclidean = 1,
46 CyclicToroidal = 2,
47 Hyperbolic = 3,
48 BoundaryClique = 4,
49}
50
51impl MetricKind {
52 #[inline]
53 pub const fn from_u8(raw: u8) -> Option<MetricKind> {
54 match raw {
55 0 => Some(MetricKind::Undefined),
56 1 => Some(MetricKind::Euclidean),
57 2 => Some(MetricKind::CyclicToroidal),
58 3 => Some(MetricKind::Hyperbolic),
59 4 => Some(MetricKind::BoundaryClique),
60 _ => None,
61 }
62 }
63}
64
65#[repr(C)]
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Pod, Zeroable)]
77pub struct MetricBranchDescriptor {
78 pub v_class: u8,
81 pub metric_kind: u8,
83 pub folded_axes: u16,
85 pub reserved: u32,
87}
88
89impl MetricBranchDescriptor {
90 #[inline]
92 pub const fn folds_axis(self, i: usize) -> bool {
93 (self.folded_axes >> i) & 1 == 1
94 }
95}
96
97#[repr(C)]
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Pod, Zeroable)]
103pub struct MetricCompletenessDescriptor {
104 pub branches: [MetricBranchDescriptor; METRIC_BRANCH_COUNT],
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct MetricDivergence {
112 pub v_class: u8,
113 pub axis_index: usize,
114 pub declared_folds: bool,
115 pub actual_folds: bool,
116}
117
118impl fmt::Display for MetricDivergence {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 let axis = super::axis_role::AXIS_ORDER[self.axis_index];
121 write!(
122 f,
123 "metric-completeness divergence: v={} claims axis {} is {}folded but full_distance {}folds it",
124 self.v_class,
125 axis,
126 if self.declared_folds { "" } else { "not " },
127 if self.actual_folds { "" } else { "does not " },
128 )
129 }
130}
131
132impl std::error::Error for MetricDivergence {}
133
134fn axis_is_folded_by_full_distance(v_class: u8, axis_index: usize) -> bool {
141 let mut base = Tensor10D::default();
144 base.v = v_class as f32;
145 let mut perturbed = base;
146 perturb_axis(&mut perturbed, axis_index);
147 let d_base = base.full_distance(&base);
148 let d_perturbed = base.full_distance(&perturbed);
149 (d_perturbed - d_base).abs() > 1e-6
152}
153
154fn perturb_axis(t: &mut Tensor10D, axis_index: usize) {
159 const DELTA: f32 = 0.25;
163 match axis_index {
164 0 => t.q += DELTA,
165 1 => t.v += DELTA,
166 2 => t.w += DELTA,
167 3 => t.x += DELTA,
168 4 => t.y += DELTA,
169 5 => t.z += DELTA,
170 6 => t.t += DELTA,
171 7 => t.alpha += DELTA,
172 8 => t.mu += DELTA,
173 9 => t.sigma += DELTA,
174 _ => unreachable!("axis_index out of range"),
175 }
176}
177
178pub fn probe_folded_axes(v_class: u8) -> u16 {
182 let mut mask: u16 = 0;
183 for &i in &COORDINATE_AXES {
184 if axis_is_folded_by_full_distance(v_class, i) {
185 mask |= 1 << i;
186 }
187 }
188 mask
189}
190
191pub fn verify_descriptor_against_reality(
201 descriptor: &MetricCompletenessDescriptor,
202) -> Result<(), MetricDivergence> {
203 for (row_index, branch) in descriptor.branches.iter().enumerate() {
204 let v_class = if row_index == BOUNDARY_CLIQUE_BRANCH_INDEX {
206 3
207 } else {
208 branch.v_class
209 };
210
211 let declared_kind = MetricKind::from_u8(branch.metric_kind);
213 match (declared_kind, v_class) {
214 (Some(MetricKind::Euclidean), 0) => {}
215 (Some(MetricKind::CyclicToroidal), 1) => {}
216 (Some(MetricKind::Hyperbolic), 2) => {}
217 (Some(MetricKind::BoundaryClique), 3) => {}
218 (Some(MetricKind::Undefined), _) => {
219 return Err(MetricDivergence {
220 v_class,
221 axis_index: 0,
222 declared_folds: false,
223 actual_folds: false,
224 });
225 }
226 _ => {
227 return Err(MetricDivergence {
229 v_class,
230 axis_index: 0,
231 declared_folds: false,
232 actual_folds: false,
233 });
234 }
235 }
236
237 let actual = probe_folded_axes(v_class);
238 for &i in &COORDINATE_AXES {
239 let declared_folds = branch.folds_axis(i);
240 let actual_folds = (actual >> i) & 1 == 1;
241 if declared_folds != actual_folds {
242 return Err(MetricDivergence {
243 v_class,
244 axis_index: i,
245 declared_folds,
246 actual_folds,
247 });
248 }
249 }
250 }
251 Ok(())
252}
253
254pub const fn proposed_metric_descriptor() -> MetricCompletenessDescriptor {
259 const fn branch(v: u8, kind: u8, folded: u16) -> MetricBranchDescriptor {
260 MetricBranchDescriptor {
261 v_class: v,
262 metric_kind: kind,
263 folded_axes: folded,
264 reserved: 0,
265 }
266 }
267 const XYZ: u16 = (1 << 3) | (1 << 4) | (1 << 5);
270 const ALL_SEVEN: u16 = XYZ | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9);
271 MetricCompletenessDescriptor {
272 branches: [
273 branch(0, MetricKind::Euclidean as u8, ALL_SEVEN),
274 branch(1, MetricKind::CyclicToroidal as u8, XYZ),
275 branch(2, MetricKind::Hyperbolic as u8, XYZ),
276 branch(255, MetricKind::BoundaryClique as u8, 0),
277 ],
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 #[test]
286 fn probe_v0_euclidean_folds_all_seven_coordinates() {
287 let mask = probe_folded_axes(0);
288 assert_eq!(
290 mask,
291 (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
292 );
293 }
294
295 #[test]
296 fn probe_v1_cyclic_folds_xyz_only() {
297 let mask = probe_folded_axes(1);
298 assert_eq!(
299 mask,
300 (1 << 3) | (1 << 4) | (1 << 5),
301 "v=1 must fold only x,y,z; got {mask:#b}"
302 );
303 assert_eq!(mask & (1 << 6), 0, "t must not be folded under v=1");
305 assert_eq!(mask & (1 << 7), 0, "α must not be folded under v=1");
306 assert_eq!(mask & (1 << 8), 0, "μ must not be folded under v=1");
307 assert_eq!(mask & (1 << 9), 0, "σ must not be folded under v=1");
308 }
309
310 #[test]
311 fn probe_v2_hyperbolic_folds_xyz_only() {
312 let mask = probe_folded_axes(2);
313 assert_eq!(
314 mask,
315 (1 << 3) | (1 << 4) | (1 << 5),
316 "v=2 must fold only x,y,z; got {mask:#b}"
317 );
318 }
319
320 #[test]
321 fn probe_v3_boundary_folds_no_coordinate_axes() {
322 let mask = probe_folded_axes(3);
323 assert_eq!(
324 mask, 0,
325 "v>=3 boundary clique must fold no coordinate axes; got {mask:#b}"
326 );
327 }
328
329 #[test]
330 fn proposed_descriptor_matches_reality() {
331 let desc = proposed_metric_descriptor();
332 assert!(
333 verify_descriptor_against_reality(&desc).is_ok(),
334 "the proposed (option b) descriptor must match full_distance's actual behaviour"
335 );
336 }
337
338 #[test]
339 fn diverging_descriptor_claiming_v1_folds_t_is_rejected() {
340 let mut desc = proposed_metric_descriptor();
341 desc.branches[1].folded_axes |= 1 << 6;
343 let err =
344 verify_descriptor_against_reality(&desc).expect_err("must reject diverging claim");
345 assert_eq!(err.v_class, 1);
346 assert_eq!(err.axis_index, 6, "divergence must name axis t (index 6)");
347 assert!(err.declared_folds);
348 assert!(!err.actual_folds);
349 }
350
351 #[test]
352 fn diverging_descriptor_claiming_v0_ignores_sigma_is_rejected() {
353 let mut desc = proposed_metric_descriptor();
354 desc.branches[0].folded_axes &= !(1 << 9);
356 let err =
357 verify_descriptor_against_reality(&desc).expect_err("must reject diverging claim");
358 assert_eq!(err.v_class, 0);
359 assert_eq!(err.axis_index, 9, "divergence must name axis σ (index 9)");
360 assert!(!err.declared_folds);
361 assert!(err.actual_folds);
362 }
363
364 #[test]
365 fn diverging_descriptor_claiming_v3_folds_x_is_rejected() {
366 let mut desc = proposed_metric_descriptor();
367 desc.branches[BOUNDARY_CLIQUE_BRANCH_INDEX].folded_axes |= 1 << 3;
369 let err =
370 verify_descriptor_against_reality(&desc).expect_err("must reject diverging claim");
371 assert_eq!(err.v_class, 3);
372 assert_eq!(err.axis_index, 3);
373 }
374
375 #[test]
376 fn wrong_metric_kind_for_v_class_is_rejected() {
377 let mut desc = proposed_metric_descriptor();
378 desc.branches[0].metric_kind = MetricKind::Hyperbolic as u8;
380 assert!(verify_descriptor_against_reality(&desc).is_err());
381 }
382
383 #[test]
384 fn undefined_metric_kind_is_rejected() {
385 let mut desc = proposed_metric_descriptor();
386 desc.branches[0].metric_kind = MetricKind::Undefined as u8;
387 assert!(verify_descriptor_against_reality(&desc).is_err());
388 }
389}