#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EnvelopeRegion {
Interior,
Boundary,
Exterior,
}
#[derive(Debug, Clone, Copy)]
pub struct AdmissibilityEnvelope {
pub rho_min: f64,
pub rho_max: f64,
pub delta: f64,
}
impl AdmissibilityEnvelope {
pub fn new(rho_min: f64, rho_max: f64, delta: f64) -> Self {
assert!(rho_min > 0.0, "ρ_min must be positive");
assert!(rho_max >= rho_min, "ρ_max must be ≥ ρ_min");
assert!(delta > 0.0 && delta <= rho_min / 4.0,
"δ must satisfy 0 < δ ≤ ρ_min/4 (Definition 4.1)");
Self { rho_min, rho_max, delta }
}
#[inline]
pub fn classify(&self, magnitude: f64) -> EnvelopeRegion {
if magnitude > self.rho_max + self.delta {
EnvelopeRegion::Exterior
} else if magnitude >= self.rho_max - self.delta {
EnvelopeRegion::Boundary
} else {
EnvelopeRegion::Interior
}
}
}
#[derive(Debug, Clone)]
pub struct EnvelopeFamily {
envelopes: Vec<AdmissibilityEnvelope>,
}
impl EnvelopeFamily {
pub fn new(envelopes: Vec<AdmissibilityEnvelope>) -> Self {
for w in envelopes.windows(2) {
assert!(w[1].rho_max >= w[0].rho_max,
"EnvelopeFamily must be monotonically ordered by ρ_max");
}
Self { envelopes }
}
pub fn get(&self, lambda: usize) -> Option<&AdmissibilityEnvelope> {
self.envelopes.get(lambda)
}
pub fn len(&self) -> usize { self.envelopes.len() }
pub fn is_empty(&self) -> bool { self.envelopes.is_empty() }
}