1use scirs2_core::random::prelude::*;
4use std::collections::HashMap;
5use std::sync::{Arc, Mutex};
6use std::time::{Duration, Instant};
7
8use scirs2_core::random::Rng;
9
10use quantrs2_circuit::prelude::Circuit;
11use quantrs2_core::qubit::QubitId;
12use scirs2_core::ndarray::{Array1, Array2};
13
14use super::{
15 config::{
16 AdaptationCriteria, AdaptiveDDConfig, ControlAlgorithm, DDPerformanceMetric,
17 DDSequenceType, ExplorationStrategy, FeedbackControlConfig, LearningAlgorithm,
18 LearningConfig, MonitoringConfig, MonitoringMetric,
19 },
20 noise::DDNoiseAnalysis,
21 performance::DDPerformanceAnalysis,
22 sequences::{DDSequence, DDSequenceGenerator},
23 DDCircuitExecutor,
24};
25use crate::{DeviceError, DeviceResult};
26#[allow(unused_imports)]
27use std::cmp::Ordering;
28
29#[derive(Debug, Clone)]
31pub struct AdaptiveDDState {
32 pub current_sequence: DDSequence,
34 pub performance_history: Vec<PerformanceRecord>,
36 pub noise_history: Vec<NoiseRecord>,
38 pub adaptation_history: Vec<AdaptationRecord>,
40 pub current_metrics: PerformanceMetrics,
42 pub system_health: SystemHealth,
44}
45
46#[derive(Debug, Clone)]
48pub struct PerformanceRecord {
49 pub timestamp: Instant,
51 pub coherence_time: f64,
53 pub fidelity: f64,
55 pub gate_overhead: f64,
57 pub success_rate: f64,
59 pub resource_utilization: f64,
61}
62
63#[derive(Debug, Clone)]
65pub struct NoiseRecord {
66 pub timestamp: Instant,
68 pub noise_levels: HashMap<String, f64>,
70 pub dominant_sources: Vec<String>,
72 pub environmental_conditions: EnvironmentalConditions,
74}
75
76#[derive(Debug, Clone)]
78pub struct EnvironmentalConditions {
79 pub temperature: f64,
81 pub magnetic_field: f64,
83 pub emi_level: f64,
85 pub vibration_level: f64,
87}
88
89#[derive(Debug, Clone)]
91pub struct AdaptationRecord {
92 pub timestamp: Instant,
94 pub previous_sequence: DDSequenceType,
96 pub new_sequence: DDSequenceType,
98 pub adaptation_reason: AdaptationReason,
100 pub expected_improvement: f64,
102 pub actual_improvement: Option<f64>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
108pub enum AdaptationReason {
109 PerformanceDegradation,
111 NoiseChange,
113 EnvironmentalChange,
115 ScheduledOptimization,
117 LearningImprovement,
119 Emergency,
121}
122
123#[derive(Debug, Clone)]
125pub struct PerformanceMetrics {
126 pub coherence_time: f64,
128 pub fidelity: f64,
130 pub error_rates: HashMap<String, f64>,
132 pub resource_usage: ResourceUsage,
134 pub throughput: f64,
136 pub latency: Duration,
138}
139
140#[derive(Debug, Clone)]
142pub struct ResourceUsage {
143 pub cpu_utilization: f64,
145 pub memory_usage: usize,
147 pub network_usage: f64,
149 pub power_consumption: f64,
151}
152
153#[derive(Debug, Clone)]
155pub struct SystemHealth {
156 pub health_score: f64,
158 pub component_health: HashMap<String, f64>,
160 pub active_alerts: Vec<Alert>,
162 pub predicted_issues: Vec<PredictedIssue>,
164}
165
166#[derive(Debug, Clone)]
168pub struct Alert {
169 pub alert_type: AlertType,
171 pub severity: AlertSeverity,
173 pub message: String,
175 pub timestamp: Instant,
177 pub suggested_actions: Vec<String>,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
183pub enum AlertType {
184 PerformanceDegradation,
185 NoiseIncrease,
186 HardwareFailure,
187 TemperatureAnomaly,
188 ResourceExhaustion,
189 CommunicationLoss,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum AlertSeverity {
195 Info,
196 Warning,
197 Error,
198 Critical,
199}
200
201#[derive(Debug, Clone)]
203pub struct PredictedIssue {
204 pub issue_type: String,
206 pub probability: f64,
208 pub time_to_occurrence: Duration,
210 pub potential_impact: f64,
212 pub prevention_strategies: Vec<String>,
214}
215
216pub struct AdaptiveDDSystem {
218 config: AdaptiveDDConfig,
220 state: Arc<Mutex<AdaptiveDDState>>,
222 available_sequences: Vec<DDSequenceType>,
224 learning_agent: Option<LearningAgent>,
226 feedback_controller: FeedbackController,
228 monitor: RealTimeMonitor,
230 sequence_cache: HashMap<String, DDSequence>,
232}
233
234struct LearningAgent {
236 q_table: HashMap<(String, String), f64>,
238 replay_buffer: Vec<Experience>,
240 exploration_strategy: ExplorationStrategy,
242 learning_stats: LearningStatistics,
244 action_counts: HashMap<String, u32>,
246}
247
248#[derive(Debug, Clone)]
250struct Experience {
251 state: String,
253 action: String,
255 reward: f64,
257 next_state: String,
259 done: bool,
261}
262
263#[derive(Debug, Clone)]
265struct LearningStatistics {
266 total_episodes: usize,
268 average_reward: f64,
270 exploration_rate: f64,
272 learning_rate: f64,
274}
275
276struct FeedbackController {
278 algorithm: ControlAlgorithm,
280 pid_state: PIDState,
282 control_history: Vec<ControlAction>,
284}
285
286#[derive(Debug, Clone)]
288struct PIDState {
289 previous_error: f64,
291 integral: f64,
293 last_update: Instant,
295}
296
297#[derive(Debug, Clone)]
299struct ControlAction {
300 timestamp: Instant,
302 output: f64,
304 target: f64,
306 current: f64,
308 error: f64,
310}
311
312struct RealTimeMonitor {
314 monitoring_enabled: bool,
316 metric_collectors: HashMap<MonitoringMetric, MetricCollector>,
318 alert_manager: AlertManager,
320}
321
322struct MetricCollector {
324 last_value: f64,
326 history: Vec<(Instant, f64)>,
328 moving_average: f64,
330 thresholds: (f64, f64), }
333
334struct AlertManager {
336 active_alerts: Vec<Alert>,
338 alert_history: Vec<Alert>,
340 alert_rules: Vec<AlertRule>,
342}
343
344struct AlertRule {
346 metric: MonitoringMetric,
348 condition: AlertCondition,
350 threshold: f64,
352 severity: AlertSeverity,
354 message_template: String,
356}
357
358#[derive(Debug, Clone, PartialEq)]
360enum AlertCondition {
361 GreaterThan,
362 LessThan,
363 Equal,
364 RateOfChange,
365 Anomaly,
366}
367
368impl AdaptiveDDSystem {
369 pub fn new(
371 config: AdaptiveDDConfig,
372 initial_sequence: DDSequence,
373 available_sequences: Vec<DDSequenceType>,
374 ) -> Self {
375 let initial_state = AdaptiveDDState {
376 current_sequence: initial_sequence,
377 performance_history: Vec::new(),
378 noise_history: Vec::new(),
379 adaptation_history: Vec::new(),
380 current_metrics: PerformanceMetrics {
381 coherence_time: 0.0,
382 fidelity: 0.0,
383 error_rates: HashMap::new(),
384 resource_usage: ResourceUsage {
385 cpu_utilization: 0.0,
386 memory_usage: 0,
387 network_usage: 0.0,
388 power_consumption: 0.0,
389 },
390 throughput: 0.0,
391 latency: Duration::from_nanos(0),
392 },
393 system_health: SystemHealth {
394 health_score: 1.0,
395 component_health: HashMap::new(),
396 active_alerts: Vec::new(),
397 predicted_issues: Vec::new(),
398 },
399 };
400
401 let learning_agent =
402 if config.learning_config.learning_algorithm == LearningAlgorithm::QLearning {
403 Some(LearningAgent {
404 q_table: HashMap::new(),
405 replay_buffer: Vec::new(),
406 exploration_strategy: ExplorationStrategy::EpsilonGreedy(0.1),
407 learning_stats: LearningStatistics {
408 total_episodes: 0,
409 average_reward: 0.0,
410 exploration_rate: 0.1,
411 learning_rate: config.learning_config.learning_rate,
412 },
413 action_counts: HashMap::new(),
414 })
415 } else {
416 None
417 };
418
419 Self {
420 config,
421 state: Arc::new(Mutex::new(initial_state)),
422 available_sequences,
423 learning_agent,
424 feedback_controller: FeedbackController {
425 algorithm: ControlAlgorithm::PID,
426 pid_state: PIDState {
427 previous_error: 0.0,
428 integral: 0.0,
429 last_update: Instant::now(),
430 },
431 control_history: Vec::new(),
432 },
433 monitor: RealTimeMonitor {
434 monitoring_enabled: true,
435 metric_collectors: HashMap::new(),
436 alert_manager: AlertManager {
437 active_alerts: Vec::new(),
438 alert_history: Vec::new(),
439 alert_rules: Vec::new(),
440 },
441 },
442 sequence_cache: HashMap::new(),
443 }
444 }
445
446 pub fn start(&mut self, executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
448 println!("Starting adaptive DD system");
449
450 self.initialize_monitoring()?;
452
453 self.start_control_loop(executor)?;
455
456 Ok(())
457 }
458
459 pub fn update_performance(
461 &mut self,
462 performance_analysis: &DDPerformanceAnalysis,
463 noise_analysis: &DDNoiseAnalysis,
464 ) -> DeviceResult<()> {
465 let mut state = self
466 .state
467 .lock()
468 .map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?;
469
470 let performance_record = PerformanceRecord {
472 timestamp: Instant::now(),
473 coherence_time: performance_analysis
474 .metrics
475 .get(&DDPerformanceMetric::CoherenceTime)
476 .copied()
477 .unwrap_or(0.0),
478 fidelity: performance_analysis
479 .metrics
480 .get(&DDPerformanceMetric::ProcessFidelity)
481 .copied()
482 .unwrap_or(0.95),
483 gate_overhead: performance_analysis
484 .metrics
485 .get(&DDPerformanceMetric::GateOverhead)
486 .copied()
487 .unwrap_or(1.0),
488 success_rate: performance_analysis
489 .metrics
490 .get(&DDPerformanceMetric::RobustnessScore)
491 .copied()
492 .unwrap_or(0.9),
493 resource_utilization: performance_analysis
494 .metrics
495 .get(&DDPerformanceMetric::ResourceEfficiency)
496 .copied()
497 .unwrap_or(0.8),
498 };
499 state.performance_history.push(performance_record);
500
501 let noise_record = NoiseRecord {
503 timestamp: Instant::now(),
504 noise_levels: noise_analysis
505 .noise_characterization
506 .noise_types
507 .iter()
508 .map(|(noise_type, characteristics)| {
509 (format!("{noise_type:?}"), characteristics.strength)
510 })
511 .collect(),
512 dominant_sources: noise_analysis
513 .noise_characterization
514 .dominant_sources
515 .iter()
516 .map(|source| format!("{:?}", source.source_type))
517 .collect(),
518 environmental_conditions: EnvironmentalConditions {
519 temperature: 20.0, magnetic_field: 0.1,
521 emi_level: 0.05,
522 vibration_level: 0.02,
523 },
524 };
525 state.noise_history.push(noise_record);
526
527 state.current_metrics.coherence_time = performance_analysis
529 .metrics
530 .get(&DDPerformanceMetric::CoherenceTime)
531 .copied()
532 .unwrap_or(0.0);
533 state.current_metrics.fidelity = performance_analysis
534 .metrics
535 .get(&DDPerformanceMetric::ProcessFidelity)
536 .copied()
537 .unwrap_or(0.95);
538
539 if self.should_adapt(&state)? {
541 drop(state); self.trigger_adaptation()?;
543 }
544
545 Ok(())
546 }
547
548 fn should_adapt(&self, state: &AdaptiveDDState) -> DeviceResult<bool> {
550 let criteria = &self.config.adaptation_criteria;
551
552 if state.current_metrics.coherence_time < criteria.coherence_threshold {
554 return Ok(true);
555 }
556
557 if state.current_metrics.fidelity < criteria.fidelity_threshold {
559 return Ok(true);
560 }
561
562 let average_noise: f64 = state.current_metrics.error_rates.values().sum::<f64>()
564 / state.current_metrics.error_rates.len().max(1) as f64;
565 if average_noise > criteria.noise_threshold {
566 return Ok(true);
567 }
568
569 Ok(false)
570 }
571
572 fn trigger_adaptation(&mut self) -> DeviceResult<()> {
574 println!("Triggering DD adaptation");
575
576 let current_state = self.analyze_current_state()?;
578
579 let new_sequence_type = self.select_optimal_sequence(¤t_state)?;
581
582 let new_sequence = self.generate_sequence(&new_sequence_type)?;
584
585 let previous_sequence_type = self
587 .state
588 .lock()
589 .map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?
590 .current_sequence
591 .sequence_type
592 .clone();
593
594 let adaptation_record = AdaptationRecord {
595 timestamp: Instant::now(),
596 previous_sequence: previous_sequence_type,
597 new_sequence: new_sequence_type,
598 adaptation_reason: AdaptationReason::PerformanceDegradation,
599 expected_improvement: 0.1, actual_improvement: None,
601 };
602
603 {
605 let mut state = self.state.lock().map_err(|_| {
606 DeviceError::LockError("Failed to lock adaptive DD state".to_string())
607 })?;
608 state.current_sequence = new_sequence;
609 state.adaptation_history.push(adaptation_record);
610 }
611
612 println!("DD adaptation completed");
613 Ok(())
614 }
615
616 fn analyze_current_state(&self) -> DeviceResult<String> {
618 let state = self
619 .state
620 .lock()
621 .map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?;
622
623 let coherence_level = if state.current_metrics.coherence_time > 50e-6 {
625 "high"
626 } else if state.current_metrics.coherence_time > 20e-6 {
627 "medium"
628 } else {
629 "low"
630 };
631
632 let fidelity_level = if state.current_metrics.fidelity > 0.99 {
633 "high"
634 } else if state.current_metrics.fidelity > 0.95 {
635 "medium"
636 } else {
637 "low"
638 };
639
640 let noise_level = {
641 let avg_noise: f64 = state.current_metrics.error_rates.values().sum::<f64>()
642 / state.current_metrics.error_rates.len().max(1) as f64;
643 if avg_noise < 0.01 {
644 "low"
645 } else if avg_noise < 0.05 {
646 "medium"
647 } else {
648 "high"
649 }
650 };
651
652 Ok(format!(
653 "coherence_{coherence_level}_fidelity_{fidelity_level}_noise_{noise_level}"
654 ))
655 }
656
657 fn select_optimal_sequence(&mut self, current_state: &str) -> DeviceResult<DDSequenceType> {
659 if let Some(ref mut agent) = self.learning_agent {
661 let available_sequences = self.available_sequences.clone();
663 return Self::select_sequence_with_learning_static(
664 agent,
665 current_state,
666 &available_sequences,
667 );
668 }
669
670 self.select_sequence_rule_based(current_state)
672 }
673
674 fn select_sequence_with_learning_static(
676 agent: &mut LearningAgent,
677 current_state: &str,
678 available_sequences: &[DDSequenceType],
679 ) -> DeviceResult<DDSequenceType> {
680 let mut best_sequence = DDSequenceType::CPMG { n_pulses: 1 };
682 let mut best_q_value = f64::NEG_INFINITY;
683
684 for sequence_type in available_sequences {
685 let action = format!("{sequence_type:?}");
686 let q_value = agent
687 .q_table
688 .get(&(current_state.to_string(), action))
689 .copied()
690 .unwrap_or(0.0);
691
692 if q_value > best_q_value {
693 best_q_value = q_value;
694 best_sequence = sequence_type.clone();
695 }
696 }
697
698 match agent.exploration_strategy {
700 ExplorationStrategy::EpsilonGreedy(epsilon) => {
701 if thread_rng().gen::<f64>() < epsilon {
702 let random_idx = thread_rng().gen_range(0..available_sequences.len());
704 best_sequence = available_sequences[random_idx].clone();
705 }
706 }
707 ExplorationStrategy::UCB(c) => {
708 let total_visits = agent.action_counts.values().sum::<u32>() as f64;
710 let mut best_ucb = f64::NEG_INFINITY;
711
712 for sequence_type in available_sequences {
713 let action = format!("{sequence_type:?}");
714 let visits = agent.action_counts.get(&action).copied().unwrap_or(0) as f64;
715 let q_value = agent
716 .q_table
717 .get(&(current_state.to_string(), action.clone()))
718 .copied()
719 .unwrap_or(0.0);
720
721 let ucb_value = if visits > 0.0 {
722 c.mul_add((total_visits.ln() / visits).sqrt(), q_value)
723 } else {
724 f64::INFINITY };
726
727 if ucb_value > best_ucb {
728 best_ucb = ucb_value;
729 best_sequence = sequence_type.clone();
730 }
731 }
732 }
733 ExplorationStrategy::Boltzmann(temperature) => {
734 let mut probabilities = Vec::new();
736 let mut exp_sum = 0.0;
737
738 for sequence_type in available_sequences {
739 let action = format!("{sequence_type:?}");
740 let q_value = agent
741 .q_table
742 .get(&(current_state.to_string(), action))
743 .copied()
744 .unwrap_or(0.0);
745 let exp_val = (q_value / temperature).exp();
746 probabilities.push(exp_val);
747 exp_sum += exp_val;
748 }
749
750 for prob in &mut probabilities {
752 *prob /= exp_sum;
753 }
754
755 let mut cumsum = 0.0;
757 let rand_val = thread_rng().gen::<f64>();
758 for (i, prob) in probabilities.iter().enumerate() {
759 cumsum += prob;
760 if rand_val <= cumsum {
761 best_sequence = available_sequences[i].clone();
762 break;
763 }
764 }
765 }
766 ExplorationStrategy::ThompsonSampling => {
767 if thread_rng().gen::<f64>() < 0.1 {
770 let random_idx = thread_rng().gen_range(0..available_sequences.len());
771 best_sequence = available_sequences[random_idx].clone();
772 }
773 }
774 }
775
776 Ok(best_sequence)
777 }
778
779 fn select_sequence_with_learning(
781 &self,
782 agent: &mut LearningAgent,
783 current_state: &str,
784 ) -> DeviceResult<DDSequenceType> {
785 let mut best_sequence = DDSequenceType::CPMG { n_pulses: 1 };
787 let mut best_q_value = f64::NEG_INFINITY;
788
789 for sequence_type in &self.available_sequences {
790 let action = format!("{sequence_type:?}");
791 let q_value = agent
792 .q_table
793 .get(&(current_state.to_string(), action))
794 .copied()
795 .unwrap_or(0.0);
796
797 if q_value > best_q_value {
798 best_q_value = q_value;
799 best_sequence = sequence_type.clone();
800 }
801 }
802
803 if let ExplorationStrategy::EpsilonGreedy(epsilon) = agent.exploration_strategy {
805 if thread_rng().gen::<f64>() < epsilon {
806 let random_idx = thread_rng().gen_range(0..self.available_sequences.len());
808 best_sequence = self.available_sequences[random_idx].clone();
809 }
810 } else {
811 }
813
814 Ok(best_sequence)
815 }
816
817 fn select_sequence_rule_based(&self, current_state: &str) -> DeviceResult<DDSequenceType> {
819 match current_state {
821 s if s.contains("noise_high") => Ok(DDSequenceType::XY8),
822 s if s.contains("coherence_low") => Ok(DDSequenceType::UDD { n_pulses: 3 }),
823 s if s.contains("fidelity_low") => Ok(DDSequenceType::XY4),
824 _ => Ok(DDSequenceType::CPMG { n_pulses: 1 }),
825 }
826 }
827
828 fn generate_sequence(&mut self, sequence_type: &DDSequenceType) -> DeviceResult<DDSequence> {
830 let cache_key = format!("{sequence_type:?}");
832 if let Some(cached_sequence) = self.sequence_cache.get(&cache_key) {
833 return Ok(cached_sequence.clone());
834 }
835
836 let target_qubits = vec![
838 quantrs2_core::qubit::QubitId(0),
839 quantrs2_core::qubit::QubitId(1),
840 ];
841 let duration = 100e-6; let sequence =
844 DDSequenceGenerator::generate_base_sequence(sequence_type, &target_qubits, duration)?;
845
846 self.sequence_cache.insert(cache_key, sequence.clone());
848
849 Ok(sequence)
850 }
851
852 fn initialize_monitoring(&mut self) -> DeviceResult<()> {
854 println!("Initializing DD monitoring system");
855
856 for metric in &self.config.monitoring_config.metrics {
858 let collector = MetricCollector {
859 last_value: 0.0,
860 history: Vec::new(),
861 moving_average: 0.0,
862 thresholds: (0.8, 0.6), };
864 self.monitor
865 .metric_collectors
866 .insert(metric.clone(), collector);
867 }
868
869 self.monitor.alert_manager.alert_rules.push(AlertRule {
871 metric: MonitoringMetric::CoherenceTime,
872 condition: AlertCondition::LessThan,
873 threshold: 20e-6, severity: AlertSeverity::Warning,
875 message_template: "Coherence time degraded below threshold".to_string(),
876 });
877
878 self.monitor.alert_manager.alert_rules.push(AlertRule {
879 metric: MonitoringMetric::Fidelity,
880 condition: AlertCondition::LessThan,
881 threshold: 0.95,
882 severity: AlertSeverity::Error,
883 message_template: "Process fidelity degraded below threshold".to_string(),
884 });
885
886 Ok(())
887 }
888
889 fn start_control_loop(&mut self, _executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
891 println!("Starting DD control loop");
892
893 Ok(())
897 }
898
899 pub fn get_current_state(&self) -> AdaptiveDDState {
901 self.state
902 .lock()
903 .map(|state| state.clone())
904 .unwrap_or_else(|poisoned| poisoned.into_inner().clone())
905 }
906
907 pub fn get_performance_history(&self) -> Vec<PerformanceRecord> {
909 self.state
910 .lock()
911 .map(|state| state.performance_history.clone())
912 .unwrap_or_default()
913 }
914
915 pub fn get_adaptation_statistics(&self) -> AdaptationStatistics {
917 let state = match self.state.lock() {
918 Ok(s) => s,
919 Err(poisoned) => poisoned.into_inner(),
920 };
921
922 let total_adaptations = state.adaptation_history.len();
923 let successful_adaptations = state
924 .adaptation_history
925 .iter()
926 .filter(|record| record.actual_improvement.unwrap_or(0.0) > 0.0)
927 .count();
928
929 let success_rate = if total_adaptations > 0 {
930 successful_adaptations as f64 / total_adaptations as f64
931 } else {
932 0.0
933 };
934
935 let average_improvement = state
936 .adaptation_history
937 .iter()
938 .filter_map(|record| record.actual_improvement)
939 .sum::<f64>()
940 / state.adaptation_history.len().max(1) as f64;
941
942 AdaptationStatistics {
943 total_adaptations,
944 successful_adaptations,
945 success_rate,
946 average_improvement,
947 most_used_sequence: self.get_most_used_sequence(&state),
948 adaptation_frequency: self.calculate_adaptation_frequency(&state),
949 }
950 }
951
952 fn get_most_used_sequence(&self, state: &AdaptiveDDState) -> DDSequenceType {
954 let mut sequence_counts: HashMap<DDSequenceType, usize> = HashMap::new();
955
956 for record in &state.adaptation_history {
957 *sequence_counts
958 .entry(record.new_sequence.clone())
959 .or_insert(0) += 1;
960 }
961
962 sequence_counts
963 .into_iter()
964 .max_by_key(|(_, count)| *count)
965 .map_or(DDSequenceType::CPMG { n_pulses: 1 }, |(sequence, _)| {
966 sequence
967 })
968 }
969
970 fn calculate_adaptation_frequency(&self, state: &AdaptiveDDState) -> f64 {
972 if state.adaptation_history.len() < 2 {
973 return 0.0;
974 }
975
976 let first_adaptation = match state.adaptation_history.first() {
978 Some(record) => record.timestamp,
979 None => return 0.0,
980 };
981 let last_adaptation = match state.adaptation_history.last() {
982 Some(record) => record.timestamp,
983 None => return 0.0,
984 };
985 let time_span = last_adaptation
986 .duration_since(first_adaptation)
987 .as_secs_f64();
988
989 if time_span > 0.0 {
990 state.adaptation_history.len() as f64 / time_span
991 } else {
992 0.0
993 }
994 }
995}
996
997#[derive(Debug, Clone)]
999pub struct AdaptationStatistics {
1000 pub total_adaptations: usize,
1002 pub successful_adaptations: usize,
1004 pub success_rate: f64,
1006 pub average_improvement: f64,
1008 pub most_used_sequence: DDSequenceType,
1010 pub adaptation_frequency: f64,
1012}
1013
1014#[cfg(test)]
1015mod tests {
1016 use super::*;
1017 use crate::dynamical_decoupling::{
1018 config::DDSequenceType,
1019 sequences::{DDSequence, DDSequenceProperties, ResourceRequirements, SequenceSymmetry},
1020 };
1021
1022 fn create_test_sequence() -> DDSequence {
1023 DDSequence {
1024 sequence_type: DDSequenceType::CPMG { n_pulses: 1 },
1025 target_qubits: vec![quantrs2_core::qubit::QubitId(0)],
1026 duration: 100e-6,
1027 circuit: Circuit::<32>::new(),
1028 pulse_timings: vec![50e-6],
1029 pulse_phases: vec![std::f64::consts::PI],
1030 properties: DDSequenceProperties {
1031 pulse_count: 1,
1032 sequence_order: 1,
1033 periodicity: 1,
1034 symmetry: SequenceSymmetry {
1035 time_reversal: true,
1036 phase_symmetry: true,
1037 rotational_symmetry: false,
1038 inversion_symmetry: true,
1039 },
1040 noise_suppression: std::collections::HashMap::new(),
1041 resource_requirements: ResourceRequirements {
1042 gate_count: 1,
1043 circuit_depth: 1,
1044 required_connectivity: Vec::new(),
1045 execution_time: 100e-6,
1046 memory_requirements: 8,
1047 },
1048 },
1049 }
1050 }
1051
1052 #[test]
1053 fn test_adaptive_dd_system_creation() {
1054 let config = AdaptiveDDConfig::default();
1055 let initial_sequence = create_test_sequence();
1056 let available_sequences = vec![
1057 DDSequenceType::CPMG { n_pulses: 1 },
1058 DDSequenceType::XY4,
1059 DDSequenceType::XY8,
1060 ];
1061
1062 let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
1063 let state = system.get_current_state();
1064
1065 assert!(matches!(
1066 state.current_sequence.sequence_type,
1067 DDSequenceType::CPMG { .. }
1068 ));
1069 assert_eq!(state.system_health.health_score, 1.0);
1070 }
1071
1072 #[test]
1073 fn test_rule_based_sequence_selection() {
1074 let config = AdaptiveDDConfig::default();
1075 let initial_sequence = create_test_sequence();
1076 let available_sequences = vec![
1077 DDSequenceType::CPMG { n_pulses: 1 },
1078 DDSequenceType::XY4,
1079 DDSequenceType::XY8,
1080 ];
1081
1082 let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
1083
1084 let high_noise_state = "coherence_medium_fidelity_medium_noise_high";
1085 let low_coherence_state = "coherence_low_fidelity_medium_noise_medium";
1086 let low_fidelity_state = "coherence_medium_fidelity_low_noise_medium";
1087
1088 assert_eq!(
1089 system
1090 .select_sequence_rule_based(high_noise_state)
1091 .expect("high noise state should return valid sequence"),
1092 DDSequenceType::XY8
1093 );
1094 assert_eq!(
1095 system
1096 .select_sequence_rule_based(low_coherence_state)
1097 .expect("low coherence state should return valid sequence"),
1098 DDSequenceType::UDD { n_pulses: 3 }
1099 );
1100 assert_eq!(
1101 system
1102 .select_sequence_rule_based(low_fidelity_state)
1103 .expect("low fidelity state should return valid sequence"),
1104 DDSequenceType::XY4
1105 );
1106 }
1107
1108 #[test]
1109 fn test_adaptation_statistics() {
1110 let config = AdaptiveDDConfig::default();
1111 let initial_sequence = create_test_sequence();
1112 let available_sequences = vec![DDSequenceType::CPMG { n_pulses: 1 }, DDSequenceType::XY4];
1113
1114 let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
1115 let stats = system.get_adaptation_statistics();
1116
1117 assert_eq!(stats.total_adaptations, 0);
1118 assert_eq!(stats.success_rate, 0.0);
1119 assert!(matches!(
1120 stats.most_used_sequence,
1121 DDSequenceType::CPMG { .. }
1122 ));
1123 }
1124}