quantrs2-anneal 0.1.3

Quantum annealing support for the QuantRS2 framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
//! Performance regression detection system

use super::{
    AlertThresholds, ApplicationError, ApplicationResult, Duration, HashMap, Instant,
    RegressionAlgorithmType, StatisticalModelType, TrendDirection, VecDeque,
};

/// Performance regression detector
#[derive(Debug)]
pub struct RegressionDetector {
    /// Performance history database
    pub performance_history: HashMap<String, VecDeque<PerformanceDataPoint>>,
    /// Regression detection algorithms
    pub detection_algorithms: Vec<RegressionAlgorithm>,
    /// Alert thresholds
    pub alert_thresholds: AlertThresholds,
    /// Statistical models for prediction
    pub statistical_models: HashMap<String, StatisticalModel>,
}

/// Performance data point
#[derive(Debug, Clone)]
pub struct PerformanceDataPoint {
    /// Timestamp of measurement
    pub timestamp: Instant,
    /// Performance value
    pub value: f64,
    /// Test configuration
    pub test_config: TestConfiguration,
    /// Environmental factors
    pub environment: EnvironmentalFactors,
    /// Additional metadata
    pub metadata: HashMap<String, String>,
}

/// Test configuration for reproducibility
#[derive(Debug, Clone)]
pub struct TestConfiguration {
    /// Test parameters
    pub parameters: HashMap<String, f64>,
    /// Hardware configuration
    pub hardware: HardwareConfiguration,
    /// Software configuration
    pub software: SoftwareConfiguration,
}

/// Hardware configuration
#[derive(Debug, Clone)]
pub struct HardwareConfiguration {
    /// CPU model
    pub cpu_model: String,
    /// Memory size (GB)
    pub memory_gb: usize,
    /// Number of cores
    pub num_cores: usize,
    /// GPU information
    pub gpu_info: Option<String>,
}

/// Software configuration
#[derive(Debug, Clone)]
pub struct SoftwareConfiguration {
    /// Operating system
    pub os: String,
    /// Compiler version
    pub compiler_version: String,
    /// Optimization flags
    pub optimization_flags: Vec<String>,
    /// Library versions
    pub dependencies: HashMap<String, String>,
}

/// Environmental factors affecting performance
#[derive(Debug, Clone)]
pub struct EnvironmentalFactors {
    /// System load
    pub system_load: f64,
    /// Temperature
    pub temperature: Option<f64>,
    /// Network conditions
    pub network_latency: Option<Duration>,
    /// Power mode
    pub power_mode: Option<String>,
}

/// Regression detection algorithm
#[derive(Debug)]
pub struct RegressionAlgorithm {
    /// Algorithm identifier
    pub id: String,
    /// Algorithm type
    pub algorithm_type: RegressionAlgorithmType,
    /// Algorithm parameters
    pub parameters: HashMap<String, f64>,
    /// Sensitivity level
    pub sensitivity: f64,
}

/// Statistical model for regression analysis
#[derive(Debug)]
pub struct StatisticalModel {
    /// Model type
    pub model_type: StatisticalModelType,
    /// Model parameters
    pub parameters: Vec<f64>,
    /// Model confidence
    pub confidence: f64,
    /// Last update time
    pub last_update: Instant,
}

impl RegressionDetector {
    #[must_use]
    pub fn new() -> Self {
        Self {
            performance_history: HashMap::new(),
            detection_algorithms: Self::create_default_algorithms(),
            alert_thresholds: AlertThresholds::default(),
            statistical_models: HashMap::new(),
        }
    }

    /// Create default regression detection algorithms
    fn create_default_algorithms() -> Vec<RegressionAlgorithm> {
        vec![
            RegressionAlgorithm {
                id: "statistical_process_control".to_string(),
                algorithm_type: RegressionAlgorithmType::StatisticalProcessControl,
                parameters: {
                    let mut params = HashMap::new();
                    params.insert("control_limit_factor".to_string(), 3.0);
                    params.insert("window_size".to_string(), 50.0);
                    params
                },
                sensitivity: 0.95,
            },
            RegressionAlgorithm {
                id: "change_point_detection".to_string(),
                algorithm_type: RegressionAlgorithmType::ChangePointDetection,
                parameters: {
                    let mut params = HashMap::new();
                    params.insert("penalty".to_string(), 1.0);
                    params.insert("min_segment_length".to_string(), 10.0);
                    params
                },
                sensitivity: 0.90,
            },
            RegressionAlgorithm {
                id: "time_series_analysis".to_string(),
                algorithm_type: RegressionAlgorithmType::TimeSeriesAnalysis,
                parameters: {
                    let mut params = HashMap::new();
                    params.insert("trend_threshold".to_string(), 0.05);
                    params.insert("seasonality_period".to_string(), 7.0);
                    params
                },
                sensitivity: 0.85,
            },
        ]
    }

