quantrs2_device/dynamical_decoupling/
adaptive.rs

1//! Adaptive dynamical decoupling system with real-time optimization
2
3use 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/// Adaptive DD system state
30#[derive(Debug, Clone)]
31pub struct AdaptiveDDState {
32    /// Current sequence being used
33    pub current_sequence: DDSequence,
34    /// Performance history
35    pub performance_history: Vec<PerformanceRecord>,
36    /// Noise characteristics history
37    pub noise_history: Vec<NoiseRecord>,
38    /// Adaptation history
39    pub adaptation_history: Vec<AdaptationRecord>,
40    /// Current performance metrics
41    pub current_metrics: PerformanceMetrics,
42    /// System health status
43    pub system_health: SystemHealth,
44}
45
46/// Performance record for historical tracking
47#[derive(Debug, Clone)]
48pub struct PerformanceRecord {
49    /// Timestamp
50    pub timestamp: Instant,
51    /// Coherence time
52    pub coherence_time: f64,
53    /// Process fidelity
54    pub fidelity: f64,
55    /// Gate overhead
56    pub gate_overhead: f64,
57    /// Success rate
58    pub success_rate: f64,
59    /// Resource utilization
60    pub resource_utilization: f64,
61}
62
63/// Noise record for historical tracking
64#[derive(Debug, Clone)]
65pub struct NoiseRecord {
66    /// Timestamp
67    pub timestamp: Instant,
68    /// Noise level by type
69    pub noise_levels: HashMap<String, f64>,
70    /// Dominant noise sources
71    pub dominant_sources: Vec<String>,
72    /// Environmental conditions
73    pub environmental_conditions: EnvironmentalConditions,
74}
75
76/// Environmental conditions
77#[derive(Debug, Clone)]
78pub struct EnvironmentalConditions {
79    /// Temperature
80    pub temperature: f64,
81    /// Magnetic field strength
82    pub magnetic_field: f64,
83    /// Electromagnetic interference level
84    pub emi_level: f64,
85    /// Vibration level
86    pub vibration_level: f64,
87}
88
89/// Adaptation record
90#[derive(Debug, Clone)]
91pub struct AdaptationRecord {
92    /// Timestamp
93    pub timestamp: Instant,
94    /// Previous sequence
95    pub previous_sequence: DDSequenceType,
96    /// New sequence
97    pub new_sequence: DDSequenceType,
98    /// Reason for adaptation
99    pub adaptation_reason: AdaptationReason,
100    /// Expected improvement
101    pub expected_improvement: f64,
102    /// Actual improvement (if measured)
103    pub actual_improvement: Option<f64>,
104}
105
106/// Reasons for adaptation
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub enum AdaptationReason {
109    /// Performance degradation
110    PerformanceDegradation,
111    /// Noise change
112    NoiseChange,
113    /// Environmental change
114    EnvironmentalChange,
115    /// Scheduled optimization
116    ScheduledOptimization,
117    /// Learning-based improvement
118    LearningImprovement,
119    /// Emergency intervention
120    Emergency,
121}
122
123/// Current performance metrics
124#[derive(Debug, Clone)]
125pub struct PerformanceMetrics {
126    /// Real-time coherence time
127    pub coherence_time: f64,
128    /// Real-time fidelity
129    pub fidelity: f64,
130    /// Error rates
131    pub error_rates: HashMap<String, f64>,
132    /// Resource usage
133    pub resource_usage: ResourceUsage,
134    /// Throughput
135    pub throughput: f64,
136    /// Latency
137    pub latency: Duration,
138}
139
140/// Resource usage tracking
141#[derive(Debug, Clone)]
142pub struct ResourceUsage {
143    /// CPU utilization
144    pub cpu_utilization: f64,
145    /// Memory usage
146    pub memory_usage: usize,
147    /// Network bandwidth usage
148    pub network_usage: f64,
149    /// Power consumption
150    pub power_consumption: f64,
151}
152
153/// System health status
154#[derive(Debug, Clone)]
155pub struct SystemHealth {
156    /// Overall health score (0.0 to 1.0)
157    pub health_score: f64,
158    /// Component health
159    pub component_health: HashMap<String, f64>,
160    /// Active alerts
161    pub active_alerts: Vec<Alert>,
162    /// Predicted issues
163    pub predicted_issues: Vec<PredictedIssue>,
164}
165
166/// System alert
167#[derive(Debug, Clone)]
168pub struct Alert {
169    /// Alert type
170    pub alert_type: AlertType,
171    /// Severity level
172    pub severity: AlertSeverity,
173    /// Message
174    pub message: String,
175    /// Timestamp
176    pub timestamp: Instant,
177    /// Suggested actions
178    pub suggested_actions: Vec<String>,
179}
180
181/// Alert types
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub enum AlertType {
184    PerformanceDegradation,
185    NoiseIncrease,
186    HardwareFailure,
187    TemperatureAnomaly,
188    ResourceExhaustion,
189    CommunicationLoss,
190}
191
192/// Alert severity levels
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum AlertSeverity {
195    Info,
196    Warning,
197    Error,
198    Critical,
199}
200
201/// Predicted issue
202#[derive(Debug, Clone)]
203pub struct PredictedIssue {
204    /// Issue type
205    pub issue_type: String,
206    /// Probability
207    pub probability: f64,
208    /// Time to occurrence
209    pub time_to_occurrence: Duration,
210    /// Potential impact
211    pub potential_impact: f64,
212    /// Prevention strategies
213    pub prevention_strategies: Vec<String>,
214}
215
216/// Adaptive DD system
217pub struct AdaptiveDDSystem {
218    /// Configuration
219    config: AdaptiveDDConfig,
220    /// Current state
221    state: Arc<Mutex<AdaptiveDDState>>,
222    /// Available sequence types
223    available_sequences: Vec<DDSequenceType>,
224    /// Learning agent
225    learning_agent: Option<LearningAgent>,
226    /// Feedback controller
227    feedback_controller: FeedbackController,
228    /// Real-time monitor
229    monitor: RealTimeMonitor,
230    /// Sequence cache
231    sequence_cache: HashMap<String, DDSequence>,
232}
233
234/// Learning agent for adaptive DD
235struct LearningAgent {
236    /// Q-table for Q-learning (simplified)
237    q_table: HashMap<(String, String), f64>,
238    /// Experience replay buffer
239    replay_buffer: Vec<Experience>,
240    /// Exploration strategy
241    exploration_strategy: ExplorationStrategy,
242    /// Learning statistics
243    learning_stats: LearningStatistics,
244    /// Action count tracking for exploration
245    action_counts: HashMap<String, u32>,
246}
247
248/// Experience for learning
249#[derive(Debug, Clone)]
250struct Experience {
251    /// State representation
252    state: String,
253    /// Action taken
254    action: String,
255    /// Reward received
256    reward: f64,
257    /// Next state
258    next_state: String,
259    /// Done flag
260    done: bool,
261}
262
263/// Learning statistics
264#[derive(Debug, Clone)]
265struct LearningStatistics {
266    /// Total episodes
267    total_episodes: usize,
268    /// Average reward
269    average_reward: f64,
270    /// Exploration rate
271    exploration_rate: f64,
272    /// Learning rate
273    learning_rate: f64,
274}
275
276/// Feedback controller
277struct FeedbackController {
278    /// Control algorithm
279    algorithm: ControlAlgorithm,
280    /// PID state
281    pid_state: PIDState,
282    /// Control history
283    control_history: Vec<ControlAction>,
284}
285
286/// PID controller state
287#[derive(Debug, Clone)]
288struct PIDState {
289    /// Previous error
290    previous_error: f64,
291    /// Integral accumulator
292    integral: f64,
293    /// Last update time
294    last_update: Instant,
295}
296
297/// Control action
298#[derive(Debug, Clone)]
299struct ControlAction {
300    /// Timestamp
301    timestamp: Instant,
302    /// Control output
303    output: f64,
304    /// Target value
305    target: f64,
306    /// Current value
307    current: f64,
308    /// Error
309    error: f64,
310}
311
312/// Real-time monitor
313struct RealTimeMonitor {
314    /// Monitoring thread handle
315    monitoring_enabled: bool,
316    /// Metric collectors
317    metric_collectors: HashMap<MonitoringMetric, MetricCollector>,
318    /// Alert manager
319    alert_manager: AlertManager,
320}
321
322/// Metric collector
323struct MetricCollector {
324    /// Last collected value
325    last_value: f64,
326    /// Collection history
327    history: Vec<(Instant, f64)>,
328    /// Moving average
329    moving_average: f64,
330    /// Threshold values
331    thresholds: (f64, f64), // (warning, critical)
332}
333
334/// Alert manager
335struct AlertManager {
336    /// Active alerts
337    active_alerts: Vec<Alert>,
338    /// Alert history
339    alert_history: Vec<Alert>,
340    /// Alert rules
341    alert_rules: Vec<AlertRule>,
342}
343
344/// Alert rule
345struct AlertRule {
346    /// Metric to monitor
347    metric: MonitoringMetric,
348    /// Condition
349    condition: AlertCondition,
350    /// Threshold value
351    threshold: f64,
352    /// Severity
353    severity: AlertSeverity,
354    /// Message template
355    message_template: String,
356}
357
358/// Alert conditions
359#[derive(Debug, Clone, PartialEq)]
360enum AlertCondition {
361    GreaterThan,
362    LessThan,
363    Equal,
364    RateOfChange,
365    Anomaly,
366}
367
368impl AdaptiveDDSystem {
369    /// Create new adaptive DD system
370    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    /// Start adaptive DD system
447    pub fn start(&mut self, executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
448        println!("Starting adaptive DD system");
449
450        // Initialize monitoring
451        self.initialize_monitoring()?;
452
453        // Start feedback control loop
454        self.start_control_loop(executor)?;
455
456        Ok(())
457    }
458
459    /// Update system with new performance data
460    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        // Record performance
471        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        // Record noise characteristics
502        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, // Would be read from sensors
520                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        // Update current metrics
528        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        // Check for adaptation triggers
540        if self.should_adapt(&state)? {
541            drop(state); // Release lock before adaptation
542            self.trigger_adaptation()?;
543        }
544
545        Ok(())
546    }
547
548    /// Check if adaptation should be triggered
549    fn should_adapt(&self, state: &AdaptiveDDState) -> DeviceResult<bool> {
550        let criteria = &self.config.adaptation_criteria;
551
552        // Check coherence time degradation
553        if state.current_metrics.coherence_time < criteria.coherence_threshold {
554            return Ok(true);
555        }
556
557        // Check fidelity degradation
558        if state.current_metrics.fidelity < criteria.fidelity_threshold {
559            return Ok(true);
560        }
561
562        // Check noise level increase
563        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    /// Trigger adaptation process
573    fn trigger_adaptation(&mut self) -> DeviceResult<()> {
574        println!("Triggering DD adaptation");
575
576        // Analyze current performance
577        let current_state = self.analyze_current_state()?;
578
579        // Select new sequence
580        let new_sequence_type = self.select_optimal_sequence(&current_state)?;
581
582        // Generate new sequence
583        let new_sequence = self.generate_sequence(&new_sequence_type)?;
584
585        // Record adaptation
586        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, // Estimated improvement
600            actual_improvement: None,
601        };
602
603        // Update state
604        {
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    /// Analyze current system state
617    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        // Create state representation for learning
624        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    /// Select optimal sequence based on current conditions
658    fn select_optimal_sequence(&mut self, current_state: &str) -> DeviceResult<DDSequenceType> {
659        // Use learning agent if available
660        if let Some(ref mut agent) = self.learning_agent {
661            // Clone the available sequences to avoid borrowing conflicts
662            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        // Fallback to rule-based selection
671        self.select_sequence_rule_based(current_state)
672    }
673
674    /// Select sequence using learning agent (static method)
675    fn select_sequence_with_learning_static(
676        agent: &mut LearningAgent,
677        current_state: &str,
678        available_sequences: &[DDSequenceType],
679    ) -> DeviceResult<DDSequenceType> {
680        // Get Q-values for all available actions
681        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        // Apply exploration
699        match agent.exploration_strategy {
700            ExplorationStrategy::EpsilonGreedy(epsilon) => {
701                if thread_rng().gen::<f64>() < epsilon {
702                    // Random exploration
703                    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                // Upper Confidence Bound exploration
709                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 // Unvisited actions get highest priority
725                    };
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                // Softmax exploration
735                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                // Normalize probabilities
751                for prob in &mut probabilities {
752                    *prob /= exp_sum;
753                }
754
755                // Sample from distribution
756                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                // Thompson sampling exploration (simplified implementation)
768                // For now, use epsilon-greedy with a fixed epsilon as fallback
769                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    /// Select sequence using learning agent
780    fn select_sequence_with_learning(
781        &self,
782        agent: &mut LearningAgent,
783        current_state: &str,
784    ) -> DeviceResult<DDSequenceType> {
785        // Get Q-values for all available actions
786        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        // Apply exploration
804        if let ExplorationStrategy::EpsilonGreedy(epsilon) = agent.exploration_strategy {
805            if thread_rng().gen::<f64>() < epsilon {
806                // Explore: select random sequence
807                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            // Use greedy selection
812        }
813
814        Ok(best_sequence)
815    }
816
817    /// Select sequence using rule-based approach
818    fn select_sequence_rule_based(&self, current_state: &str) -> DeviceResult<DDSequenceType> {
819        // Simple rule-based selection
820        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    /// Generate sequence of specified type
829    fn generate_sequence(&mut self, sequence_type: &DDSequenceType) -> DeviceResult<DDSequence> {
830        // Check cache first
831        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        // Generate new sequence
837        let target_qubits = vec![
838            quantrs2_core::qubit::QubitId(0),
839            quantrs2_core::qubit::QubitId(1),
840        ];
841        let duration = 100e-6; // 100 microseconds
842
843        let sequence =
844            DDSequenceGenerator::generate_base_sequence(sequence_type, &target_qubits, duration)?;
845
846        // Cache the sequence
847        self.sequence_cache.insert(cache_key, sequence.clone());
848
849        Ok(sequence)
850    }
851
852    /// Initialize monitoring system
853    fn initialize_monitoring(&mut self) -> DeviceResult<()> {
854        println!("Initializing DD monitoring system");
855
856        // Initialize metric collectors
857        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), // Warning and critical thresholds
863            };
864            self.monitor
865                .metric_collectors
866                .insert(metric.clone(), collector);
867        }
868
869        // Initialize alert rules
870        self.monitor.alert_manager.alert_rules.push(AlertRule {
871            metric: MonitoringMetric::CoherenceTime,
872            condition: AlertCondition::LessThan,
873            threshold: 20e-6, // 20 microseconds
874            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    /// Start control loop
890    fn start_control_loop(&mut self, _executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
891        println!("Starting DD control loop");
892
893        // In a real implementation, this would start a background thread
894        // for continuous monitoring and control
895
896        Ok(())
897    }
898
899    /// Get current system state
900    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    /// Get performance history
908    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    /// Get adaptation statistics
916    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    /// Get most used sequence type
953    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    /// Calculate adaptation frequency
971    fn calculate_adaptation_frequency(&self, state: &AdaptiveDDState) -> f64 {
972        if state.adaptation_history.len() < 2 {
973            return 0.0;
974        }
975
976        // Safe to use expect here since we already checked len() >= 2
977        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/// Adaptation statistics
998#[derive(Debug, Clone)]
999pub struct AdaptationStatistics {
1000    /// Total number of adaptations
1001    pub total_adaptations: usize,
1002    /// Number of successful adaptations
1003    pub successful_adaptations: usize,
1004    /// Success rate
1005    pub success_rate: f64,
1006    /// Average improvement per adaptation
1007    pub average_improvement: f64,
1008    /// Most frequently used sequence
1009    pub most_used_sequence: DDSequenceType,
1010    /// Adaptation frequency (adaptations per second)
1011    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}