|
- use std::collections::VecDeque;
-
- #[derive(Debug, Clone)]
- pub struct WeightedPoint {
- pub time: u64,
- /// value * weight.
- ///
- /// when purging expired items, do not subtract `wt_val * wt`, as `wt_val`
- /// has already been multiplied by `wt`. Instead, simply substract `wt_val`
- /// from `w_sum`.
- pub wt_val: f64,
- pub wt: f64,
- }
-
- #[derive(Clone)]
- pub struct WeightedAvgWindow {
- size: u64,
- items: VecDeque<WeightedPoint>,
- w_sum: f64,
- sum_w: f64,
- //w_mean: f64,
- }
-
- impl WeightedAvgWindow {
- pub fn new(size: u64) -> Self {
- Self {
- size,
- items: Default::default(),
- w_sum: 0.0,
- sum_w: 0.0,
- }
- }
-
- /// Removes expired items and updates incremental calculations.
- ///
- /// Returns `true` if any items were removed.
- pub fn purge(&mut self, time: u64) -> bool {
- let mut n_remove = 0;
-
- {
- let items = &self.items;
- let w_sum = &mut self.w_sum;
- let sum_w = &mut self.sum_w;
- let size = self.size;
-
- for expired in items.iter().take_while(|x| time - x.time > size) {
- *w_sum -= expired.wt_val;
- *sum_w -= expired.wt;
- n_remove += 1;
- }
- }
-
- for _ in 0..n_remove { self.items.pop_front(); }
-
- // when items is empty, set w_sum, sum_w to 0.0
- let zeroer: f64 = ( ! self.items.is_empty()) as u8 as f64;
- self.w_sum *= zeroer;
- self.sum_w *= zeroer;
-
- n_remove > 0
- }
-
- /// Add a new item, updating incremental calculations in the process.
- pub fn push(&mut self, time: u64, val: f64, wt: f64) {
- let wt_val: f64 = val * wt;
- self.w_sum += wt_val;
- self.sum_w += wt;
- self.items.push_back(WeightedPoint { time, wt_val, wt });
- }
-
- /// Calculate the weighted mean from current state of incremental
- /// accumulators.
- ///
- /// Note; this value is not cached.
- pub fn wt_mean(&self) -> f64 {
- self.w_sum / self.sum_w
- }
-
- /// Checks whether items `is_empty` before trying to calculate.
- /// Returns None if items is empty.
- pub fn checked_wt_mean(&self) -> Option<f64> {
- match self.is_empty() {
- true => None,
- false => Some(self.w_sum / self.sum_w),
- }
- }
-
- /// Purge, push and get `checked_wt_mean`, all in one convenient step.
- pub fn update(&mut self, time: u64, val: f64, wt: f64) -> Option<f64> {
- self.purge(time);
- self.push(time, val, wt);
- self.checked_wt_mean()
- }
-
- pub fn len(&self) -> usize { self.items.len() }
-
- pub fn is_empty(&self) -> bool { self.items.is_empty() }
- }
|