radiate_core/stats/
distribution.rs

1use crate::Statistic;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Clone, PartialEq, Default)]
7#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8pub struct Distribution {
9    pub statistic: Statistic,
10    pub last_sequence: Vec<f32>,
11}
12
13impl Distribution {
14    #[inline(always)]
15    pub fn push(&mut self, value: f32) {
16        self.statistic.add(value);
17        self.last_sequence.push(value);
18    }
19
20    #[inline(always)]
21    pub fn add(&mut self, value: &[f32]) {
22        self.clear();
23        for v in value {
24            self.statistic.add(*v);
25            self.last_sequence.push(*v);
26        }
27    }
28
29    pub fn last_sequence(&self) -> &Vec<f32> {
30        &self.last_sequence
31    }
32
33    pub fn count(&self) -> i32 {
34        self.last_sequence.len() as i32
35    }
36
37    pub fn mean(&self) -> f32 {
38        self.statistic.mean()
39    }
40
41    pub fn variance(&self) -> f32 {
42        self.statistic.variance()
43    }
44
45    pub fn standard_deviation(&self) -> f32 {
46        self.statistic.std_dev()
47    }
48
49    pub fn skewness(&self) -> f32 {
50        self.statistic.skewness()
51    }
52
53    pub fn kurtosis(&self) -> f32 {
54        self.statistic.kurtosis()
55    }
56
57    pub fn min(&self) -> f32 {
58        self.statistic.min()
59    }
60
61    pub fn max(&self) -> f32 {
62        self.statistic.max()
63    }
64
65    pub fn clear(&mut self) {
66        self.last_sequence.clear();
67    }
68
69    pub fn log2(&self) -> f32 {
70        (self.last_sequence().len() as f32).log2()
71    }
72
73    #[inline(always)]
74    pub fn entropy(&self) -> f32 {
75        let bin_width = 0.01;
76        let mut counts = HashMap::new();
77
78        for &value in &self.last_sequence {
79            let bin = (value / bin_width).floor();
80            *counts.entry(bin as i32).or_insert(0) += 1;
81        }
82
83        let total = self.last_sequence.len() as f32;
84        if total == 0.0 {
85            return 0.0;
86        }
87
88        counts
89            .values()
90            .map(|&count| {
91                let p = count as f32 / total;
92                -p * p.log2()
93            })
94            .sum()
95    }
96
97    #[inline(always)]
98    pub fn percentile(&self, p: f32) -> f32 {
99        if p < 0.0 || p > 100.0 {
100            panic!("Percentile must be between 0 and 100");
101        }
102
103        let count = self.last_sequence.len() as f32;
104        if count == 0 as f32 {
105            panic!("Cannot calculate percentile for an empty distribution");
106        }
107        let index = (p / 100.0) * count;
108        let sorted_values = {
109            let mut values = self.last_sequence.clone();
110            values.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
111            values
112        };
113
114        let index = index as usize;
115        if index >= sorted_values.len() {
116            panic!("Index out of bounds for the sorted values");
117        }
118
119        sorted_values[index]
120    }
121}
122
123impl From<&[f32]> for Distribution {
124    fn from(value: &[f32]) -> Self {
125        let mut result = Distribution::default();
126        result.add(value);
127        result
128    }
129}
130
131impl From<Vec<f32>> for Distribution {
132    fn from(value: Vec<f32>) -> Self {
133        let mut result = Distribution::default();
134        result.add(&value);
135        result
136    }
137}