use crate::error::RobustError;
use crate::scale::ScaleEstimator;
use crate::types::Scale;
#[derive(Debug, Clone, Copy)]
pub struct Mad {
pub consistency: f64,
}
impl Default for Mad {
fn default() -> Self {
Self {
consistency: 1.482_602_218_505_602,
}
}
}
impl ScaleEstimator for Mad {
fn scale(&self, residuals: &[f64]) -> Result<Scale, RobustError> {
if residuals.is_empty() {
return Err(RobustError::InsufficientData { needed: 1, got: 0 });
}
let mut buf = residuals.to_vec();
let center = median(&mut buf);
for x in buf.iter_mut() {
*x = (*x - center).abs(); }
let mad = median(&mut buf);
let s = mad * self.consistency;
if !s.is_finite() || s <= 0.0 {
return Err(RobustError::DegenerateScale);
}
Scale::new(s)
}
}
fn median(v: &mut [f64]) -> f64 {
v.sort_unstable_by(f64::total_cmp);
let n = v.len();
let mid = n / 2;
if n % 2 == 1 {
v[mid]
} else {
0.5 * (v[mid - 1] + v[mid])
}
}