llm_optimizer_processor/aggregation/
sum.rs1use super::trait_::{Aggregator, ToF64};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct SumAccumulator {
8 sum: f64,
9 count: u64,
10}
11
12#[derive(Debug, Clone)]
30pub struct SumAggregator<T> {
31 sum: f64,
32 count: u64,
33 _phantom: std::marker::PhantomData<T>,
34}
35
36impl<T: ToF64 + Clone> SumAggregator<T> {
37 pub fn new() -> Self {
39 Self {
40 sum: 0.0,
41 count: 0,
42 _phantom: std::marker::PhantomData,
43 }
44 }
45}
46
47impl<T: ToF64 + Clone> Default for SumAggregator<T> {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl<T: ToF64 + Clone + Send + Sync + std::fmt::Debug> Aggregator for SumAggregator<T> {
54 type Input = T;
55 type Output = f64;
56 type Accumulator = SumAccumulator;
57
58 fn new() -> Self {
59 Self::new()
60 }
61
62 fn update(&mut self, value: <Self as Aggregator>::Input) -> anyhow::Result<()> {
63 self.sum += value.to_f64();
64 self.count += 1;
65 Ok(())
66 }
67
68 fn finalize(&self) -> anyhow::Result<<Self as Aggregator>::Output> {
69 Ok(self.sum)
70 }
71
72 fn accumulator(&self) -> <Self as Aggregator>::Accumulator {
73 SumAccumulator {
74 sum: self.sum,
75 count: self.count,
76 }
77 }
78
79 fn merge(&mut self, other: <Self as Aggregator>::Accumulator) -> anyhow::Result<()> {
80 self.sum += other.sum;
81 self.count += other.count;
82 Ok(())
83 }
84
85 fn reset(&mut self) {
86 self.sum = 0.0;
87 self.count = 0;
88 }
89
90 fn count(&self) -> u64 {
91 self.count
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_sum_basic() {
101 let mut agg = SumAggregator::<f64>::new();
102 assert_eq!(agg.count(), 0);
103 assert!(agg.is_empty());
104
105 agg.update(1.0).unwrap();
106 agg.update(2.0).unwrap();
107 agg.update(3.0).unwrap();
108
109 assert_eq!(agg.count(), 3);
110 assert_eq!(agg.finalize().unwrap(), 6.0);
111 }
112
113 #[test]
114 fn test_sum_batch() {
115 let mut agg = SumAggregator::<f64>::new();
116 agg.update_batch(&[1.0, 2.0, 3.0, 4.0, 5.0]).unwrap();
117
118 assert_eq!(agg.count(), 5);
119 assert_eq!(agg.finalize().unwrap(), 15.0);
120 }
121
122 #[test]
123 fn test_sum_merge() {
124 let mut agg1 = SumAggregator::<i32>::new();
125 agg1.update(1).unwrap();
126 agg1.update(2).unwrap();
127
128 let mut agg2 = SumAggregator::<i32>::new();
129 agg2.update(3).unwrap();
130 agg2.update(4).unwrap();
131 agg2.update(5).unwrap();
132
133 let acc2 = agg2.accumulator();
134 agg1.merge(acc2).unwrap();
135
136 assert_eq!(agg1.finalize().unwrap(), 15.0);
137 assert_eq!(agg1.count(), 5);
138 }
139
140 #[test]
141 fn test_sum_reset() {
142 let mut agg = SumAggregator::<f64>::new();
143 agg.update(1.0).unwrap();
144 agg.update(2.0).unwrap();
145
146 assert_eq!(agg.finalize().unwrap(), 3.0);
147
148 agg.reset();
149 assert_eq!(agg.count(), 0);
150 assert_eq!(agg.finalize().unwrap(), 0.0);
151 }
152
153 #[test]
154 fn test_sum_serialization() {
155 let mut agg = SumAggregator::<f64>::new();
156 agg.update(1.5).unwrap();
157 agg.update(2.5).unwrap();
158
159 let acc = agg.accumulator();
160 let serialized = serde_json::to_string(&acc).unwrap();
161 let deserialized: SumAccumulator = serde_json::from_str(&serialized).unwrap();
162
163 assert_eq!(acc, deserialized);
164 assert_eq!(deserialized.sum, 4.0);
165 assert_eq!(deserialized.count, 2);
166 }
167
168 #[test]
169 fn test_sum_with_different_types() {
170 let mut agg = SumAggregator::<i64>::new();
172 agg.update(10).unwrap();
173 agg.update(20).unwrap();
174 agg.update(30).unwrap();
175 assert_eq!(agg.finalize().unwrap(), 60.0);
176
177 let mut agg = SumAggregator::<f32>::new();
179 agg.update(1.5).unwrap();
180 agg.update(2.5).unwrap();
181 assert_eq!(agg.finalize().unwrap(), 4.0);
182 }
183
184 #[test]
185 fn test_sum_negative_values() {
186 let mut agg = SumAggregator::<f64>::new();
187 agg.update(10.0).unwrap();
188 agg.update(-5.0).unwrap();
189 agg.update(3.0).unwrap();
190
191 assert_eq!(agg.finalize().unwrap(), 8.0);
192 }
193
194 #[test]
195 fn test_sum_empty() {
196 let agg = SumAggregator::<f64>::new();
197 assert_eq!(agg.finalize().unwrap(), 0.0);
198 }
199}