    /// Add performance data point
    pub fn add_data_point(&mut self, test_id: String, data_point: PerformanceDataPoint) {
        let history = self
            .performance_history
            .entry(test_id)
            .or_insert_with(VecDeque::new);
        history.push_back(data_point);

        // Keep only recent data points
        while history.len() > 1000 {
            history.pop_front();
        }
    }

    /// Detect performance regression
    pub fn detect_regression(
        &self,
        test_id: &str,
    ) -> ApplicationResult<Vec<RegressionDetectionResult>> {
        let history = self.performance_history.get(test_id).ok_or_else(|| {
            ApplicationError::ConfigurationError(format!(
                "No performance history found for test: {test_id}"
            ))
        })?;

        if history.len() < self.alert_thresholds.min_sample_size {
            return Ok(Vec::new());
        }

        let mut results = Vec::new();

        for algorithm in &self.detection_algorithms {
            let result = self.run_detection_algorithm(algorithm, history)?;
            results.push(result);
        }

        Ok(results)
    }

    /// Run specific detection algorithm
    fn run_detection_algorithm(
        &self,
        algorithm: &RegressionAlgorithm,
        history: &VecDeque<PerformanceDataPoint>,
    ) -> ApplicationResult<RegressionDetectionResult> {
        match algorithm.algorithm_type {
            RegressionAlgorithmType::StatisticalProcessControl => {
                self.run_statistical_process_control(algorithm, history)
            }
            RegressionAlgorithmType::ChangePointDetection => {
                self.run_change_point_detection(algorithm, history)
            }
            RegressionAlgorithmType::TimeSeriesAnalysis => {
                self.run_time_series_analysis(algorithm, history)
            }
            _ => Ok(RegressionDetectionResult {
                algorithm_id: algorithm.id.clone(),
                regression_detected: false,
                confidence: 0.0,
                p_value: 1.0,
                change_point: None,
                trend_direction: TrendDirection::Stable,
                magnitude: 0.0,
                details: "Algorithm not implemented".to_string(),
            }),
        }
    }

    /// Run statistical process control algorithm
    fn run_statistical_process_control(
        &self,
        algorithm: &RegressionAlgorithm,
        history: &VecDeque<PerformanceDataPoint>,
    ) -> ApplicationResult<RegressionDetectionResult> {
        let window_size = *algorithm.parameters.get("window_size").unwrap_or(&50.0) as usize;
        let control_limit_factor = algorithm
            .parameters
            .get("control_limit_factor")
            .unwrap_or(&3.0);

        let values: Vec<f64> = history.iter().map(|dp| dp.value).collect();

        if values.len() < window_size {
            return Ok(RegressionDetectionResult {
                algorithm_id: algorithm.id.clone(),
                regression_detected: false,
                confidence: 0.0,
                p_value: 1.0,
                change_point: None,
                trend_direction: TrendDirection::Stable,
                magnitude: 0.0,
                details: "Insufficient data for SPC".to_string(),
            });
        }

        // Calculate control limits from baseline window
        let baseline = &values[..window_size];
        let mean = baseline.iter().sum::<f64>() / baseline.len() as f64;
        let variance =
            baseline.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (baseline.len() - 1) as f64;
        let std_dev = variance.sqrt();

        let upper_limit = mean + control_limit_factor * std_dev;
        let lower_limit = mean - control_limit_factor * std_dev;

        // Check recent values against control limits
        let recent_values = &values[window_size..];
        let violations: Vec<usize> = recent_values
            .iter()
            .enumerate()
            .filter(|(_, &value)| value > upper_limit || value < lower_limit)
            .map(|(i, _)| i + window_size)
            .collect();

        let regression_detected = !violations.is_empty();
        let confidence = if regression_detected {
            algorithm.sensitivity
        } else {
            1.0 - algorithm.sensitivity
        };

        let trend_direction = if recent_values.iter().any(|&v| v < lower_limit) {
            TrendDirection::Degrading
        } else if recent_values.iter().any(|&v| v > upper_limit) {
            TrendDirection::Improving
        } else {
            TrendDirection::Stable
        };

        Ok(RegressionDetectionResult {
            algorithm_id: algorithm.id.clone(),
            regression_detected,
            confidence,
            p_value: if regression_detected { 0.01 } else { 0.9 },
            change_point: violations.first().copied(),
            trend_direction,
            magnitude: if violations.is_empty() {
                0.0
            } else {
                let worst_violation = recent_values
                    .iter()
                    .map(|&v| (v - mean).abs() / std_dev)
                    .fold(0.0, f64::max);
                worst_violation
            },
            details: format!("SPC analysis: {} violations detected", violations.len()),
        })
    }

