1use super::config::*;
8use super::optimizer::{Adaptation, AdaptationPriority, AdaptationType, StreamingDataPoint};
9use super::resource_management::ResourceUsage;
10
11use scirs2_core::numeric::Float;
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, VecDeque};
14use std::iter::Sum;
15use std::time::{Duration, Instant};
16
17#[derive(Debug, Clone)]
19pub struct PerformanceSnapshot<A: Float + Send + Sync> {
20 pub timestamp: Instant,
22 pub loss: A,
24 pub accuracy: Option<A>,
26 pub convergence_rate: Option<A>,
28 pub gradient_norm: Option<A>,
30 pub parameter_update_magnitude: Option<A>,
32 pub data_statistics: DataStatistics<A>,
34 pub resource_usage: ResourceUsage,
36 pub custom_metrics: HashMap<String, A>,
38}
39
40#[derive(Debug, Clone)]
42pub struct DataStatistics<A: Float + Send + Sync> {
43 pub sample_count: usize,
45 pub feature_means: scirs2_core::ndarray::Array1<A>,
47 pub feature_stds: scirs2_core::ndarray::Array1<A>,
49 pub average_quality: A,
51 pub timestamp: Instant,
53}
54
55impl<A: Float + Send + Sync> Default for DataStatistics<A> {
56 fn default() -> Self {
57 Self {
58 sample_count: 0,
59 feature_means: scirs2_core::ndarray::Array1::zeros(0),
60 feature_stds: scirs2_core::ndarray::Array1::zeros(0),
61 average_quality: A::zero(),
62 timestamp: Instant::now(),
63 }
64 }
65}
66
67#[derive(Debug, Clone)]
69pub enum PerformanceMetric<A: Float + Send + Sync> {
70 Loss(A),
72 Accuracy(A),
74 ConvergenceRate(A),
76 GradientNorm(A),
78 LearningRateEffectiveness(A),
80 ResourceEfficiency(A),
82 DataQuality(A),
84 Custom(String, A),
86}
87
88#[derive(Debug, Clone)]
90pub struct PerformanceContext<A: Float + Send + Sync> {
91 pub learning_rate: A,
93 pub batch_size: usize,
95 pub buffer_size: usize,
97 pub drift_detected: bool,
99 pub resource_constraints: ResourceUsage,
101 pub time_since_adaptation: Duration,
103}
104
105pub struct PerformanceTracker<A: Float + Send + Sync + std::iter::Sum> {
107 config: PerformanceConfig,
109 performance_history: VecDeque<PerformanceSnapshot<A>>,
111 trend_analyzer: PerformanceTrendAnalyzer<A>,
113 predictor: PerformancePredictor<A>,
115 baseline: Option<PerformanceSnapshot<A>>,
117 current_context: Option<PerformanceContext<A>>,
119 improvement_tracker: PerformanceImprovementTracker<A>,
121 performance_anomaly_detector: PerformanceAnomalyDetector<A>,
123}
124
125pub struct PerformanceTrendAnalyzer<A: Float + Send + Sync> {
127 window_size: usize,
129 trends: HashMap<String, TrendData<A>>,
131 trend_methods: Vec<TrendMethod>,
133}
134
135#[derive(Debug, Clone)]
137pub struct TrendData<A: Float + Send + Sync> {
138 pub slope: A,
140 pub correlation: A,
142 pub volatility: A,
144 pub confidence: A,
146 pub recent_values: VecDeque<A>,
148 pub last_update: Instant,
150}
151
152#[derive(Debug, Clone)]
154pub enum TrendMethod {
155 LinearRegression,
157 MovingAverage { window: usize },
159 ExponentialSmoothing { alpha: f64 },
161 SeasonalDecomposition,
163}
164
165pub struct PerformancePredictor<A: Float + Send + Sync> {
167 prediction_methods: Vec<PredictionMethod>,
169 prediction_history: VecDeque<PredictionResult<A>>,
171 model_accuracies: HashMap<String, A>,
173 ensemble_weights: HashMap<String, A>,
175}
176
177#[derive(Debug, Clone)]
179pub enum PredictionMethod {
180 Linear,
182 Exponential { alpha: f64, beta: f64 },
184 ARIMA { p: usize, d: usize, q: usize },
186 NeuralNetwork { hidden_layers: Vec<usize> },
188 Ensemble,
190}
191
192#[derive(Debug, Clone)]
194pub struct PredictionResult<A: Float + Send + Sync> {
195 pub predicted_value: A,
197 pub confidence_interval: (A, A),
199 pub method: String,
201 pub steps_ahead: usize,
203 pub timestamp: Instant,
205 pub actual_value: Option<A>,
207}
208
209pub struct PerformanceImprovementTracker<A: Float + Send + Sync> {
211 baseline_metrics: HashMap<String, A>,
213 improvement_rates: HashMap<String, A>,
215 improvement_history: VecDeque<ImprovementEvent<A>>,
217 plateau_detector: PlateauDetector<A>,
219}
220
221#[derive(Debug, Clone)]
223pub struct ImprovementEvent<A: Float + Send + Sync> {
224 pub timestamp: Instant,
226 pub metric_name: String,
228 pub improvement: A,
230 pub improvement_rate: A,
232 pub context: String,
234}
235
236pub struct PlateauDetector<A: Float + Send + Sync> {
238 window_size: usize,
240 plateau_threshold: A,
242 recent_values: VecDeque<A>,
244 is_plateau: bool,
246 plateau_duration: Duration,
248 last_significant_change: Option<Instant>,
250}
251
252pub struct PerformanceAnomalyDetector<A: Float + Send + Sync> {
254 threshold: A,
256 historical_stats: HashMap<String, MetricStatistics<A>>,
258 recent_anomalies: VecDeque<PerformanceAnomaly<A>>,
260 adaptive_threshold: bool,
262}
263
264#[derive(Debug, Clone)]
266pub struct MetricStatistics<A: Float + Send + Sync> {
267 pub mean: A,
269 pub variance: A,
271 pub min_value: A,
273 pub max_value: A,
275 pub count: usize,
277 pub last_update: Instant,
279}
280
281#[derive(Debug, Clone)]
283pub struct PerformanceAnomaly<A: Float + Send + Sync> {
284 pub timestamp: Instant,
286 pub metric_name: String,
288 pub observed_value: A,
290 pub expected_range: (A, A),
292 pub severity: AnomalySeverity,
294 pub anomaly_type: AnomalyType,
296}
297
298#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
300pub enum AnomalySeverity {
301 Minor,
303 Moderate,
305 Major,
307 Critical,
309}
310
311#[derive(Debug, Clone, PartialEq, Eq)]
313pub enum AnomalyType {
314 High,
316 Low,
318 TrendChange,
320 Oscillation,
322 Degradation,
324 Plateau,
326}
327
328impl<A: Float + Default + Clone + std::iter::Sum + Send + Sync + std::fmt::Debug>
329 PerformanceTracker<A>
330{
331 pub fn new(config: &StreamingConfig) -> Result<Self, String> {
333 let performance_config = config.performance_config.clone();
334
335 let trend_analyzer = PerformanceTrendAnalyzer::new(performance_config.trend_window_size);
336 let predictor = PerformancePredictor::new();
337 let improvement_tracker = PerformanceImprovementTracker::new();
338 let performance_anomaly_detector = PerformanceAnomalyDetector::new(2.0); Ok(Self {
341 config: performance_config,
342 performance_history: VecDeque::with_capacity(1000),
343 trend_analyzer,
344 predictor,
345 baseline: None,
346 current_context: None,
347 improvement_tracker,
348 performance_anomaly_detector,
349 })
350 }
351
352 pub fn add_performance(&mut self, snapshot: PerformanceSnapshot<A>) -> Result<(), String> {
354 if self.performance_history.len() >= self.config.history_size {
356 self.performance_history.pop_front();
357 }
358 self.performance_history.push_back(snapshot.clone());
359
360 if self.baseline.is_none() {
362 self.baseline = Some(snapshot.clone());
363 }
364
365 if self.config.enable_trend_analysis {
367 self.trend_analyzer.update(&snapshot)?;
368 }
369
370 self.improvement_tracker.update(&snapshot)?;
372
373 let anomalies = self
375 .performance_anomaly_detector
376 .check_for_anomalies(&snapshot)?;
377 if !anomalies.is_empty() {
378 self.handle_performance_anomalies(&anomalies)?;
380 }
381
382 if self.config.enable_prediction {
384 self.predictor.update_with_actual(&snapshot)?;
385 }
386
387 Ok(())
388 }
389
390 pub fn get_recent_performance(&self, count: usize) -> Vec<PerformanceSnapshot<A>> {
392 self.performance_history
393 .iter()
394 .rev()
395 .take(count)
396 .cloned()
397 .collect()
398 }
399
400 pub fn get_recent_losses(&self, count: usize) -> Vec<A> {
402 self.performance_history
403 .iter()
404 .rev()
405 .take(count)
406 .map(|snapshot| snapshot.loss)
407 .collect()
408 }
409
410 pub fn predict_performance(
412 &mut self,
413 steps_ahead: usize,
414 ) -> Result<PredictionResult<A>, String> {
415 if !self.config.enable_prediction {
416 return Err("Performance prediction is disabled".to_string());
417 }
418
419 self.predictor
420 .predict(steps_ahead, &self.performance_history)
421 }
422
423 pub fn get_performance_trends(&self) -> HashMap<String, TrendData<A>> {
425 self.trend_analyzer.get_current_trends()
426 }
427
428 pub fn apply_threshold_adaptation(&mut self, adaptation: &Adaptation<A>) -> Result<(), String> {
430 if adaptation.adaptation_type == AdaptationType::PerformanceThreshold {
431 let new_threshold = self.performance_anomaly_detector.threshold + adaptation.magnitude;
433 self.performance_anomaly_detector
434 .update_threshold(new_threshold);
435 }
436 Ok(())
437 }
438
439 fn handle_performance_anomalies(
441 &mut self,
442 anomalies: &[PerformanceAnomaly<A>],
443 ) -> Result<(), String> {
444 for anomaly in anomalies {
445 match anomaly.severity {
446 AnomalySeverity::Critical | AnomalySeverity::Major => {
447 println!("Critical performance anomaly detected: {:?}", anomaly);
449 }
450 _ => {
451 self.performance_anomaly_detector
453 .recent_anomalies
454 .push_back(anomaly.clone());
455 }
456 }
457 }
458 Ok(())
459 }
460
461 pub fn reset(&mut self) -> Result<(), String> {
463 self.performance_history.clear();
464 self.baseline = None;
465 self.current_context = None;
466 self.trend_analyzer.reset();
467 self.predictor.reset();
468 self.improvement_tracker.reset();
469 self.performance_anomaly_detector.reset();
470 Ok(())
471 }
472
473 pub fn get_diagnostics(&self) -> PerformanceDiagnostics {
475 PerformanceDiagnostics {
476 history_size: self.performance_history.len(),
477 baseline_set: self.baseline.is_some(),
478 trends_available: !self.trend_analyzer.trends.is_empty(),
479 anomalies_detected: self.performance_anomaly_detector.recent_anomalies.len(),
480 plateau_detected: self.improvement_tracker.plateau_detector.is_plateau,
481 prediction_accuracy: self.predictor.get_average_accuracy(),
482 }
483 }
484}
485
486impl<A: Float + Default + Clone + Send + Sync + std::iter::Sum> PerformanceTrendAnalyzer<A> {
487 fn new(window_size: usize) -> Self {
488 Self {
489 window_size,
490 trends: HashMap::new(),
491 trend_methods: vec![
492 TrendMethod::LinearRegression,
493 TrendMethod::MovingAverage {
494 window: window_size / 2,
495 },
496 TrendMethod::ExponentialSmoothing { alpha: 0.3 },
497 ],
498 }
499 }
500
501 fn update(&mut self, snapshot: &PerformanceSnapshot<A>) -> Result<(), String> {
502 self.update_metric_trend("loss", snapshot.loss)?;
504
505 if let Some(accuracy) = snapshot.accuracy {
506 self.update_metric_trend("accuracy", accuracy)?;
507 }
508
509 if let Some(convergence) = snapshot.convergence_rate {
510 self.update_metric_trend("convergence", convergence)?;
511 }
512
513 self.compute_trends()?;
514 Ok(())
515 }
516
517 fn update_metric_trend(&mut self, metric_name: &str, value: A) -> Result<(), String> {
518 let trend_data = self
519 .trends
520 .entry(metric_name.to_string())
521 .or_insert_with(|| TrendData {
522 slope: A::zero(),
523 correlation: A::zero(),
524 volatility: A::zero(),
525 confidence: A::zero(),
526 recent_values: VecDeque::with_capacity(self.window_size),
527 last_update: Instant::now(),
528 });
529
530 if trend_data.recent_values.len() >= self.window_size {
531 trend_data.recent_values.pop_front();
532 }
533 trend_data.recent_values.push_back(value);
534 trend_data.last_update = Instant::now();
535
536 Ok(())
537 }
538
539 fn compute_trends(&mut self) -> Result<(), String> {
540 let keys: Vec<_> = self.trends.keys().cloned().collect();
541
542 let mut computed_values = Vec::new();
544 for metric_name in &keys {
545 if let Some(trend_data) = self.trends.get(metric_name) {
546 if trend_data.recent_values.len() >= 3 {
547 let values = trend_data.recent_values.clone();
548 let slope = self.compute_slope(&values)?;
549 let correlation = self.compute_correlation(&values)?;
550 let volatility = self.compute_volatility(&values)?;
551 let confidence = self.compute_confidence(&values)?;
552 computed_values.push((
553 metric_name.clone(),
554 slope,
555 correlation,
556 volatility,
557 confidence,
558 ));
559 }
560 }
561 }
562
563 for (metric_name, slope, correlation, volatility, confidence) in computed_values {
565 if let Some(trend_data) = self.trends.get_mut(&metric_name) {
566 trend_data.slope = slope;
567 trend_data.correlation = correlation;
568 trend_data.volatility = volatility;
569 trend_data.confidence = confidence;
570 }
571 }
572
573 Ok(())
574 }
575
576 fn compute_slope(&self, values: &VecDeque<A>) -> Result<A, String> {
577 if values.len() < 2 {
578 return Ok(A::zero());
579 }
580
581 let n = A::from(values.len()).unwrap();
582 let sum_x = n * (n + A::one()) / A::from(2.0).unwrap();
584 let sum_y = values.iter().cloned().sum::<A>();
585 let sum_xy = values
586 .iter()
587 .enumerate()
588 .map(|(i, &y)| A::from(i + 1).unwrap() * y)
589 .sum::<A>();
590 let two = A::from(2.0).unwrap();
592 let six = A::from(6.0).unwrap();
593 let sum_x_squared = n * (n + A::one()) * (two * n + A::one()) / six;
594
595 let denominator = n * sum_x_squared - sum_x * sum_x;
596 if denominator == A::zero() {
597 return Ok(A::zero());
598 }
599
600 let slope = (n * sum_xy - sum_x * sum_y) / denominator;
601 Ok(slope)
602 }
603
604 fn compute_correlation(&self, values: &VecDeque<A>) -> Result<A, String> {
605 if values.len() < 2 {
606 return Ok(A::zero());
607 }
608
609 let n = values.len();
611 let time_values: Vec<A> = (1..=n).map(|i| A::from(i).unwrap()).collect();
612 let value_vec: Vec<A> = values.iter().cloned().collect();
613
614 let mean_time = time_values.iter().cloned().sum::<A>() / A::from(n).unwrap();
615 let mean_value = value_vec.iter().cloned().sum::<A>() / A::from(n).unwrap();
616
617 let numerator = time_values
618 .iter()
619 .zip(value_vec.iter())
620 .map(|(&t, &v)| (t - mean_time) * (v - mean_value))
621 .sum::<A>();
622
623 let time_variance = time_values
624 .iter()
625 .map(|&t| (t - mean_time) * (t - mean_time))
626 .sum::<A>();
627
628 let value_variance = value_vec
629 .iter()
630 .map(|&v| (v - mean_value) * (v - mean_value))
631 .sum::<A>();
632
633 let denominator = (time_variance * value_variance).sqrt();
634 if denominator == A::zero() {
635 return Ok(A::zero());
636 }
637
638 Ok(numerator / denominator)
639 }
640
641 fn compute_volatility(&self, values: &VecDeque<A>) -> Result<A, String> {
642 if values.len() < 2 {
643 return Ok(A::zero());
644 }
645
646 let mean = values.iter().cloned().sum::<A>() / A::from(values.len()).unwrap();
647 let variance = values.iter().map(|&v| (v - mean) * (v - mean)).sum::<A>()
648 / A::from(values.len()).unwrap();
649
650 Ok(variance.sqrt())
651 }
652
653 fn compute_confidence(&self, values: &VecDeque<A>) -> Result<A, String> {
654 if values.len() < 3 {
656 return Ok(A::zero());
657 }
658
659 let slope = self.compute_slope(values)?;
660 let correlation = self.compute_correlation(values)?;
661
662 let confidence = correlation.abs() * (A::one() - (slope.abs() / (slope.abs() + A::one())));
664 Ok(confidence)
665 }
666
667 fn get_current_trends(&self) -> HashMap<String, TrendData<A>> {
668 self.trends.clone()
669 }
670
671 fn reset(&mut self) {
672 self.trends.clear();
673 }
674}
675
676impl<A: Float + Default + Clone + Send + Sync + std::iter::Sum> PerformancePredictor<A> {
677 fn new() -> Self {
678 Self {
679 prediction_methods: vec![
680 PredictionMethod::Linear,
681 PredictionMethod::Exponential {
682 alpha: 0.3,
683 beta: 0.1,
684 },
685 ],
686 prediction_history: VecDeque::with_capacity(1000),
687 model_accuracies: HashMap::new(),
688 ensemble_weights: HashMap::new(),
689 }
690 }
691
692 fn predict(
693 &mut self,
694 steps_ahead: usize,
695 history: &VecDeque<PerformanceSnapshot<A>>,
696 ) -> Result<PredictionResult<A>, String> {
697 if history.len() < 2 {
698 return Err("Insufficient history for prediction".to_string());
699 }
700
701 let loss_values: Vec<A> = history.iter().map(|s| s.loss).collect();
703
704 let predicted_value = self.linear_prediction(&loss_values, steps_ahead)?;
706
707 let recent_volatility = self.compute_recent_volatility(&loss_values)?;
709 let confidence_interval = (
710 predicted_value - recent_volatility,
711 predicted_value + recent_volatility,
712 );
713
714 let prediction = PredictionResult {
715 predicted_value,
716 confidence_interval,
717 method: "linear".to_string(),
718 steps_ahead,
719 timestamp: Instant::now(),
720 actual_value: None,
721 };
722
723 if self.prediction_history.len() >= 1000 {
725 self.prediction_history.pop_front();
726 }
727 self.prediction_history.push_back(prediction.clone());
728
729 Ok(prediction)
730 }
731
732 fn linear_prediction(&self, values: &[A], steps_ahead: usize) -> Result<A, String> {
733 if values.len() < 2 {
734 return Ok(A::zero());
735 }
736
737 let n = values.len();
739 let x1 = A::from(n - 1).unwrap();
740 let y1 = values[n - 1];
741 let x2 = A::from(n).unwrap();
742 let y2 = values[n - 1]; if n >= 3 {
746 let slope = (values[n - 1] - values[n - 3]) / A::from(2).unwrap();
747 let predicted = values[n - 1] + slope * A::from(steps_ahead).unwrap();
748 Ok(predicted)
749 } else {
750 Ok(values[n - 1])
751 }
752 }
753
754 fn exponential_prediction(&self, values: &[A], steps_ahead: usize) -> Result<A, String> {
755 if values.is_empty() {
756 return Ok(A::zero());
757 }
758
759 let alpha = A::from(0.3).unwrap();
761 let mut forecast = values[0];
762
763 for &value in values.iter().skip(1) {
764 forecast = alpha * value + (A::one() - alpha) * forecast;
765 }
766
767 for _ in 0..steps_ahead {
769 forecast = forecast * A::from(0.99).unwrap(); }
771
772 Ok(forecast)
773 }
774
775 fn compute_recent_volatility(&self, values: &[A]) -> Result<A, String> {
776 if values.len() < 2 {
777 return Ok(A::zero());
778 }
779
780 let recent_count = values.len().min(10);
781 let recent_values = &values[values.len() - recent_count..];
782
783 let mean = recent_values.iter().cloned().sum::<A>() / A::from(recent_count).unwrap();
784 let variance = recent_values
785 .iter()
786 .map(|&v| (v - mean) * (v - mean))
787 .sum::<A>()
788 / A::from(recent_count).unwrap();
789
790 Ok(variance.sqrt())
791 }
792
793 fn update_with_actual(&mut self, snapshot: &PerformanceSnapshot<A>) -> Result<(), String> {
794 let mut updated_predictions = Vec::new();
796
797 for prediction in &mut self.prediction_history {
798 if prediction.actual_value.is_none() {
799 let time_diff = snapshot.timestamp.duration_since(prediction.timestamp);
800 let expected_duration = Duration::from_secs(prediction.steps_ahead as u64 * 10); if time_diff >= expected_duration {
803 prediction.actual_value = Some(snapshot.loss);
804 updated_predictions.push(prediction.clone());
805 }
806 }
807 }
808
809 for prediction in &updated_predictions {
811 self.update_accuracy_metrics(prediction)?;
812 }
813
814 Ok(())
815 }
816
817 fn update_accuracy_metrics(&mut self, prediction: &PredictionResult<A>) -> Result<(), String> {
818 if let Some(actual) = prediction.actual_value {
819 let error = (prediction.predicted_value - actual).abs();
820 let relative_error = error / actual.max(A::from(1e-8).unwrap());
821
822 let accuracy = A::one() - relative_error.min(A::one());
824 let method_name = &prediction.method;
825
826 self.model_accuracies.insert(method_name.clone(), accuracy);
827 }
828
829 Ok(())
830 }
831
832 fn get_average_accuracy(&self) -> f64 {
833 if self.model_accuracies.is_empty() {
834 return 0.0;
835 }
836
837 let sum: A = self.model_accuracies.values().cloned().sum();
838 let avg = sum / A::from(self.model_accuracies.len()).unwrap();
839 avg.to_f64().unwrap_or(0.0)
840 }
841
842 fn reset(&mut self) {
843 self.prediction_history.clear();
844 self.model_accuracies.clear();
845 self.ensemble_weights.clear();
846 }
847}
848
849impl<A: Float + Default + Clone + Sum + Send + Sync + Send + Sync>
850 PerformanceImprovementTracker<A>
851{
852 fn new() -> Self {
853 Self {
854 baseline_metrics: HashMap::new(),
855 improvement_rates: HashMap::new(),
856 improvement_history: VecDeque::with_capacity(1000),
857 plateau_detector: PlateauDetector::new(50, A::from(0.01).unwrap()),
858 }
859 }
860
861 fn update(&mut self, snapshot: &PerformanceSnapshot<A>) -> Result<(), String> {
862 if self.baseline_metrics.is_empty() {
864 self.baseline_metrics
865 .insert("loss".to_string(), snapshot.loss);
866 if let Some(accuracy) = snapshot.accuracy {
867 self.baseline_metrics
868 .insert("accuracy".to_string(), accuracy);
869 }
870 }
871
872 if let Some(&baseline_loss) = self.baseline_metrics.get("loss") {
874 if snapshot.loss < baseline_loss {
875 let improvement = baseline_loss - snapshot.loss;
876 let improvement_event = ImprovementEvent {
877 timestamp: snapshot.timestamp,
878 metric_name: "loss".to_string(),
879 improvement,
880 improvement_rate: improvement / A::from(1.0).unwrap(), context: "optimization_step".to_string(),
882 };
883
884 if self.improvement_history.len() >= 1000 {
885 self.improvement_history.pop_front();
886 }
887 self.improvement_history.push_back(improvement_event);
888
889 self.baseline_metrics
891 .insert("loss".to_string(), snapshot.loss);
892 }
893 }
894
895 self.plateau_detector.update(snapshot.loss);
897
898 Ok(())
899 }
900
901 fn reset(&mut self) {
902 self.baseline_metrics.clear();
903 self.improvement_rates.clear();
904 self.improvement_history.clear();
905 self.plateau_detector.reset();
906 }
907}
908
909impl<A: Float + Default + Clone + Send + Sync + std::iter::Sum> PlateauDetector<A> {
910 fn new(window_size: usize, threshold: A) -> Self {
911 Self {
912 window_size,
913 plateau_threshold: threshold,
914 recent_values: VecDeque::with_capacity(window_size),
915 is_plateau: false,
916 plateau_duration: Duration::ZERO,
917 last_significant_change: None,
918 }
919 }
920
921 fn update(&mut self, value: A) {
922 if self.recent_values.len() >= self.window_size {
923 self.recent_values.pop_front();
924 }
925 self.recent_values.push_back(value);
926
927 if self.recent_values.len() >= self.window_size {
928 self.detect_plateau();
929 }
930 }
931
932 fn detect_plateau(&mut self) {
933 if self.recent_values.len() < 2 {
934 return;
935 }
936
937 let max_val = self.recent_values.iter().cloned().fold(A::zero(), A::max);
938 let min_val = self.recent_values.iter().cloned().fold(A::zero(), A::min);
939 let range = max_val - min_val;
940
941 let was_plateau = self.is_plateau;
942 self.is_plateau = range < self.plateau_threshold;
943
944 if self.is_plateau && !was_plateau {
945 self.plateau_duration = Duration::ZERO;
946 } else if self.is_plateau {
947 self.plateau_duration += Duration::from_secs(1); } else if !self.is_plateau {
949 self.last_significant_change = Some(Instant::now());
950 self.plateau_duration = Duration::ZERO;
951 }
952 }
953
954 fn reset(&mut self) {
955 self.recent_values.clear();
956 self.is_plateau = false;
957 self.plateau_duration = Duration::ZERO;
958 self.last_significant_change = None;
959 }
960}
961
962impl<A: Float + Default + Clone + Sum + Send + Sync + Send + Sync> PerformanceAnomalyDetector<A> {
963 fn new(threshold: f64) -> Self {
964 Self {
965 threshold: A::from(threshold).unwrap(),
966 historical_stats: HashMap::new(),
967 recent_anomalies: VecDeque::with_capacity(100),
968 adaptive_threshold: true,
969 }
970 }
971
972 fn check_for_anomalies(
973 &mut self,
974 snapshot: &PerformanceSnapshot<A>,
975 ) -> Result<Vec<PerformanceAnomaly<A>>, String> {
976 let mut anomalies = Vec::new();
977
978 let loss_anomaly = self.check_metric_anomaly("loss", snapshot.loss, snapshot.timestamp)?;
980 if let Some(anomaly) = loss_anomaly {
981 anomalies.push(anomaly);
982 }
983
984 if let Some(accuracy) = snapshot.accuracy {
986 let accuracy_anomaly =
987 self.check_metric_anomaly("accuracy", accuracy, snapshot.timestamp)?;
988 if let Some(anomaly) = accuracy_anomaly {
989 anomalies.push(anomaly);
990 }
991 }
992
993 Ok(anomalies)
994 }
995
996 fn check_metric_anomaly(
997 &mut self,
998 metric_name: &str,
999 value: A,
1000 timestamp: Instant,
1001 ) -> Result<Option<PerformanceAnomaly<A>>, String> {
1002 let stats = self
1004 .historical_stats
1005 .entry(metric_name.to_string())
1006 .or_insert_with(|| MetricStatistics {
1007 mean: value,
1008 variance: A::zero(),
1009 min_value: value,
1010 max_value: value,
1011 count: 0,
1012 last_update: timestamp,
1013 });
1014
1015 stats.count += 1;
1017 let delta = value - stats.mean;
1018 stats.mean = stats.mean + delta / A::from(stats.count).unwrap();
1019 let delta2 = value - stats.mean;
1020 stats.variance = stats.variance + delta * delta2;
1021 stats.min_value = stats.min_value.min(value);
1022 stats.max_value = stats.max_value.max(value);
1023 stats.last_update = timestamp;
1024
1025 if stats.count >= 10 {
1027 let std_dev = (stats.variance / A::from(stats.count - 1).unwrap()).sqrt();
1028 let z_score = (value - stats.mean) / std_dev.max(A::from(1e-8).unwrap());
1029
1030 if z_score.abs() > self.threshold {
1031 let severity = if z_score.abs() > A::from(3.0).unwrap() {
1032 AnomalySeverity::Critical
1033 } else if z_score.abs() > A::from(2.5).unwrap() {
1034 AnomalySeverity::Major
1035 } else {
1036 AnomalySeverity::Moderate
1037 };
1038
1039 let anomaly_type = if z_score > A::zero() {
1040 AnomalyType::High
1041 } else {
1042 AnomalyType::Low
1043 };
1044
1045 let expected_range = (
1046 stats.mean - self.threshold * std_dev,
1047 stats.mean + self.threshold * std_dev,
1048 );
1049
1050 let anomaly = PerformanceAnomaly {
1051 timestamp,
1052 metric_name: metric_name.to_string(),
1053 observed_value: value,
1054 expected_range,
1055 severity,
1056 anomaly_type,
1057 };
1058
1059 return Ok(Some(anomaly));
1060 }
1061 }
1062
1063 Ok(None)
1064 }
1065
1066 fn update_threshold(&mut self, new_threshold: A) {
1067 self.threshold = new_threshold;
1068 }
1069
1070 fn reset(&mut self) {
1071 self.historical_stats.clear();
1072 self.recent_anomalies.clear();
1073 }
1074}
1075
1076#[derive(Debug, Clone)]
1078pub struct PerformanceDiagnostics {
1079 pub history_size: usize,
1080 pub baseline_set: bool,
1081 pub trends_available: bool,
1082 pub anomalies_detected: usize,
1083 pub plateau_detected: bool,
1084 pub prediction_accuracy: f64,
1085}