concision_traits/math/
stats.rs

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