use crate::sign::ResidualSign;
use crate::envelope::{AdmissibilityEnvelope, EnvelopeRegion};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GrammarState {
Admissible,
Boundary,
Violation,
}
impl GrammarState {
#[inline]
pub fn is_non_nominal(&self) -> bool {
!matches!(self, GrammarState::Admissible)
}
#[inline]
pub fn is_violation(&self) -> bool {
matches!(self, GrammarState::Violation)
}
}
impl std::fmt::Display for GrammarState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GrammarState::Admissible => write!(f, "Adm"),
GrammarState::Boundary => write!(f, "Bdy"),
GrammarState::Violation => write!(f, "Vio"),
}
}
}
#[derive(Debug, Clone)]
pub struct GrammarFsm {
state: GrammarState,
persistence: usize,
}
impl GrammarFsm {
pub fn new() -> Self {
Self { state: GrammarState::Admissible, persistence: 0 }
}
pub fn state(&self) -> GrammarState { self.state }
pub fn persistence(&self) -> usize { self.persistence }
pub fn step(&mut self, sign: &ResidualSign, envelope: &AdmissibilityEnvelope) -> GrammarState {
let region = envelope.classify(sign.magnitude);
let next = match region {
EnvelopeRegion::Interior => GrammarState::Admissible,
EnvelopeRegion::Boundary => GrammarState::Boundary,
EnvelopeRegion::Exterior => GrammarState::Violation,
};
if next == self.state {
self.persistence = self.persistence.saturating_add(1);
} else {
self.persistence = 0;
}
self.state = next;
next
}
}
impl Default for GrammarFsm {
fn default() -> Self { Self::new() }
}