1use crate::error::SpotResult;
7
8use crate::ubend::Ubend;
9
10#[derive(Debug, Clone)]
12pub struct Peaks {
13 e: f64,
15 e2: f64,
17 min: f64,
19 max: f64,
21 container: Ubend,
23}
24
25impl Peaks {
26 pub fn new(size: usize) -> SpotResult<Self> {
28 Ok(Self {
29 e: 0.0,
30 e2: 0.0,
31 min: f64::NAN,
32 max: f64::NAN,
33 container: Ubend::new(size)?,
34 })
35 }
36
37 pub fn size(&self) -> usize {
39 self.container.size()
40 }
41
42 pub fn push(&mut self, x: f64) {
44 let erased = self.container.push(x);
45 let size = self.size();
46
47 self.e += x;
49 self.e2 += x * x;
50
51 if size == 1 || x < self.min {
53 self.min = x;
54 }
55 if size == 1 || x > self.max {
56 self.max = x;
57 }
58
59 if !erased.is_nan() {
62 self.e -= erased;
63 self.e2 -= erased * erased;
64 if (erased <= self.min) || (erased >= self.max) {
65 self.update_stats();
69 }
70 }
71 }
72
73 pub fn mean(&self) -> f64 {
75 let size = self.size();
76 if size == 0 {
77 f64::NAN
78 } else {
79 self.e / (size as f64)
80 }
81 }
82
83 pub fn variance(&self) -> f64 {
85 let size = self.size();
86 if size == 0 {
87 f64::NAN
88 } else {
89 let size_f = size as f64;
90 let mean = self.e / size_f;
91 (self.e2 / size_f) - (mean * mean)
92 }
93 }
94
95 pub fn min(&self) -> f64 {
97 self.min
98 }
99
100 pub fn max(&self) -> f64 {
102 self.max
103 }
104
105 pub fn sum(&self) -> f64 {
107 self.e
108 }
109
110 pub fn sum_squares(&self) -> f64 {
112 self.e2
113 }
114
115 pub fn container(&self) -> &Ubend {
117 &self.container
118 }
119
120 fn update_stats(&mut self) {
123 self.min = f64::NAN;
125 self.max = f64::NAN;
126 self.e = 0.0;
128 self.e2 = 0.0;
129
130 let max_iteration = self.container.size();
131
132 for i in 0..max_iteration {
133 let value = self.container.raw_data()[i];
135 self.e += value;
136 self.e2 += value * value;
137
138 if self.min.is_nan() || (value < self.min) {
139 self.min = value;
140 }
141 if self.max.is_nan() || (value > self.max) {
142 self.max = value;
143 }
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::error::SpotError;
152 use approx::assert_relative_eq;
153
154 #[test]
155 fn test_peaks_creation() {
156 let peaks = Peaks::new(5).unwrap();
157 assert_eq!(peaks.size(), 0);
158 assert_relative_eq!(peaks.sum(), 0.0);
159 assert_relative_eq!(peaks.sum_squares(), 0.0);
160 assert!(peaks.min().is_nan());
161 assert!(peaks.max().is_nan());
162 assert!(peaks.mean().is_nan());
163 assert!(peaks.variance().is_nan());
164 }
165
166 #[test]
167 fn test_peaks_zero_size() {
168 let result = Peaks::new(0);
169 assert!(result.is_err());
170 assert_eq!(result.unwrap_err(), SpotError::MemoryAllocationFailed);
171 }
172
173 #[test]
174 fn test_peaks_single_element() {
175 let mut peaks = Peaks::new(3).unwrap();
176
177 peaks.push(5.0);
178 assert_eq!(peaks.size(), 1);
179 assert_relative_eq!(peaks.sum(), 5.0);
180 assert_relative_eq!(peaks.sum_squares(), 25.0);
181 assert_relative_eq!(peaks.min(), 5.0);
182 assert_relative_eq!(peaks.max(), 5.0);
183 assert_relative_eq!(peaks.mean(), 5.0);
184 assert_relative_eq!(peaks.variance(), 0.0);
185 }
186
187 #[test]
188 fn test_peaks_multiple_elements() {
189 let mut peaks = Peaks::new(5).unwrap();
190
191 peaks.push(1.0);
192 peaks.push(2.0);
193 peaks.push(3.0);
194
195 assert_eq!(peaks.size(), 3);
196 assert_relative_eq!(peaks.sum(), 6.0);
197 assert_relative_eq!(peaks.sum_squares(), 14.0);
198 assert_relative_eq!(peaks.min(), 1.0);
199 assert_relative_eq!(peaks.max(), 3.0);
200 assert_relative_eq!(peaks.mean(), 2.0);
201
202 assert_relative_eq!(peaks.variance(), 2.0 / 3.0, epsilon = 1e-14);
204 }
205
206 #[test]
207 fn test_peaks_overflow_and_min_max_update() {
208 let mut peaks = Peaks::new(3).unwrap();
209
210 peaks.push(1.0); peaks.push(2.0); peaks.push(3.0); assert_relative_eq!(peaks.min(), 1.0);
216 assert_relative_eq!(peaks.max(), 3.0);
217
218 peaks.push(0.5); assert_eq!(peaks.size(), 3);
222 assert_relative_eq!(peaks.min(), 0.5);
223 assert_relative_eq!(peaks.max(), 3.0);
224 assert_relative_eq!(peaks.sum(), 5.5);
225
226 peaks.push(4.0); assert_relative_eq!(peaks.min(), 0.5);
230 assert_relative_eq!(peaks.max(), 4.0);
231 assert_relative_eq!(peaks.sum(), 7.5);
232 }
233
234 #[test]
235 fn test_peaks_stats_after_min_erasure() {
236 let mut peaks = Peaks::new(3).unwrap();
237
238 peaks.push(2.0);
240 peaks.push(1.0); peaks.push(3.0);
242
243 assert_relative_eq!(peaks.min(), 1.0);
244 assert_relative_eq!(peaks.max(), 3.0);
245
246 peaks.push(2.5); assert_relative_eq!(peaks.min(), 1.0); assert_relative_eq!(peaks.max(), 3.0); peaks.push(2.7); assert_relative_eq!(peaks.min(), 2.5);
257 assert_relative_eq!(peaks.max(), 3.0);
258 }
259
260 #[test]
261 fn test_peaks_stats_after_max_erasure() {
262 let mut peaks = Peaks::new(3).unwrap();
263
264 peaks.push(1.0);
266 peaks.push(3.0); peaks.push(2.0);
268
269 assert_relative_eq!(peaks.min(), 1.0);
270 assert_relative_eq!(peaks.max(), 3.0);
271
272 peaks.push(1.5); peaks.push(1.7); assert_relative_eq!(peaks.min(), 1.5);
278 assert_relative_eq!(peaks.max(), 2.0);
279 }
280}