concision_math/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
20    fn elems(&self) -> Self::Item {
21        Self::Item::from_usize(self.len()).unwrap()
22    }
23
24    fn len(&self) -> usize;
25
26    fn mean(&self) -> Self::Output {
27        self.sum() / self.elems()
28    }
29
30    fn product(&self) -> Self::Output;
31
32    fn sum(&self) -> Self::Output;
33
34    fn std(&self) -> Self::Output;
35
36    fn var(&self) -> Self::Output;
37}
38
39/*
40 ************* Implementations *************
41*/
42impl<'a, T, I> SummaryStatistics for &'a I
43where
44    I: Clone + ExactSizeIterator<Item = T>,
45    T: Copy + FromPrimitive + Num + Pow<i32, Output = T> + Product + Root<Output = T> + Sum,
46{
47    type Item = T;
48    type Output = T;
49
50    fn len(&self) -> usize {
51        ExactSizeIterator::len(*self)
52    }
53
54    fn product(&self) -> Self::Output {
55        (*self).clone().product()
56    }
57
58    fn sum(&self) -> Self::Output {
59        (*self).clone().sum()
60    }
61
62    fn std(&self) -> Self::Output {
63        let mean = self.mean();
64        let sum = (*self).clone().map(|x| (x - mean).pow(2)).sum::<T>();
65        (sum / self.elems()).sqrt()
66    }
67
68    fn var(&self) -> Self::Output {
69        let mean = self.mean();
70        let sum = (*self).clone().map(|x| (x - mean).pow(2)).sum::<T>();
71        sum / self.elems()
72    }
73}
74
75macro_rules! impl_summary {
76    ($($T:ty),* $(,)?) => {
77        $(
78            impl_summary!(@impl $T);
79        )*
80    };
81    (@impl $T:ty) => {
82
83        impl<T> SummaryStatistics for $T
84        where
85            T: Copy + FromPrimitive + Num + Pow<i32, Output = T> + Product + Root<Output = T> + Sum,
86        {
87            type Item = T;
88            type Output = T;
89
90            fn len(&self) -> usize {
91                self.len()
92            }
93
94            fn product(&self) -> Self::Output {
95                self.iter().copied().product::<T>()
96            }
97
98            fn sum(&self) -> Self::Output {
99                self.iter().copied().sum::<T>()
100            }
101
102            fn std(&self) -> Self::Output {
103                let mean = self.mean();
104                let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<T>();
105                (sum / self.elems()).sqrt()
106            }
107
108            fn var(&self) -> Self::Output {
109                let mean = self.mean();
110                let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<T>();
111                sum / self.elems()
112            }
113        }
114    };
115}
116
117impl_summary!([T]);
118
119#[cfg(feature = "alloc")]
120impl_summary!(alloc::vec::Vec<T>);
121
122impl<A, S, D> SummaryStatistics for ArrayBase<S, D>
123where
124    A: Copy + FromPrimitive + Num + Pow<i32, Output = A> + Product + Root<Output = A> + Sum,
125    D: Dimension,
126    S: Data<Elem = A>,
127    for<'a> &'a A: Product,
128{
129    type Item = A;
130    type Output = A;
131
132    fn len(&self) -> usize {
133        self.len()
134    }
135
136    fn product(&self) -> Self::Output {
137        self.iter().copied().product::<A>()
138    }
139
140    fn sum(&self) -> Self::Output {
141        self.iter().copied().sum::<A>()
142    }
143
144    fn std(&self) -> Self::Output {
145        let mean = self.mean().unwrap_or_else(A::zero);
146        let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<A>();
147        (sum / self.elems()).sqrt()
148    }
149
150    fn var(&self) -> Self::Output {
151        let mean = self.mean().unwrap_or_else(A::zero);
152        let sum = self.iter().copied().map(|x| (x - mean).pow(2)).sum::<A>();
153        sum / self.elems()
154    }
155}