    /// Run change point detection algorithm
    fn run_change_point_detection(
        &self,
        algorithm: &RegressionAlgorithm,
        history: &VecDeque<PerformanceDataPoint>,
    ) -> ApplicationResult<RegressionDetectionResult> {
        let min_segment_length = *algorithm
            .parameters
            .get("min_segment_length")
            .unwrap_or(&10.0) as usize;
        let values: Vec<f64> = history.iter().map(|dp| dp.value).collect();

        if values.len() < min_segment_length * 2 {
            return Ok(RegressionDetectionResult {
                algorithm_id: algorithm.id.clone(),
                regression_detected: false,
                confidence: 0.0,
                p_value: 1.0,
                change_point: None,
                trend_direction: TrendDirection::Stable,
                magnitude: 0.0,
                details: "Insufficient data for change point detection".to_string(),
            });
        }

        // Simplified change point detection using variance changes
        let mut best_change_point = None;
        let mut best_score = 0.0;

        for i in min_segment_length..(values.len() - min_segment_length) {
            let before = &values[..i];
            let after = &values[i..];

            let mean_before = before.iter().sum::<f64>() / before.len() as f64;
            let mean_after = after.iter().sum::<f64>() / after.len() as f64;

            let score = (mean_before - mean_after).abs();

            if score > best_score {
                best_score = score;
                best_change_point = Some(i);
            }
        }

        let threshold = 0.1; // Simplified threshold
        let regression_detected = best_score > threshold;

        Ok(RegressionDetectionResult {
            algorithm_id: algorithm.id.clone(),
            regression_detected,
            confidence: if regression_detected {
                algorithm.sensitivity
            } else {
                1.0 - algorithm.sensitivity
            },
            p_value: if regression_detected { 0.05 } else { 0.8 },
            change_point: best_change_point,
            trend_direction: if regression_detected {
                if let Some(cp) = best_change_point {
                    let before_mean = values[..cp].iter().sum::<f64>() / cp as f64;
                    let after_mean = values[cp..].iter().sum::<f64>() / (values.len() - cp) as f64;
                    if after_mean < before_mean {
                        TrendDirection::Degrading
                    } else {
                        TrendDirection::Improving
                    }
                } else {
                    TrendDirection::Stable
                }
            } else {
                TrendDirection::Stable
            },
            magnitude: best_score,
            details: format!("Change point detection: score = {best_score:.4}"),
        })
    }

