#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PageHinkleyChange {
Increase,
Decrease,
}
#[derive(Clone, Debug)]
pub struct PageHinkleyDetector {
delta: f64,
lambda: f64,
n: u64,
mean: f64,
m_inc: f64,
min_inc: f64,
m_dec: f64,
max_dec: f64,
}
impl PageHinkleyDetector {
pub fn new(delta: f64, lambda: f64) -> Self {
Self {
delta,
lambda,
n: 0,
mean: 0.0,
m_inc: 0.0,
min_inc: 0.0,
m_dec: 0.0,
max_dec: 0.0,
}
}
pub fn update(&mut self, x: f64) -> Option<PageHinkleyChange> {
if !x.is_finite() {
return None;
}
self.n += 1;
self.mean += (x - self.mean) / self.n as f64;
self.m_inc += x - self.mean - self.delta;
self.min_inc = self.min_inc.min(self.m_inc);
self.m_dec += x - self.mean + self.delta;
self.max_dec = self.max_dec.max(self.m_dec);
let ph_inc = self.m_inc - self.min_inc;
let ph_dec = self.max_dec - self.m_dec;
if ph_inc > self.lambda {
self.reset();
Some(PageHinkleyChange::Increase)
} else if ph_dec > self.lambda {
self.reset();
Some(PageHinkleyChange::Decrease)
} else {
None
}
}
pub fn samples_since_reset(&self) -> u64 {
self.n
}
pub fn reset(&mut self) {
self.n = 0;
self.mean = 0.0;
self.m_inc = 0.0;
self.min_inc = 0.0;
self.m_dec = 0.0;
self.max_dec = 0.0;
}
}