vec_utilities/running/
mod.rs

1// See https://nullbuffer.com/articles/welford_algorithm.html
2
3use num::Float;
4
5// TODO: These would actually be way better as iterators
6
7// Running Sum
8pub struct RunningSum<'a, T: Float + 'a, I: Iterator<Item = &'a T>> {
9    iter: I,
10    sum: T,
11}
12
13impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> RunningSum<'a, T, I> {
14    pub fn new(iter: I) -> Self {
15        return Self {
16            iter: iter,
17            sum: T::zero(),
18        };
19    }
20}
21
22impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> Iterator for RunningSum<'a, T, I> {
23    type Item = T;
24
25    fn next(&mut self) -> Option<Self::Item> {
26        match self.iter.next() {
27            Some(x) => {
28                self.sum = self.sum + *x;
29
30                return Some(self.sum);
31            }
32            None => return None,
33        }
34    }
35}
36
37// Running Mean
38pub struct RunningMean<'a, T: Float + 'a, I: Iterator<Item = &'a T>> {
39    iter: I,
40    m: T,
41    k: T,
42}
43
44impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> RunningMean<'a, T, I> {
45    pub fn new(iter: I) -> Self {
46        return Self {
47            iter,
48            m: T::zero(),
49            k: T::one(),
50        };
51    }
52}
53
54impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> Iterator for RunningMean<'a, T, I> {
55    type Item = T;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        match self.iter.next() {
59            Some(x) => {
60                self.m = self.m + (*x - self.m) / self.k;
61                self.k = self.k + T::one();
62
63                return Some(self.m);
64            }
65            None => return None,
66        }
67    }
68}
69
70// Running Std
71pub struct RunningStd<'a, T: Float + 'a, I: Iterator<Item = &'a T>> {
72    iter: I,
73    n: T,
74    mean: T,
75    m2: T,
76}
77
78impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> RunningStd<'a, T, I> {
79    pub fn new(iter: I) -> Self {
80        return Self {
81            iter,
82            n: T::zero(),
83            mean: T::zero(),
84            m2: T::zero(),
85        };
86    }
87}
88
89impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> Iterator for RunningStd<'a, T, I> {
90    type Item = T;
91
92    fn next(&mut self) -> Option<Self::Item> {
93        match self.iter.next() {
94            Some(x) => {
95                self.n = self.n + T::one();
96                let delta = *x - self.mean;
97                self.mean = self.mean + (delta / self.n);
98                let delta2 = *x - self.mean;
99                self.m2 = self.m2 + (delta * delta2);
100
101                if self.n < T::from(2.0).unwrap() {
102                    return Some(T::zero());
103                } else {
104                    return Some((self.m2 / (self.n - T::one())).sqrt());
105                }
106            }
107            None => return None,
108        }
109    }
110}
111
112// Use the `Running` trait
113pub trait Running<'a, T: Float + 'a, I: Iterator<Item = &'a T>> {
114    fn running_sum(self) -> RunningSum<'a, T, I>;
115    fn running_mean(self) -> RunningMean<'a, T, I>;
116    fn running_std(self) -> RunningStd<'a, T, I>;
117}
118
119impl<'a, T: Float + 'a, I: Iterator<Item = &'a T>> Running<'a, T, I> for I {
120    fn running_sum(self) -> RunningSum<'a, T, I> {
121        RunningSum::new(self)
122    }
123
124    fn running_mean(self) -> RunningMean<'a, T, I> {
125        RunningMean::new(self)
126    }
127
128    fn running_std(self) -> RunningStd<'a, T, I> {
129        RunningStd::new(self)
130    }
131}