sim_lib_interference_solve/verification.rs
1//! Public measurements and diagnostics for reference verification.
2
3use std::fmt;
4
5use crate::ReferenceSolveError;
6
7/// Largest relative error admitted for the closed-form analytic checks.
8pub const MAX_ANALYTIC_RELATIVE_ERROR: f64 = 1.0e-12;
9
10/// Largest relative error admitted for a metamorphic field law.
11pub const MAX_METAMORPHIC_RELATIVE_ERROR: f64 = 1.0e-12;
12
13/// Complete measurements from the deterministic reference verification suite.
14///
15/// The Helmholtz value is the matrix member farthest from ideal second-order
16/// convergence. Every matrix member is checked before a report is returned.
17#[derive(Clone, Copy, Debug, PartialEq)]
18pub struct VerificationReport {
19 /// Largest relative error across the analytic identities and time-sign check.
20 pub analytic_max_error: f64,
21 /// Relative point Green-function reciprocity error.
22 pub reciprocity_relative: f64,
23 /// Largest relative superposition error.
24 pub linearity_relative: f64,
25 /// Largest relative error after a shared rotation and translation.
26 pub rigid_motion_relative: f64,
27 /// Largest relative error after rotating every phasor by one phase.
28 pub global_phase_relative: f64,
29 /// Whether every source input permutation produced identical component bits.
30 pub source_permutation_identical: bool,
31 /// Observed residual order farthest from ideal order two in the fixture matrix.
32 pub helmholtz_observed_order: f64,
33}
34
35/// A deterministic verification suite failed before producing a passing report.
36#[derive(Clone, Debug, PartialEq)]
37pub enum VerificationError {
38 /// A checked fixture or reference solve was refused.
39 Reference {
40 /// Exact reference-solver diagnostic.
41 cause: Box<ReferenceSolveError>,
42 },
43 /// A measured analytic or metamorphic error exceeded its declared limit.
44 RelativeErrorExceeded {
45 /// Stable verification check name.
46 check: &'static str,
47 /// Measured relative error.
48 measured: f64,
49 /// Largest accepted relative error.
50 limit: f64,
51 },
52 /// Canonical source permutations changed the field's component bits.
53 SourcePermutationChanged,
54 /// One named Helmholtz fixture did not exhibit second-order convergence.
55 HelmholtzOrderOutOfRange {
56 /// Stable fixture name.
57 fixture: &'static str,
58 /// Measured convergence order.
59 observed: f64,
60 /// Inclusive lower bound.
61 minimum: f64,
62 /// Inclusive upper bound.
63 maximum: f64,
64 },
65}
66
67impl From<ReferenceSolveError> for VerificationError {
68 fn from(cause: ReferenceSolveError) -> Self {
69 Self::Reference {
70 cause: Box::new(cause),
71 }
72 }
73}
74
75impl fmt::Display for VerificationError {
76 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77 match self {
78 Self::Reference { cause } => write!(formatter, "verification fixture failed: {cause}"),
79 Self::RelativeErrorExceeded {
80 check,
81 measured,
82 limit,
83 } => write!(
84 formatter,
85 "verification check `{check}` measured relative error {measured:e}, \
86 exceeding {limit:e}"
87 ),
88 Self::SourcePermutationChanged => {
89 formatter.write_str("canonical source permutations changed field component bits")
90 }
91 Self::HelmholtzOrderOutOfRange {
92 fixture,
93 observed,
94 minimum,
95 maximum,
96 } => write!(
97 formatter,
98 "Helmholtz fixture `{fixture}` observed order {observed}, outside \
99 [{minimum}, {maximum}]"
100 ),
101 }
102 }
103}
104
105impl std::error::Error for VerificationError {
106 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
107 match self {
108 Self::Reference { cause } => Some(cause.as_ref()),
109 Self::RelativeErrorExceeded { .. }
110 | Self::SourcePermutationChanged
111 | Self::HelmholtzOrderOutOfRange { .. } => None,
112 }
113 }
114}