radiate_core/stats/
distribution.rs1use 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}