llm_optimizer_processor/aggregation/
avg.rs1use super::trait_::{Aggregator, ToF64};
2use anyhow::anyhow;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct AverageAccumulator {
8 sum: f64,
9 count: u64,
10}
11
12#[derive(Debug, Clone)]
30pub struct AverageAggregator<T> {
31 sum: f64,
32 count: u64,
33 _phantom: std::marker::PhantomData<T>,
34}
35
36impl<T: ToF64 + Clone> AverageAggregator<T> {
37 pub fn new() -> Self {
39 Self {
40 sum: 0.0,
41 count: 0,
42 _phantom: std::marker::PhantomData,
43 }
44 }
45
46 pub fn mean(&self) -> Option<f64> {
48 if self.count == 0 {
49 None
50 } else {
51 Some(self.sum / self.count as f64)
52 }
53 }
54}
55
56impl<T: ToF64 + Clone> Default for AverageAggregator<T> {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl<T: ToF64 + Clone + Send + Sync + std::fmt::Debug> Aggregator for AverageAggregator<T> {
63 type Input = T;
64 type Output = f64;
65 type Accumulator = AverageAccumulator;
66
67 fn new() -> Self {
68 Self::new()
69 }
70
71 fn update(&mut self, value: <Self as Aggregator>::Input) -> anyhow::Result<()> {
72 self.sum += value.to_f64();
73 self.count += 1;
74 Ok(())
75 }
76
77 fn finalize(&self) -> anyhow::Result<<Self as Aggregator>::Output> {
78 if self.count == 0 {
79 return Err(anyhow!("Cannot compute average of zero values"));
80 }
81 Ok(self.sum / self.count as f64)
82 }
83
84 fn accumulator(&self) -> <Self as Aggregator>::Accumulator {
85 AverageAccumulator {
86 sum: self.sum,
87 count: self.count,
88 }
89 }
90
91 fn merge(&mut self, other: <Self as Aggregator>::Accumulator) -> anyhow::Result<()> {
92 self.sum += other.sum;
93 self.count += other.count;
94 Ok(())
95 }
96
97 fn reset(&mut self) {
98 self.sum = 0.0;
99 self.count = 0;
100 }
101
102 fn count(&self) -> u64 {
103 self.count
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_avg_basic() {
113 let mut agg = AverageAggregator::<f64>::new();
114 assert_eq!(agg.count(), 0);
115 assert!(agg.is_empty());
116
117 agg.update(10.0).unwrap();
118 agg.update(20.0).unwrap();
119 agg.update(30.0).unwrap();
120
121 assert_eq!(agg.count(), 3);
122 assert_eq!(agg.finalize().unwrap(), 20.0);
123 assert_eq!(agg.mean().unwrap(), 20.0);
124 }
125
126 #[test]
127 fn test_avg_batch() {
128 let mut agg = AverageAggregator::<f64>::new();
129 agg.update_batch(&[10.0, 20.0, 30.0, 40.0, 50.0]).unwrap();
130
131 assert_eq!(agg.count(), 5);
132 assert_eq!(agg.finalize().unwrap(), 30.0);
133 }
134
135 #[test]
136 fn test_avg_merge() {
137 let mut agg1 = AverageAggregator::<f64>::new();
138 agg1.update(10.0).unwrap();
139 agg1.update(20.0).unwrap();
140 let mut agg2 = AverageAggregator::<f64>::new();
143 agg2.update(30.0).unwrap();
144 agg2.update(40.0).unwrap();
145 agg2.update(50.0).unwrap();
146 let acc2 = agg2.accumulator();
149 agg1.merge(acc2).unwrap();
150
151 assert_eq!(agg1.finalize().unwrap(), 30.0);
153 assert_eq!(agg1.count(), 5);
154 }
155
156 #[test]
157 fn test_avg_reset() {
158 let mut agg = AverageAggregator::<f64>::new();
159 agg.update(10.0).unwrap();
160 agg.update(20.0).unwrap();
161
162 assert_eq!(agg.finalize().unwrap(), 15.0);
163
164 agg.reset();
165 assert_eq!(agg.count(), 0);
166 assert!(agg.mean().is_none());
167 }
168
169 #[test]
170 fn test_avg_serialization() {
171 let mut agg = AverageAggregator::<f64>::new();
172 agg.update(10.0).unwrap();
173 agg.update(20.0).unwrap();
174
175 let acc = agg.accumulator();
176 let serialized = serde_json::to_string(&acc).unwrap();
177 let deserialized: AverageAccumulator = serde_json::from_str(&serialized).unwrap();
178
179 assert_eq!(acc, deserialized);
180 assert_eq!(deserialized.sum, 30.0);
181 assert_eq!(deserialized.count, 2);
182 }
183
184 #[test]
185 fn test_avg_with_different_types() {
186 let mut agg = AverageAggregator::<i64>::new();
188 agg.update(10).unwrap();
189 agg.update(20).unwrap();
190 agg.update(30).unwrap();
191 assert_eq!(agg.finalize().unwrap(), 20.0);
192
193 let mut agg = AverageAggregator::<f32>::new();
195 agg.update(1.5).unwrap();
196 agg.update(2.5).unwrap();
197 assert_eq!(agg.finalize().unwrap(), 2.0);
198 }
199
200 #[test]
201 fn test_avg_empty() {
202 let agg = AverageAggregator::<f64>::new();
203 assert!(agg.finalize().is_err());
204 assert!(agg.mean().is_none());
205 }
206
207 #[test]
208 fn test_avg_single_value() {
209 let mut agg = AverageAggregator::<f64>::new();
210 agg.update(42.0).unwrap();
211 assert_eq!(agg.finalize().unwrap(), 42.0);
212 }
213
214 #[test]
215 fn test_avg_negative_values() {
216 let mut agg = AverageAggregator::<f64>::new();
217 agg.update(-10.0).unwrap();
218 agg.update(10.0).unwrap();
219 agg.update(20.0).unwrap();
220
221 assert_eq!(agg.finalize().unwrap(), 20.0 / 3.0);
222 }
223}