quantrs2_anneal/advanced_quantum_algorithms/
utils.rs1use scirs2_core::Complex64;
4use std::f64::consts::PI;
5
6#[must_use]
8pub fn complex_phase(phase: f64) -> Complex64 {
9 Complex64::new(phase.cos(), phase.sin())
10}
11
12pub type Complex = Complex64;
14
15#[must_use]
17pub fn validate_parameters(params: &[f64]) -> bool {
18 params.iter().all(|&p| p >= 0.0 && p <= 2.0 * PI)
19}
20
21pub fn normalize_parameters(params: &mut [f64]) {
23 for param in params.iter_mut() {
24 *param = param.clamp(0.0, 2.0 * PI);
25 }
26}
27
28#[must_use]
30pub fn estimate_problem_complexity(num_variables: usize, density: f64) -> f64 {
31 let size_factor = (num_variables as f64).log2();
32 let density_factor = density.clamp(0.1, 1.0);
33 size_factor * density_factor
34}
35
36#[must_use]
38pub fn calculate_relative_improvement(old_value: f64, new_value: f64) -> f64 {
39 if old_value.abs() < 1e-8 {
40 if new_value.abs() < 1e-8 {
41 0.0
42 } else {
43 f64::INFINITY
44 }
45 } else {
46 (old_value - new_value) / old_value.abs()
47 }
48}
49
50#[must_use]
52pub fn linear_interpolate(start: f64, end: f64, fraction: f64) -> f64 {
53 fraction.mul_add(end - start, start)
54}
55
56#[must_use]
58pub fn running_average(current_avg: f64, new_value: f64, decay_factor: f64) -> f64 {
59 decay_factor.mul_add(current_avg, (1.0 - decay_factor) * new_value)
60}
61
62#[must_use]
64pub fn has_converged(current: f64, previous: f64, tolerance: f64) -> bool {
65 (current - previous).abs() < tolerance
66}
67
68#[must_use]
70pub fn exponential_moving_average(values: &[f64], alpha: f64) -> Vec<f64> {
71 if values.is_empty() {
72 return Vec::new();
73 }
74
75 let mut ema = Vec::with_capacity(values.len());
76 ema.push(values[0]);
77
78 for i in 1..values.len() {
79 let new_ema = alpha.mul_add(values[i], (1.0 - alpha) * ema[i - 1]);
80 ema.push(new_ema);
81 }
82
83 ema
84}
85
86#[must_use]
88pub fn fibonacci_sequence(n: usize) -> Vec<usize> {
89 if n == 0 {
90 return Vec::new();
91 }
92 if n == 1 {
93 return vec![1];
94 }
95
96 let mut fib = vec![1, 1];
97 for i in 2..n {
98 let next = fib[i - 1] + fib[i - 2];
99 fib.push(next);
100 }
101 fib
102}
103
104#[must_use]
106pub fn golden_ratio_increment(current: usize) -> usize {
107 ((current as f64) * 1.618) as usize
108}
109
110#[must_use]
112pub fn autocorrelation(data: &[f64], lag: usize) -> f64 {
113 if data.len() <= lag {
114 return 0.0;
115 }
116
117 let n = data.len() - lag;
118 let mean = data.iter().sum::<f64>() / data.len() as f64;
119
120 let mut numerator = 0.0;
121 let mut denominator = 0.0;
122
123 for i in 0..n {
124 let x_i = data[i] - mean;
125 let x_lag = data[i + lag] - mean;
126 numerator += x_i * x_lag;
127 denominator += x_i * x_i;
128 }
129
130 if denominator > 1e-8 {
131 numerator / denominator
132 } else {
133 0.0
134 }
135}
136
137#[derive(Debug, Clone)]
139pub struct WindowStats {
140 pub mean: f64,
141 pub std: f64,
142 pub min: f64,
143 pub max: f64,
144}
145
146impl WindowStats {
147 #[must_use]
148 pub fn new(data: &[f64]) -> Self {
149 if data.is_empty() {
150 return Self {
151 mean: 0.0,
152 std: 0.0,
153 min: 0.0,
154 max: 0.0,
155 };
156 }
157
158 let mean = data.iter().sum::<f64>() / data.len() as f64;
159 let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / data.len() as f64;
160 let std = variance.sqrt();
161 let min = data.iter().fold(f64::INFINITY, |a, &b| a.min(b));
162 let max = data.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
163
164 Self {
165 mean,
166 std,
167 min,
168 max,
169 }
170 }
171}
172
173#[derive(Debug, Clone)]
175pub struct PerformanceTracker {
176 values: Vec<f64>,
177 max_size: usize,
178}
179
180impl PerformanceTracker {
181 #[must_use]
182 pub const fn new(max_size: usize) -> Self {
183 Self {
184 values: Vec::new(),
185 max_size,
186 }
187 }
188
189 pub fn add_value(&mut self, value: f64) {
190 self.values.push(value);
191 if self.values.len() > self.max_size {
192 self.values.remove(0);
193 }
194 }
195
196 #[must_use]
197 pub fn recent_improvement(&self, window_size: usize) -> f64 {
198 if self.values.len() < window_size {
199 return 0.0;
200 }
201
202 let recent_start = self.values.len() - window_size;
203 let recent_values = &self.values[recent_start..];
204
205 if recent_values.len() < 2 {
206 return 0.0;
207 }
208
209 let initial = recent_values[0];
210 let final_val = recent_values[recent_values.len() - 1];
211
212 calculate_relative_improvement(initial, final_val)
213 }
214
215 #[must_use]
216 pub fn is_stagnating(&self, threshold: f64, window_size: usize) -> bool {
217 let improvement = self.recent_improvement(window_size);
218 improvement.abs() < threshold
219 }
220
221 #[must_use]
222 pub fn get_trend(&self, window_size: usize) -> f64 {
223 if self.values.len() < window_size {
224 return 0.0;
225 }
226
227 let recent_start = self.values.len() - window_size;
228 let recent_values = &self.values[recent_start..];
229
230 let n = recent_values.len() as f64;
232 let sum_x = (0..recent_values.len()).sum::<usize>() as f64;
233 let sum_y = recent_values.iter().sum::<f64>();
234 let sum_xy = recent_values
235 .iter()
236 .enumerate()
237 .map(|(i, &y)| i as f64 * y)
238 .sum::<f64>();
239 let sum_x2 = (0..recent_values.len())
240 .map(|i| (i as f64).powi(2))
241 .sum::<f64>();
242
243 let denominator = sum_x.mul_add(-sum_x, n * sum_x2);
244 if denominator.abs() < 1e-8 {
245 0.0
246 } else {
247 n.mul_add(sum_xy, -(sum_x * sum_y)) / denominator
248 }
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 #[test]
257 fn test_complex_phase() {
258 let phase = PI / 4.0;
259 let complex_val = complex_phase(phase);
260
261 assert!((complex_val.re - (PI / 4.0).cos()).abs() < 1e-10);
262 assert!((complex_val.im - (PI / 4.0).sin()).abs() < 1e-10);
263 }
264
265 #[test]
266 fn test_parameter_validation() {
267 let valid_params = vec![0.0, PI, 2.0 * PI];
268 let invalid_params = vec![-1.0, 3.0 * PI];
269
270 assert!(validate_parameters(&valid_params));
271 assert!(!validate_parameters(&invalid_params));
272 }
273
274 #[test]
275 fn test_parameter_normalization() {
276 let mut params = vec![-1.0, PI, 3.0 * PI];
277 normalize_parameters(&mut params);
278
279 assert!(validate_parameters(¶ms));
280 assert_eq!(params[0], 0.0);
281 assert_eq!(params[1], PI);
282 assert_eq!(params[2], 2.0 * PI);
283 }
284
285 #[test]
286 fn test_relative_improvement() {
287 assert_eq!(calculate_relative_improvement(10.0, 8.0), 0.2);
288 assert_eq!(calculate_relative_improvement(8.0, 10.0), -0.25);
289 assert_eq!(calculate_relative_improvement(0.0, 0.0), 0.0);
290 }
291
292 #[test]
293 fn test_fibonacci_sequence() {
294 let fib = fibonacci_sequence(5);
295 assert_eq!(fib, vec![1, 1, 2, 3, 5]);
296 }
297
298 #[test]
299 fn test_exponential_moving_average() {
300 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
301 let ema = exponential_moving_average(&values, 0.5);
302
303 assert_eq!(ema.len(), values.len());
304 assert_eq!(ema[0], 1.0);
305 assert!(ema[1] > 1.0 && ema[1] < 2.0);
307 }
308
309 #[test]
310 fn test_window_stats() {
311 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
312 let stats = WindowStats::new(&data);
313
314 assert_eq!(stats.mean, 3.0);
315 assert_eq!(stats.min, 1.0);
316 assert_eq!(stats.max, 5.0);
317 assert!(stats.std > 0.0);
318 }
319
320 #[test]
321 fn test_performance_tracker() {
322 let mut tracker = PerformanceTracker::new(5);
323
324 tracker.add_value(10.0);
325 tracker.add_value(8.0);
326 tracker.add_value(6.0);
327
328 let improvement = tracker.recent_improvement(3);
329 assert!(improvement > 0.0); let trend = tracker.get_trend(3);
332 assert!(trend < 0.0); }
334}