use crate::stats::{RollableUnivariate, Univariate};
use num::{Float, FromPrimitive};
use std::{
collections::VecDeque,
ops::{AddAssign, SubAssign},
};
pub struct Rolling<'a, U, F>
where
U: RollableUnivariate<F>, F: Float + FromPrimitive + AddAssign + SubAssign,
{
to_roll: &'a mut U, window_size: usize,
window: VecDeque<F>,
}
impl<'a, U, F> Rolling<'a, U, F>
where
U: RollableUnivariate<F>,
F: Float + FromPrimitive + AddAssign + SubAssign,
{
pub fn new(to_roll: &'a mut U, window_size: usize) -> Result<Self, &'static str> { if window_size == 0 {
return Err("Window size should not equal to 0");
}
Ok(Self {
to_roll,
window_size,
window: VecDeque::with_capacity(window_size), })
}
}
impl<'a, U, F> Univariate<F> for Rolling<'a, U, F>
where
U: RollableUnivariate<F>,
F: Float + FromPrimitive + AddAssign + SubAssign,
{
fn update(&mut self, x: F) {
if self.window.len() == self.window_size {
let oldest = self.window.front().copied().expect("Window should not be empty"); match self.to_roll.revert(oldest) {
Ok(()) => (), 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);
}
}