use scirs2_core::random::prelude::*;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use scirs2_core::random::Rng;
use quantrs2_circuit::prelude::Circuit;
use quantrs2_core::qubit::QubitId;
use scirs2_core::ndarray::{Array1, Array2};
use super::{
config::{
AdaptationCriteria, AdaptiveDDConfig, ControlAlgorithm, DDPerformanceMetric,
DDSequenceType, ExplorationStrategy, FeedbackControlConfig, LearningAlgorithm,
LearningConfig, MonitoringConfig, MonitoringMetric,
},
noise::DDNoiseAnalysis,
performance::DDPerformanceAnalysis,
sequences::{DDSequence, DDSequenceGenerator},
DDCircuitExecutor,
};
use crate::{DeviceError, DeviceResult};
#[allow(unused_imports)]
use std::cmp::Ordering;
#[derive(Debug, Clone)]
pub struct AdaptiveDDState {
pub current_sequence: DDSequence,
pub performance_history: Vec<PerformanceRecord>,
pub noise_history: Vec<NoiseRecord>,
pub adaptation_history: Vec<AdaptationRecord>,
pub current_metrics: PerformanceMetrics,
pub system_health: SystemHealth,
}
#[derive(Debug, Clone)]
pub struct PerformanceRecord {
pub timestamp: Instant,
pub coherence_time: f64,
pub fidelity: f64,
pub gate_overhead: f64,
pub success_rate: f64,
pub resource_utilization: f64,
}
#[derive(Debug, Clone)]
pub struct NoiseRecord {
pub timestamp: Instant,
pub noise_levels: HashMap<String, f64>,
pub dominant_sources: Vec<String>,
pub environmental_conditions: EnvironmentalConditions,
}
#[derive(Debug, Clone)]
pub struct EnvironmentalConditions {
pub temperature: f64,
pub magnetic_field: f64,
pub emi_level: f64,
pub vibration_level: f64,
}
#[derive(Debug, Clone)]
pub struct AdaptationRecord {
pub timestamp: Instant,
pub previous_sequence: DDSequenceType,
pub new_sequence: DDSequenceType,
pub adaptation_reason: AdaptationReason,
pub expected_improvement: f64,
pub actual_improvement: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AdaptationReason {
PerformanceDegradation,
NoiseChange,
EnvironmentalChange,
ScheduledOptimization,
LearningImprovement,
Emergency,
}
#[derive(Debug, Clone)]
pub struct PerformanceMetrics {
pub coherence_time: f64,
pub fidelity: f64,
pub error_rates: HashMap<String, f64>,
pub resource_usage: ResourceUsage,
pub throughput: f64,
pub latency: Duration,
}
#[derive(Debug, Clone)]
pub struct ResourceUsage {
pub cpu_utilization: f64,
pub memory_usage: usize,
pub network_usage: f64,
pub power_consumption: f64,
}
#[derive(Debug, Clone)]
pub struct SystemHealth {
pub health_score: f64,
pub component_health: HashMap<String, f64>,
pub active_alerts: Vec<Alert>,
pub predicted_issues: Vec<PredictedIssue>,
}
#[derive(Debug, Clone)]
pub struct Alert {
pub alert_type: AlertType,
pub severity: AlertSeverity,
pub message: String,
pub timestamp: Instant,
pub suggested_actions: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AlertType {
PerformanceDegradation,
NoiseIncrease,
HardwareFailure,
TemperatureAnomaly,
ResourceExhaustion,
CommunicationLoss,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AlertSeverity {
Info,
Warning,
Error,
Critical,
}
#[derive(Debug, Clone)]
pub struct PredictedIssue {
pub issue_type: String,
pub probability: f64,
pub time_to_occurrence: Duration,
pub potential_impact: f64,
pub prevention_strategies: Vec<String>,
}
pub struct AdaptiveDDSystem {
config: AdaptiveDDConfig,
state: Arc<Mutex<AdaptiveDDState>>,
available_sequences: Vec<DDSequenceType>,
learning_agent: Option<LearningAgent>,
feedback_controller: FeedbackController,
monitor: RealTimeMonitor,
sequence_cache: HashMap<String, DDSequence>,
}
struct LearningAgent {
q_table: HashMap<(String, String), f64>,
replay_buffer: Vec<Experience>,
exploration_strategy: ExplorationStrategy,
learning_stats: LearningStatistics,
action_counts: HashMap<String, u32>,
}
#[derive(Debug, Clone)]
struct Experience {
state: String,
action: String,
reward: f64,
next_state: String,
done: bool,
}
#[derive(Debug, Clone)]
struct LearningStatistics {
total_episodes: usize,
average_reward: f64,
exploration_rate: f64,
learning_rate: f64,
}
struct FeedbackController {
algorithm: ControlAlgorithm,
pid_state: PIDState,
control_history: Vec<ControlAction>,
}
#[derive(Debug, Clone)]
struct PIDState {
previous_error: f64,
integral: f64,
last_update: Instant,
}
#[derive(Debug, Clone)]
struct ControlAction {
timestamp: Instant,
output: f64,
target: f64,
current: f64,
error: f64,
}
struct RealTimeMonitor {
monitoring_enabled: bool,
metric_collectors: HashMap<MonitoringMetric, MetricCollector>,
alert_manager: AlertManager,
}
struct MetricCollector {
last_value: f64,
history: Vec<(Instant, f64)>,
moving_average: f64,
thresholds: (f64, f64), }
struct AlertManager {
active_alerts: Vec<Alert>,
alert_history: Vec<Alert>,
alert_rules: Vec<AlertRule>,
}
struct AlertRule {
metric: MonitoringMetric,
condition: AlertCondition,
threshold: f64,
severity: AlertSeverity,
message_template: String,
}
#[derive(Debug, Clone, PartialEq)]
enum AlertCondition {
GreaterThan,
LessThan,
Equal,
RateOfChange,
Anomaly,
}
impl AdaptiveDDSystem {
pub fn new(
config: AdaptiveDDConfig,
initial_sequence: DDSequence,
available_sequences: Vec<DDSequenceType>,
) -> Self {
let initial_state = AdaptiveDDState {
current_sequence: initial_sequence,
performance_history: Vec::new(),
noise_history: Vec::new(),
adaptation_history: Vec::new(),
current_metrics: PerformanceMetrics {
coherence_time: 0.0,
fidelity: 0.0,
error_rates: HashMap::new(),
resource_usage: ResourceUsage {
cpu_utilization: 0.0,
memory_usage: 0,
network_usage: 0.0,
power_consumption: 0.0,
},
throughput: 0.0,
latency: Duration::from_nanos(0),
},
system_health: SystemHealth {
health_score: 1.0,
component_health: HashMap::new(),
active_alerts: Vec::new(),
predicted_issues: Vec::new(),
},
};
let learning_agent =
if config.learning_config.learning_algorithm == LearningAlgorithm::QLearning {
Some(LearningAgent {
q_table: HashMap::new(),
replay_buffer: Vec::new(),
exploration_strategy: ExplorationStrategy::EpsilonGreedy(0.1),
learning_stats: LearningStatistics {
total_episodes: 0,
average_reward: 0.0,
exploration_rate: 0.1,
learning_rate: config.learning_config.learning_rate,
},
action_counts: HashMap::new(),
})
} else {
None
};
Self {
config,
state: Arc::new(Mutex::new(initial_state)),
available_sequences,
learning_agent,
feedback_controller: FeedbackController {
algorithm: ControlAlgorithm::PID,
pid_state: PIDState {
previous_error: 0.0,
integral: 0.0,
last_update: Instant::now(),
},
control_history: Vec::new(),
},
monitor: RealTimeMonitor {
monitoring_enabled: true,
metric_collectors: HashMap::new(),
alert_manager: AlertManager {
active_alerts: Vec::new(),
alert_history: Vec::new(),
alert_rules: Vec::new(),
},
},
sequence_cache: HashMap::new(),
}
}
pub fn start(&mut self, executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
println!("Starting adaptive DD system");
self.initialize_monitoring()?;
self.start_control_loop(executor)?;
Ok(())
}
pub fn update_performance(
&mut self,
performance_analysis: &DDPerformanceAnalysis,
noise_analysis: &DDNoiseAnalysis,
) -> DeviceResult<()> {
let mut state = self
.state
.lock()
.map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?;
let performance_record = PerformanceRecord {
timestamp: Instant::now(),
coherence_time: performance_analysis
.metrics
.get(&DDPerformanceMetric::CoherenceTime)
.copied()
.unwrap_or(0.0),
fidelity: performance_analysis
.metrics
.get(&DDPerformanceMetric::ProcessFidelity)
.copied()
.unwrap_or(0.95),
gate_overhead: performance_analysis
.metrics
.get(&DDPerformanceMetric::GateOverhead)
.copied()
.unwrap_or(1.0),
success_rate: performance_analysis
.metrics
.get(&DDPerformanceMetric::RobustnessScore)
.copied()
.unwrap_or(0.9),
resource_utilization: performance_analysis
.metrics
.get(&DDPerformanceMetric::ResourceEfficiency)
.copied()
.unwrap_or(0.8),
};
state.performance_history.push(performance_record);
let noise_record = NoiseRecord {
timestamp: Instant::now(),
noise_levels: noise_analysis
.noise_characterization
.noise_types
.iter()
.map(|(noise_type, characteristics)| {
(format!("{noise_type:?}"), characteristics.strength)
})
.collect(),
dominant_sources: noise_analysis
.noise_characterization
.dominant_sources
.iter()
.map(|source| format!("{:?}", source.source_type))
.collect(),
environmental_conditions: EnvironmentalConditions {
temperature: 20.0, magnetic_field: 0.1,
emi_level: 0.05,
vibration_level: 0.02,
},
};
state.noise_history.push(noise_record);
state.current_metrics.coherence_time = performance_analysis
.metrics
.get(&DDPerformanceMetric::CoherenceTime)
.copied()
.unwrap_or(0.0);
state.current_metrics.fidelity = performance_analysis
.metrics
.get(&DDPerformanceMetric::ProcessFidelity)
.copied()
.unwrap_or(0.95);
if self.should_adapt(&state)? {
drop(state); self.trigger_adaptation()?;
}
Ok(())
}
fn should_adapt(&self, state: &AdaptiveDDState) -> DeviceResult<bool> {
let criteria = &self.config.adaptation_criteria;
if state.current_metrics.coherence_time < criteria.coherence_threshold {
return Ok(true);
}
if state.current_metrics.fidelity < criteria.fidelity_threshold {
return Ok(true);
}
let average_noise: f64 = state.current_metrics.error_rates.values().sum::<f64>()
/ state.current_metrics.error_rates.len().max(1) as f64;
if average_noise > criteria.noise_threshold {
return Ok(true);
}
Ok(false)
}
fn trigger_adaptation(&mut self) -> DeviceResult<()> {
println!("Triggering DD adaptation");
let current_state = self.analyze_current_state()?;
let new_sequence_type = self.select_optimal_sequence(¤t_state)?;
let new_sequence = self.generate_sequence(&new_sequence_type)?;
let previous_sequence_type = self
.state
.lock()
.map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?
.current_sequence
.sequence_type
.clone();
let adaptation_record = AdaptationRecord {
timestamp: Instant::now(),
previous_sequence: previous_sequence_type,
new_sequence: new_sequence_type,
adaptation_reason: AdaptationReason::PerformanceDegradation,
expected_improvement: 0.1, actual_improvement: None,
};
{
let mut state = self.state.lock().map_err(|_| {
DeviceError::LockError("Failed to lock adaptive DD state".to_string())
})?;
state.current_sequence = new_sequence;
state.adaptation_history.push(adaptation_record);
}
println!("DD adaptation completed");
Ok(())
}
fn analyze_current_state(&self) -> DeviceResult<String> {
let state = self
.state
.lock()
.map_err(|_| DeviceError::LockError("Failed to lock adaptive DD state".to_string()))?;
let coherence_level = if state.current_metrics.coherence_time > 50e-6 {
"high"
} else if state.current_metrics.coherence_time > 20e-6 {
"medium"
} else {
"low"
};
let fidelity_level = if state.current_metrics.fidelity > 0.99 {
"high"
} else if state.current_metrics.fidelity > 0.95 {
"medium"
} else {
"low"
};
let noise_level = {
let avg_noise: f64 = state.current_metrics.error_rates.values().sum::<f64>()
/ state.current_metrics.error_rates.len().max(1) as f64;
if avg_noise < 0.01 {
"low"
} else if avg_noise < 0.05 {
"medium"
} else {
"high"
}
};
Ok(format!(
"coherence_{coherence_level}_fidelity_{fidelity_level}_noise_{noise_level}"
))
}
fn select_optimal_sequence(&mut self, current_state: &str) -> DeviceResult<DDSequenceType> {
if let Some(ref mut agent) = self.learning_agent {
let available_sequences = self.available_sequences.clone();
return Self::select_sequence_with_learning_static(
agent,
current_state,
&available_sequences,
);
}
self.select_sequence_rule_based(current_state)
}
fn select_sequence_with_learning_static(
agent: &mut LearningAgent,
current_state: &str,
available_sequences: &[DDSequenceType],
) -> DeviceResult<DDSequenceType> {
let mut best_sequence = DDSequenceType::CPMG { n_pulses: 1 };
let mut best_q_value = f64::NEG_INFINITY;
for sequence_type in available_sequences {
let action = format!("{sequence_type:?}");
let q_value = agent
.q_table
.get(&(current_state.to_string(), action))
.copied()
.unwrap_or(0.0);
if q_value > best_q_value {
best_q_value = q_value;
best_sequence = sequence_type.clone();
}
}
match agent.exploration_strategy {
ExplorationStrategy::EpsilonGreedy(epsilon) => {
if thread_rng().random::<f64>() < epsilon {
let random_idx = thread_rng().random_range(0..available_sequences.len());
best_sequence = available_sequences[random_idx].clone();
}
}
ExplorationStrategy::UCB(c) => {
let total_visits = agent.action_counts.values().sum::<u32>() as f64;
let mut best_ucb = f64::NEG_INFINITY;
for sequence_type in available_sequences {
let action = format!("{sequence_type:?}");
let visits = agent.action_counts.get(&action).copied().unwrap_or(0) as f64;
let q_value = agent
.q_table
.get(&(current_state.to_string(), action.clone()))
.copied()
.unwrap_or(0.0);
let ucb_value = if visits > 0.0 {
c.mul_add((total_visits.ln() / visits).sqrt(), q_value)
} else {
f64::INFINITY };
if ucb_value > best_ucb {
best_ucb = ucb_value;
best_sequence = sequence_type.clone();
}
}
}
ExplorationStrategy::Boltzmann(temperature) => {
let mut probabilities = Vec::new();
let mut exp_sum = 0.0;
for sequence_type in available_sequences {
let action = format!("{sequence_type:?}");
let q_value = agent
.q_table
.get(&(current_state.to_string(), action))
.copied()
.unwrap_or(0.0);
let exp_val = (q_value / temperature).exp();
probabilities.push(exp_val);
exp_sum += exp_val;
}
for prob in &mut probabilities {
*prob /= exp_sum;
}
let mut cumsum = 0.0;
let rand_val = thread_rng().random::<f64>();
for (i, prob) in probabilities.iter().enumerate() {
cumsum += prob;
if rand_val <= cumsum {
best_sequence = available_sequences[i].clone();
break;
}
}
}
ExplorationStrategy::ThompsonSampling => {
if thread_rng().random::<f64>() < 0.1 {
let random_idx = thread_rng().random_range(0..available_sequences.len());
best_sequence = available_sequences[random_idx].clone();
}
}
}
Ok(best_sequence)
}
fn select_sequence_with_learning(
&self,
agent: &mut LearningAgent,
current_state: &str,
) -> DeviceResult<DDSequenceType> {
let mut best_sequence = DDSequenceType::CPMG { n_pulses: 1 };
let mut best_q_value = f64::NEG_INFINITY;
for sequence_type in &self.available_sequences {
let action = format!("{sequence_type:?}");
let q_value = agent
.q_table
.get(&(current_state.to_string(), action))
.copied()
.unwrap_or(0.0);
if q_value > best_q_value {
best_q_value = q_value;
best_sequence = sequence_type.clone();
}
}
if let ExplorationStrategy::EpsilonGreedy(epsilon) = agent.exploration_strategy {
if thread_rng().random::<f64>() < epsilon {
let random_idx = thread_rng().random_range(0..self.available_sequences.len());
best_sequence = self.available_sequences[random_idx].clone();
}
} else {
}
Ok(best_sequence)
}
fn select_sequence_rule_based(&self, current_state: &str) -> DeviceResult<DDSequenceType> {
match current_state {
s if s.contains("noise_high") => Ok(DDSequenceType::XY8),
s if s.contains("coherence_low") => Ok(DDSequenceType::UDD { n_pulses: 3 }),
s if s.contains("fidelity_low") => Ok(DDSequenceType::XY4),
_ => Ok(DDSequenceType::CPMG { n_pulses: 1 }),
}
}
fn generate_sequence(&mut self, sequence_type: &DDSequenceType) -> DeviceResult<DDSequence> {
let cache_key = format!("{sequence_type:?}");
if let Some(cached_sequence) = self.sequence_cache.get(&cache_key) {
return Ok(cached_sequence.clone());
}
let target_qubits = vec![
quantrs2_core::qubit::QubitId(0),
quantrs2_core::qubit::QubitId(1),
];
let duration = 100e-6;
let sequence =
DDSequenceGenerator::generate_base_sequence(sequence_type, &target_qubits, duration)?;
self.sequence_cache.insert(cache_key, sequence.clone());
Ok(sequence)
}
fn initialize_monitoring(&mut self) -> DeviceResult<()> {
println!("Initializing DD monitoring system");
for metric in &self.config.monitoring_config.metrics {
let collector = MetricCollector {
last_value: 0.0,
history: Vec::new(),
moving_average: 0.0,
thresholds: (0.8, 0.6), };
self.monitor
.metric_collectors
.insert(metric.clone(), collector);
}
self.monitor.alert_manager.alert_rules.push(AlertRule {
metric: MonitoringMetric::CoherenceTime,
condition: AlertCondition::LessThan,
threshold: 20e-6, severity: AlertSeverity::Warning,
message_template: "Coherence time degraded below threshold".to_string(),
});
self.monitor.alert_manager.alert_rules.push(AlertRule {
metric: MonitoringMetric::Fidelity,
condition: AlertCondition::LessThan,
threshold: 0.95,
severity: AlertSeverity::Error,
message_template: "Process fidelity degraded below threshold".to_string(),
});
Ok(())
}
fn start_control_loop(&mut self, _executor: &dyn DDCircuitExecutor) -> DeviceResult<()> {
println!("Starting DD control loop");
Ok(())
}
pub fn get_current_state(&self) -> AdaptiveDDState {
self.state
.lock()
.map(|state| state.clone())
.unwrap_or_else(|poisoned| poisoned.into_inner().clone())
}
pub fn get_performance_history(&self) -> Vec<PerformanceRecord> {
self.state
.lock()
.map(|state| state.performance_history.clone())
.unwrap_or_default()
}
pub fn get_adaptation_statistics(&self) -> AdaptationStatistics {
let state = match self.state.lock() {
Ok(s) => s,
Err(poisoned) => poisoned.into_inner(),
};
let total_adaptations = state.adaptation_history.len();
let successful_adaptations = state
.adaptation_history
.iter()
.filter(|record| record.actual_improvement.unwrap_or(0.0) > 0.0)
.count();
let success_rate = if total_adaptations > 0 {
successful_adaptations as f64 / total_adaptations as f64
} else {
0.0
};
let average_improvement = state
.adaptation_history
.iter()
.filter_map(|record| record.actual_improvement)
.sum::<f64>()
/ state.adaptation_history.len().max(1) as f64;
AdaptationStatistics {
total_adaptations,
successful_adaptations,
success_rate,
average_improvement,
most_used_sequence: self.get_most_used_sequence(&state),
adaptation_frequency: self.calculate_adaptation_frequency(&state),
}
}
fn get_most_used_sequence(&self, state: &AdaptiveDDState) -> DDSequenceType {
let mut sequence_counts: HashMap<DDSequenceType, usize> = HashMap::new();
for record in &state.adaptation_history {
*sequence_counts
.entry(record.new_sequence.clone())
.or_insert(0) += 1;
}
sequence_counts
.into_iter()
.max_by_key(|(_, count)| *count)
.map_or(DDSequenceType::CPMG { n_pulses: 1 }, |(sequence, _)| {
sequence
})
}
fn calculate_adaptation_frequency(&self, state: &AdaptiveDDState) -> f64 {
if state.adaptation_history.len() < 2 {
return 0.0;
}
let first_adaptation = match state.adaptation_history.first() {
Some(record) => record.timestamp,
None => return 0.0,
};
let last_adaptation = match state.adaptation_history.last() {
Some(record) => record.timestamp,
None => return 0.0,
};
let time_span = last_adaptation
.duration_since(first_adaptation)
.as_secs_f64();
if time_span > 0.0 {
state.adaptation_history.len() as f64 / time_span
} else {
0.0
}
}
}
#[derive(Debug, Clone)]
pub struct AdaptationStatistics {
pub total_adaptations: usize,
pub successful_adaptations: usize,
pub success_rate: f64,
pub average_improvement: f64,
pub most_used_sequence: DDSequenceType,
pub adaptation_frequency: f64,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dynamical_decoupling::{
config::DDSequenceType,
sequences::{DDSequence, DDSequenceProperties, ResourceRequirements, SequenceSymmetry},
};
fn create_test_sequence() -> DDSequence {
DDSequence {
sequence_type: DDSequenceType::CPMG { n_pulses: 1 },
target_qubits: vec![quantrs2_core::qubit::QubitId(0)],
duration: 100e-6,
circuit: Circuit::<32>::new(),
pulse_timings: vec![50e-6],
pulse_phases: vec![std::f64::consts::PI],
properties: DDSequenceProperties {
pulse_count: 1,
sequence_order: 1,
periodicity: 1,
symmetry: SequenceSymmetry {
time_reversal: true,
phase_symmetry: true,
rotational_symmetry: false,
inversion_symmetry: true,
},
noise_suppression: std::collections::HashMap::new(),
resource_requirements: ResourceRequirements {
gate_count: 1,
circuit_depth: 1,
required_connectivity: Vec::new(),
execution_time: 100e-6,
memory_requirements: 8,
},
},
}
}
#[test]
fn test_adaptive_dd_system_creation() {
let config = AdaptiveDDConfig::default();
let initial_sequence = create_test_sequence();
let available_sequences = vec![
DDSequenceType::CPMG { n_pulses: 1 },
DDSequenceType::XY4,
DDSequenceType::XY8,
];
let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
let state = system.get_current_state();
assert!(matches!(
state.current_sequence.sequence_type,
DDSequenceType::CPMG { .. }
));
assert_eq!(state.system_health.health_score, 1.0);
}
#[test]
fn test_rule_based_sequence_selection() {
let config = AdaptiveDDConfig::default();
let initial_sequence = create_test_sequence();
let available_sequences = vec![
DDSequenceType::CPMG { n_pulses: 1 },
DDSequenceType::XY4,
DDSequenceType::XY8,
];
let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
let high_noise_state = "coherence_medium_fidelity_medium_noise_high";
let low_coherence_state = "coherence_low_fidelity_medium_noise_medium";
let low_fidelity_state = "coherence_medium_fidelity_low_noise_medium";
assert_eq!(
system
.select_sequence_rule_based(high_noise_state)
.expect("high noise state should return valid sequence"),
DDSequenceType::XY8
);
assert_eq!(
system
.select_sequence_rule_based(low_coherence_state)
.expect("low coherence state should return valid sequence"),
DDSequenceType::UDD { n_pulses: 3 }
);
assert_eq!(
system
.select_sequence_rule_based(low_fidelity_state)
.expect("low fidelity state should return valid sequence"),
DDSequenceType::XY4
);
}
#[test]
fn test_adaptation_statistics() {
let config = AdaptiveDDConfig::default();
let initial_sequence = create_test_sequence();
let available_sequences = vec![DDSequenceType::CPMG { n_pulses: 1 }, DDSequenceType::XY4];
let system = AdaptiveDDSystem::new(config, initial_sequence, available_sequences);
let stats = system.get_adaptation_statistics();
assert_eq!(stats.total_adaptations, 0);
assert_eq!(stats.success_rate, 0.0);
assert!(matches!(
stats.most_used_sequence,
DDSequenceType::CPMG { .. }
));
}
}