use crate::stats::{RollableUnivariate, Univariate};
use num::{Float, FromPrimitive};
use std::{
collections::VecDeque,
ops::{AddAssign, SubAssign},
};
pub struct Rolling<'a, F: Float + FromPrimitive + AddAssign + SubAssign> {
to_roll: &'a mut dyn RollableUnivariate<F>,
window_size: usize,
window: VecDeque<F>,
}
impl<'a, F: Float + FromPrimitive + AddAssign + SubAssign> Rolling<'a, F> {
pub fn new(
to_roll: &'a mut dyn RollableUnivariate<F>,
window_size: usize,
) -> Result<Self, &str> {
if window_size == 0 {
return Err("Window size should not equals to 0");
}
Ok(Self {
to_roll,
window_size,
window: VecDeque::new(),
})
}
}
impl<'a, F: Float + FromPrimitive + AddAssign + SubAssign> Univariate<F> for Rolling<'_, F> {
fn update(&mut self, x: F) {
if self.window.len() == self.window_size {
match self.to_roll.revert(*self.window.front().unwrap()) {
Ok(it) => it,
Err(err) => panic!("{}", err),
};
self.window.pop_front();
self.window.push_back(x);
} else {
self.window.push_back(x);
}
self.to_roll.update(x);
}
fn get(&self) -> F {
self.to_roll.get()
}
}
mod tests {
#[test]
fn it_works() {
use crate::rolling::Rolling;
use crate::stats::Univariate;
use crate::variance::Variance;
let data = vec![9., 7., 3., 2., 6., 1., 8., 5., 4.];
let mut running_var: Variance<f64> = Variance::default();
let mut rolling_var: Rolling<f64> = Rolling::new(&mut running_var, 2).unwrap();
for x in data.iter() {
rolling_var.update(*x as f64);
}
assert_eq!(rolling_var.get(), 0.5);
}
}