#[derive(Debug, Clone, PartialEq)]
pub struct ControlLimits {
pub ucl: f64,
pub cl: f64,
pub lcl: f64,
}
#[derive(Debug, Clone)]
pub struct ChartPoint {
pub value: f64,
pub index: usize,
pub violations: Vec<ViolationType>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ViolationType {
BeyondLimits,
NineOneSide,
SixTrend,
FourteenAlternating,
TwoOfThreeBeyond2Sigma,
FourOfFiveBeyond1Sigma,
FifteenWithin1Sigma,
EightBeyond1Sigma,
}
#[derive(Debug, Clone)]
pub struct Violation {
pub point_index: usize,
pub violation_type: ViolationType,
}
pub trait ControlChart {
fn add_sample(&mut self, sample: &[f64]);
fn control_limits(&self) -> Option<ControlLimits>;
fn is_in_control(&self) -> bool;
fn violations(&self) -> Vec<Violation>;
fn points(&self) -> &[ChartPoint];
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_control_limits_construction() {
let limits = ControlLimits {
ucl: 30.0,
cl: 25.0,
lcl: 20.0,
};
assert!((limits.ucl - 30.0).abs() < f64::EPSILON);
assert!((limits.cl - 25.0).abs() < f64::EPSILON);
assert!((limits.lcl - 20.0).abs() < f64::EPSILON);
}
#[test]
fn test_chart_point_construction() {
let point = ChartPoint {
value: 25.5,
index: 0,
violations: vec![ViolationType::BeyondLimits],
};
assert!((point.value - 25.5).abs() < f64::EPSILON);
assert_eq!(point.index, 0);
assert_eq!(point.violations.len(), 1);
assert_eq!(point.violations[0], ViolationType::BeyondLimits);
}
#[test]
fn test_violation_type_equality() {
assert_eq!(ViolationType::BeyondLimits, ViolationType::BeyondLimits);
assert_ne!(ViolationType::BeyondLimits, ViolationType::NineOneSide);
}
#[test]
fn test_violation_construction() {
let v = Violation {
point_index: 5,
violation_type: ViolationType::SixTrend,
};
assert_eq!(v.point_index, 5);
assert_eq!(v.violation_type, ViolationType::SixTrend);
}
#[test]
fn test_control_limits_clone() {
let limits = ControlLimits {
ucl: 30.0,
cl: 25.0,
lcl: 20.0,
};
let cloned = limits.clone();
assert_eq!(limits, cloned);
}
}