    /// Run time series analysis algorithm
    fn run_time_series_analysis(
        &self,
        algorithm: &RegressionAlgorithm,
        history: &VecDeque<PerformanceDataPoint>,
    ) -> ApplicationResult<RegressionDetectionResult> {
        let trend_threshold = algorithm.parameters.get("trend_threshold").unwrap_or(&0.05);
        let values: Vec<f64> = history.iter().map(|dp| dp.value).collect();

        if values.len() < 10 {
            return Ok(RegressionDetectionResult {
                algorithm_id: algorithm.id.clone(),
                regression_detected: false,
                confidence: 0.0,
                p_value: 1.0,
                change_point: None,
                trend_direction: TrendDirection::Stable,
                magnitude: 0.0,
                details: "Insufficient data for time series analysis".to_string(),
            });
        }

        // Simple linear trend calculation
        let n = values.len() as f64;
        let x_sum = (0..values.len()).map(|i| i as f64).sum::<f64>();
        let y_sum = values.iter().sum::<f64>();
        let xy_sum = values
            .iter()
            .enumerate()
            .map(|(i, &y)| i as f64 * y)
            .sum::<f64>();
        let x2_sum = (0..values.len()).map(|i| (i as f64).powi(2)).sum::<f64>();

        let slope = n.mul_add(xy_sum, -(x_sum * y_sum)) / x_sum.mul_add(-x_sum, n * x2_sum);
        let slope_abs = slope.abs();

        let regression_detected = slope_abs > *trend_threshold;

        let trend_direction = if slope > *trend_threshold {
            TrendDirection::Improving
        } else if slope < -*trend_threshold {
            TrendDirection::Degrading
        } else {
            TrendDirection::Stable
        };

        Ok(RegressionDetectionResult {
            algorithm_id: algorithm.id.clone(),
            regression_detected,
            confidence: if regression_detected {
                algorithm.sensitivity
            } else {
                1.0 - algorithm.sensitivity
            },
            p_value: if regression_detected { 0.02 } else { 0.7 },
            change_point: None,
            trend_direction,
            magnitude: slope_abs,
            details: format!("Time series analysis: slope = {slope:.6}"),
        })
    }

    /// Get performance summary for test
    #[must_use]
    pub fn get_performance_summary(&self, test_id: &str) -> Option<PerformanceSummary> {
        let history = self.performance_history.get(test_id)?;

        if history.is_empty() {
            return None;
        }

        let values: Vec<f64> = history.iter().map(|dp| dp.value).collect();
        let mean = values.iter().sum::<f64>() / values.len() as f64;
        let variance =
            values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (values.len() - 1) as f64;
        let std_dev = variance.sqrt();

        let mut sorted_values = values.clone();
        sorted_values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));

        Some(PerformanceSummary {
            test_id: test_id.to_string(),
            sample_count: values.len(),
            mean,
            std_dev,
            min: sorted_values[0],
            max: sorted_values[sorted_values.len() - 1],
            median: if sorted_values.len() % 2 == 0 {
                f64::midpoint(
                    sorted_values[sorted_values.len() / 2 - 1],
                    sorted_values[sorted_values.len() / 2],
                )
            } else {
                sorted_values[sorted_values.len() / 2]
            },
            recent_trend: self.calculate_recent_trend(&values),
        })
    }

    /// Calculate recent trend
    fn calculate_recent_trend(&self, values: &[f64]) -> TrendDirection {
        if values.len() < 10 {
            return TrendDirection::Stable;
        }

        let recent_size = (values.len() / 4).max(5).min(20);
        let recent = &values[values.len() - recent_size..];
        let earlier = &values[values.len() - 2 * recent_size..values.len() - recent_size];

        let recent_mean = recent.iter().sum::<f64>() / recent.len() as f64;
        let earlier_mean = earlier.iter().sum::<f64>() / earlier.len() as f64;

        let change = (recent_mean - earlier_mean) / earlier_mean;

        if change > 0.05 {
            TrendDirection::Improving
        } else if change < -0.05 {
            TrendDirection::Degrading
        } else {
            TrendDirection::Stable
        }
    }
}

/// Result from regression detection
#[derive(Debug, Clone)]
pub struct RegressionDetectionResult {
    /// Algorithm identifier
    pub algorithm_id: String,
    /// Whether regression was detected
    pub regression_detected: bool,
    /// Confidence level
    pub confidence: f64,
    /// Statistical p-value
    pub p_value: f64,
    /// Change point index (if detected)
    pub change_point: Option<usize>,
    /// Direction of trend
    pub trend_direction: TrendDirection,
    /// Magnitude of change
    pub magnitude: f64,
    /// Additional details
    pub details: String,
}

/// Performance summary statistics
#[derive(Debug, Clone)]
pub struct PerformanceSummary {
    /// Test identifier
    pub test_id: String,
    /// Number of samples
    pub sample_count: usize,
    /// Mean performance
    pub mean: f64,
    /// Standard deviation
    pub std_dev: f64,
    /// Minimum value
    pub min: f64,
    /// Maximum value
    pub max: f64,
    /// Median value
    pub median: f64,
    /// Recent trend direction
    pub recent_trend: TrendDirection,
}