concision_utils/stats/
summary.rs

1/*
2    Appellation: summary <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use crate::Root;
6use core::iter::{Product, Sum};
7use ndarray::{ArrayBase, Data, Dimension};
8use num::traits::{FromPrimitive, Num, NumOps, Pow};
9
10/// This trait describes the fundamental methods of summary statistics.
11/// These include the mean, standard deviation, variance, and more.
12pub trait SummaryStatistics
13where
14    Self::Item: FromPrimitive,
15    Self::Output: NumOps<Self::Item, Self::Output>,
16{
17    type Item;
18    type Output;
19    /// returns the number of elements in the iterator
20    fn len(&self) -> usize;
21    /// returns the number of elements in the iterator as an [`Item`](Self::Item) type.
22    fn product(&self) -> Self::Output;
23    /// returns the sum of the iterator
24    fn sum(&self) -> Self::Output;
25    /// returns the standard deviation of the iterator
26    fn std(&self) -> Self::Output;
27    /// returns the variance of the iterator
28    fn var(&self) -> Self::Output;
29
30    /// returns the number of elements in the iterator as an [`Item`](Self::Item) type.
31    fn elems(&self) -> Self::Item {
32        Self::Item::from_usize(self.len()).unwrap()
33    }
34    /// returns true if the iterator is empty
35    fn is_empty(&self) -> bool {
36        self.len() == 0
37    }
38    /// returns the mean of the iterator
39    fn mean(&self) -> Self::Output {
40        self.sum() / self.elems()
41    }
42}
43
44/*
45 ************* Implementations *************
46*/
47impl<T, I> SummaryStatistics for &I
48where
49    I: Clone + ExactSizeIterator<Item = T>,
50    T: Copy + FromPrimitive + Num + Pow<i32, Output = T> + Product + Root<Output = T> + Sum,
51{
52    type Item = T;
53    type Output = T;
54
55    fn len(&self) -> usize {
56        ExactSizeIterator::len(*self)
57    }
58
59    fn product(&self) -> Self::Output {
60        (*self).clone().product()
61    }
62
63    fn sum(&self) -> Self::Output {
64        (*self).clone().sum()
65    }
66
67    fn std(&self) -> Self::Output {
68        let mean = self.mean();
69        let sum = (*self).clone().map(|x| (x - mean).pow(2)).sum::<T>();
70        (sum / self.elems()).sqrt()
71    }
72
73    fn var(&self) -> Self::Output {
74        let mean = self.mean();
75        let sum = (*self).clone().map(|x| (x - mean).pow(2)).sum::<T>();
76        sum / self.elems()
77    }
78}
79
80macro_rules! impl_summary {
81    ($($T:ty),* $(,)?) => {
82        $(
83            impl_summary!(@impl $T);
84        )*
85    };
86    (@impl $T:ty) => {
87
88        impl<T> SummaryStatistics for $T
89        where
90            T: Copy + FromPrimitive + Num + Pow<i32, Output = T> + Product + Root<Output = T> + Sum,
91        {
92            type Item = T;
93            type Output = T;
94
95            fn len(&self) -> usize {
96                self.len()
97            }
98
99            fn product(&self) -> Self::Output {
100                self.iter().copied().product::<T>()
101            }
102
103            fn sum(&self) -> Self::Output {
104                self.iter().copied().sum::<T>()
105            }
106
107            fn std(&self) -> Self::Output {
108                let mean = self.mean();
109                let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<T>();
110                (sum / self.elems()).sqrt()
111            }
112
113            fn var(&self) -> Self::Output {
114                let mean = self.mean();
115                let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<T>();
116                sum / self.elems()
117            }
118        }
119    };
120}
121
122impl_summary!([T]);
123
124#[cfg(feature = "alloc")]
125impl_summary!(alloc::vec::Vec<T>);
126
127impl<A, S, D> SummaryStatistics for ArrayBase<S, D>
128where
129    A: Copy + FromPrimitive + Num + Pow<i32, Output = A> + Product + Root<Output = A> + Sum,
130    D: Dimension,
131    S: Data<Elem = A>,
132    for<'a> &'a A: Product,
133{
134    type Item = A;
135    type Output = A;
136
137    fn len(&self) -> usize {
138        self.len()
139    }
140
141    fn product(&self) -> Self::Output {
142        self.iter().copied().product::<A>()
143    }
144
145    fn sum(&self) -> Self::Output {
146        self.iter().copied().sum::<A>()
147    }
148
149    fn std(&self) -> Self::Output {
150        let mean = self.mean().unwrap_or_else(A::zero);
151        let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<A>();
152        (sum / self.elems()).sqrt()
153    }
154
155    fn var(&self) -> Self::Output {
156        let mean = self.mean().unwrap_or_else(A::zero);
157        let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<A>();
158        sum / self.elems()
159    }
160}