1use std::collections::HashMap;
4use std::f64::consts::PI;
5
6use quantrs2_circuit::prelude::*;
7use quantrs2_core::{
8 gate::{
9 single::{Hadamard, PauliX, PauliY, PauliZ},
10 GateOp,
11 },
12 qubit::QubitId,
13};
14
15use super::config::{DDSequenceType, NoiseType};
16use crate::DeviceResult;
17use scirs2_core::random::prelude::*;
18
19#[derive(Debug, Clone)]
21pub struct DDSequence {
22 pub sequence_type: DDSequenceType,
24 pub target_qubits: Vec<QubitId>,
26 pub duration: f64,
28 pub circuit: Circuit<32>,
30 pub pulse_timings: Vec<f64>,
32 pub pulse_phases: Vec<f64>,
34 pub properties: DDSequenceProperties,
36}
37
38#[derive(Debug, Clone)]
40pub struct DDSequenceProperties {
41 pub pulse_count: usize,
43 pub sequence_order: usize,
45 pub periodicity: usize,
47 pub symmetry: SequenceSymmetry,
49 pub noise_suppression: HashMap<NoiseType, f64>,
51 pub resource_requirements: ResourceRequirements,
53}
54
55#[derive(Debug, Clone)]
57pub struct SequenceSymmetry {
58 pub time_reversal: bool,
60 pub phase_symmetry: bool,
62 pub rotational_symmetry: bool,
64 pub inversion_symmetry: bool,
66}
67
68#[derive(Debug, Clone)]
70pub struct ResourceRequirements {
71 pub gate_count: usize,
73 pub circuit_depth: usize,
75 pub required_connectivity: Vec<(QubitId, QubitId)>,
77 pub execution_time: f64,
79 pub memory_requirements: usize,
81}
82
83pub struct DDSequenceGenerator;
85
86impl DDSequenceGenerator {
87 pub fn generate_base_sequence(
89 sequence_type: &DDSequenceType,
90 target_qubits: &[QubitId],
91 duration: f64,
92 ) -> DeviceResult<DDSequence> {
93 if target_qubits.is_empty() {
95 return Err(crate::DeviceError::InvalidInput(
96 "Target qubits cannot be empty".to_string(),
97 ));
98 }
99
100 if duration <= 0.0 {
101 return Err(crate::DeviceError::InvalidInput(
102 "Duration must be positive".to_string(),
103 ));
104 }
105
106 if !duration.is_finite() {
107 return Err(crate::DeviceError::InvalidInput(
108 "Duration must be finite".to_string(),
109 ));
110 }
111
112 match sequence_type {
113 DDSequenceType::CPMG { n_pulses } => {
114 Self::generate_cpmg_sequence_with_pulses(target_qubits, duration, *n_pulses)
115 }
116 DDSequenceType::XY4 => Self::generate_xy4_sequence(target_qubits, duration),
117 DDSequenceType::XY8 => Self::generate_xy8_sequence(target_qubits, duration),
118 DDSequenceType::XY16 => Self::generate_xy16_sequence(target_qubits, duration),
119 DDSequenceType::UDD { n_pulses } => {
120 Self::generate_udd_sequence_with_pulses(target_qubits, duration, *n_pulses)
121 }
122 DDSequenceType::KDD => Self::generate_kdd_sequence(target_qubits, duration),
123 DDSequenceType::QDD => Self::generate_qdd_sequence(target_qubits, duration),
124 DDSequenceType::CDD => Self::generate_cdd_sequence(target_qubits, duration),
125 DDSequenceType::RDD => Self::generate_rdd_sequence(target_qubits, duration),
126 DDSequenceType::HahnEcho => Self::generate_hahn_echo_sequence(target_qubits, duration),
127 DDSequenceType::CarrPurcell => Self::generate_cp_sequence(target_qubits, duration),
128 DDSequenceType::SciRS2Optimized => {
129 Self::generate_optimized_sequence(target_qubits, duration)
130 }
131 DDSequenceType::Custom(name) => {
132 Self::generate_custom_sequence(name, target_qubits, duration)
133 }
134 DDSequenceType::Composite => {
135 let base_xy4 = Self::generate_xy4_sequence(target_qubits, duration)?;
137 let base_cpmg = Self::generate_cpmg_sequence(target_qubits, duration)?;
138 let base_sequences = vec![base_xy4, base_cpmg];
139 Self::generate_composite_sequence(&base_sequences, CompositionStrategy::Sequential)
140 }
141 DDSequenceType::MultiQubitCoordinated => {
142 Self::generate_xy4_sequence(target_qubits, duration)
144 }
145 DDSequenceType::Adaptive => {
146 Self::generate_optimized_sequence(target_qubits, duration)
148 }
149 }
150 }
151
152 fn generate_hahn_echo_sequence(
154 target_qubits: &[QubitId],
155 duration: f64,
156 ) -> DeviceResult<DDSequence> {
157 let pulse_spacing = duration / 2.0; let mut circuit = Circuit::<32>::new();
160 let mut pulse_timings = Vec::new();
161 let mut pulse_phases = Vec::new();
162
163 for qubit in target_qubits {
164 pulse_timings.push(pulse_spacing);
165 pulse_phases.push(PI); circuit.add_gate(PauliY { target: *qubit })?;
167 }
168
169 let properties = DDSequenceProperties {
170 pulse_count: target_qubits.len(),
171 sequence_order: 1,
172 periodicity: 1,
173 symmetry: SequenceSymmetry {
174 time_reversal: true,
175 phase_symmetry: true,
176 rotational_symmetry: false,
177 inversion_symmetry: true,
178 },
179 noise_suppression: {
180 let mut suppression = HashMap::new();
181 suppression.insert(NoiseType::PhaseDamping, 0.8);
182 suppression.insert(NoiseType::AmplitudeDamping, 0.2);
183 suppression
184 },
185 resource_requirements: ResourceRequirements {
186 gate_count: target_qubits.len(),
187 circuit_depth: 1,
188 required_connectivity: Vec::new(),
189 execution_time: duration,
190 memory_requirements: target_qubits.len() * 8,
191 },
192 };
193
194 Ok(DDSequence {
195 sequence_type: DDSequenceType::HahnEcho,
196 target_qubits: target_qubits.to_vec(),
197 duration,
198 circuit,
199 pulse_timings,
200 pulse_phases,
201 properties,
202 })
203 }
204
205 fn generate_cpmg_sequence_with_pulses(
207 target_qubits: &[QubitId],
208 duration: f64,
209 n_pulses: usize,
210 ) -> DeviceResult<DDSequence> {
211 let pulse_spacing = duration / (n_pulses + 1) as f64;
212
213 let mut circuit = Circuit::<32>::new();
214 let mut pulse_timings = Vec::new();
215 let mut pulse_phases = Vec::new();
216
217 for qubit in target_qubits {
218 for i in 1..=n_pulses {
219 let timing = i as f64 * pulse_spacing;
220 pulse_timings.push(timing);
221 pulse_phases.push(PI); circuit.add_gate(PauliY { target: *qubit })?;
224 }
225 }
226
227 let properties = DDSequenceProperties {
228 pulse_count: n_pulses * target_qubits.len(),
229 sequence_order: 1,
230 periodicity: n_pulses,
231 symmetry: SequenceSymmetry {
232 time_reversal: true,
233 phase_symmetry: true,
234 rotational_symmetry: false,
235 inversion_symmetry: true,
236 },
237 noise_suppression: {
238 let mut suppression = HashMap::new();
239 suppression.insert(NoiseType::PhaseDamping, 0.9);
240 suppression.insert(NoiseType::AmplitudeDamping, 0.3);
241 suppression
242 },
243 resource_requirements: ResourceRequirements {
244 gate_count: n_pulses * target_qubits.len(),
245 circuit_depth: n_pulses,
246 required_connectivity: Vec::new(),
247 execution_time: duration,
248 memory_requirements: n_pulses * target_qubits.len() * 8,
249 },
250 };
251
252 Ok(DDSequence {
253 sequence_type: DDSequenceType::CPMG { n_pulses },
254 target_qubits: target_qubits.to_vec(),
255 duration,
256 circuit,
257 pulse_timings,
258 pulse_phases,
259 properties,
260 })
261 }
262
263 fn generate_cpmg_sequence(
265 target_qubits: &[QubitId],
266 duration: f64,
267 ) -> DeviceResult<DDSequence> {
268 Self::generate_cpmg_sequence_with_pulses(target_qubits, duration, 16)
269 }
270
271 fn generate_xy4_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
273 let base_sequence = vec![PI, PI / 2.0, PI, 3.0 * PI / 2.0]; let n_repetitions = 4;
275 let pulse_spacing = duration / (base_sequence.len() * n_repetitions) as f64;
276
277 let mut circuit = Circuit::<32>::new();
278 let mut pulse_timings = Vec::new();
279 let mut pulse_phases = Vec::new();
280
281 for qubit in target_qubits {
282 for rep in 0..n_repetitions {
283 for (i, &phase) in base_sequence.iter().enumerate() {
284 let timing = (rep * base_sequence.len() + i + 1) as f64 * pulse_spacing;
285 pulse_timings.push(timing);
286 pulse_phases.push(phase);
287
288 match phase {
289 p if (p - PI).abs() < 1e-6 => {
290 circuit.add_gate(PauliX { target: *qubit })?;
291 }
292 p if (p - PI / 2.0).abs() < 1e-6 => {
293 circuit.add_gate(PauliY { target: *qubit })?;
294 }
295 p if (p - 3.0 * PI / 2.0).abs() < 1e-6 => {
296 circuit.add_gate(PauliY { target: *qubit })?;
297 circuit.add_gate(PauliZ { target: *qubit })?;
298 circuit.add_gate(PauliZ { target: *qubit })?;
299 }
300 _ => {
301 circuit.add_gate(PauliX { target: *qubit })?;
302 }
303 }
304 }
305 }
306 }
307
308 let properties = DDSequenceProperties {
309 pulse_count: base_sequence.len() * n_repetitions * target_qubits.len(),
310 sequence_order: 2,
311 periodicity: base_sequence.len(),
312 symmetry: SequenceSymmetry {
313 time_reversal: true,
314 phase_symmetry: true,
315 rotational_symmetry: true,
316 inversion_symmetry: true,
317 },
318 noise_suppression: {
319 let mut suppression = HashMap::new();
320 suppression.insert(NoiseType::PhaseDamping, 0.95);
321 suppression.insert(NoiseType::AmplitudeDamping, 0.4);
322 suppression.insert(NoiseType::Depolarizing, 0.8);
323 suppression
324 },
325 resource_requirements: ResourceRequirements {
326 gate_count: base_sequence.len() * n_repetitions * target_qubits.len(),
327 circuit_depth: base_sequence.len() * n_repetitions,
328 required_connectivity: Vec::new(),
329 execution_time: duration,
330 memory_requirements: base_sequence.len() * n_repetitions * target_qubits.len() * 8,
331 },
332 };
333
334 Ok(DDSequence {
335 sequence_type: DDSequenceType::XY4,
336 target_qubits: target_qubits.to_vec(),
337 duration,
338 circuit,
339 pulse_timings,
340 pulse_phases,
341 properties,
342 })
343 }
344
345 fn generate_xy8_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
347 let base_sequence = vec![
348 PI,
349 PI / 2.0,
350 PI,
351 3.0 * PI / 2.0, 3.0 * PI / 2.0,
353 PI,
354 PI / 2.0,
355 PI, ];
357 let n_repetitions = 2;
358 let pulse_spacing = duration / (base_sequence.len() * n_repetitions) as f64;
359
360 let mut circuit = Circuit::<32>::new();
361 let mut pulse_timings = Vec::new();
362 let mut pulse_phases = Vec::new();
363
364 for qubit in target_qubits {
365 for rep in 0..n_repetitions {
366 for (i, &phase) in base_sequence.iter().enumerate() {
367 let timing = (rep * base_sequence.len() + i + 1) as f64 * pulse_spacing;
368 pulse_timings.push(timing);
369 pulse_phases.push(phase);
370
371 match phase {
372 p if (p - PI).abs() < 1e-6 => {
373 circuit.add_gate(PauliX { target: *qubit })?;
374 }
375 p if (p - PI / 2.0).abs() < 1e-6 => {
376 circuit.add_gate(PauliY { target: *qubit })?;
377 }
378 p if (p - 3.0 * PI / 2.0).abs() < 1e-6 => {
379 circuit.add_gate(PauliY { target: *qubit })?;
380 circuit.add_gate(PauliZ { target: *qubit })?;
381 circuit.add_gate(PauliZ { target: *qubit })?;
382 }
383 _ => {
384 circuit.add_gate(PauliX { target: *qubit })?;
385 }
386 }
387 }
388 }
389 }
390
391 let properties = DDSequenceProperties {
392 pulse_count: base_sequence.len() * n_repetitions * target_qubits.len(),
393 sequence_order: 3,
394 periodicity: base_sequence.len(),
395 symmetry: SequenceSymmetry {
396 time_reversal: true,
397 phase_symmetry: true,
398 rotational_symmetry: true,
399 inversion_symmetry: true,
400 },
401 noise_suppression: {
402 let mut suppression = HashMap::new();
403 suppression.insert(NoiseType::PhaseDamping, 0.98);
404 suppression.insert(NoiseType::AmplitudeDamping, 0.5);
405 suppression.insert(NoiseType::Depolarizing, 0.9);
406 suppression.insert(NoiseType::CoherentErrors, 0.85);
407 suppression
408 },
409 resource_requirements: ResourceRequirements {
410 gate_count: base_sequence.len() * n_repetitions * target_qubits.len(),
411 circuit_depth: base_sequence.len() * n_repetitions,
412 required_connectivity: Vec::new(),
413 execution_time: duration,
414 memory_requirements: base_sequence.len() * n_repetitions * target_qubits.len() * 8,
415 },
416 };
417
418 Ok(DDSequence {
419 sequence_type: DDSequenceType::XY8,
420 target_qubits: target_qubits.to_vec(),
421 duration,
422 circuit,
423 pulse_timings,
424 pulse_phases,
425 properties,
426 })
427 }
428
429 fn generate_xy16_sequence(
431 target_qubits: &[QubitId],
432 duration: f64,
433 ) -> DeviceResult<DDSequence> {
434 let mut xy8_sequence = Self::generate_xy8_sequence(target_qubits, duration)?;
436 xy8_sequence.sequence_type = DDSequenceType::XY16;
437 xy8_sequence.properties.sequence_order = 4;
438 xy8_sequence
439 .properties
440 .noise_suppression
441 .insert(NoiseType::OneOverFNoise, 0.7);
442 Ok(xy8_sequence)
443 }
444
445 fn generate_udd_sequence_with_pulses(
447 target_qubits: &[QubitId],
448 duration: f64,
449 n_pulses: usize,
450 ) -> DeviceResult<DDSequence> {
451 let mut pulse_timings = Vec::new();
452 let mut pulse_phases = Vec::new();
453
454 for k in 1..=n_pulses {
456 let timing = duration
457 * (PI * k as f64 / (2.0 * n_pulses as f64 + 2.0))
458 .sin()
459 .powi(2);
460 pulse_timings.push(timing);
461 pulse_phases.push(PI); }
463
464 let mut circuit = Circuit::<32>::new();
465 for qubit in target_qubits {
466 for _ in 0..n_pulses {
467 circuit.add_gate(PauliX { target: *qubit })?;
468 }
469 }
470
471 let properties = DDSequenceProperties {
472 pulse_count: n_pulses * target_qubits.len(),
473 sequence_order: n_pulses,
474 periodicity: 1,
475 symmetry: SequenceSymmetry {
476 time_reversal: false,
477 phase_symmetry: false,
478 rotational_symmetry: false,
479 inversion_symmetry: false,
480 },
481 noise_suppression: {
482 let mut suppression = HashMap::new();
483 suppression.insert(NoiseType::PhaseDamping, 0.99);
484 suppression.insert(NoiseType::OneOverFNoise, 0.9);
485 suppression
486 },
487 resource_requirements: ResourceRequirements {
488 gate_count: n_pulses * target_qubits.len(),
489 circuit_depth: n_pulses,
490 required_connectivity: Vec::new(),
491 execution_time: duration,
492 memory_requirements: n_pulses * target_qubits.len() * 8,
493 },
494 };
495
496 Ok(DDSequence {
497 sequence_type: DDSequenceType::UDD { n_pulses },
498 target_qubits: target_qubits.to_vec(),
499 duration,
500 circuit,
501 pulse_timings,
502 pulse_phases,
503 properties,
504 })
505 }
506
507 fn generate_kdd_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
509 let mut cpmg_sequence = Self::generate_cpmg_sequence(target_qubits, duration)?;
511 cpmg_sequence.sequence_type = DDSequenceType::KDD;
512 cpmg_sequence
513 .properties
514 .noise_suppression
515 .insert(NoiseType::CoherentErrors, 0.95);
516 Ok(cpmg_sequence)
517 }
518
519 pub fn generate_composite_sequence(
521 base_sequences: &[DDSequence],
522 composition_strategy: CompositionStrategy,
523 ) -> DeviceResult<DDSequence> {
524 if base_sequences.is_empty() {
525 return Err(crate::DeviceError::InvalidInput(
526 "No base sequences provided".to_string(),
527 ));
528 }
529
530 match composition_strategy {
531 CompositionStrategy::Sequential => {
532 let mut composite_circuit = Circuit::<32>::new();
533 let mut composite_timings = Vec::new();
534 let mut composite_phases = Vec::new();
535 let mut total_duration = 0.0;
536 let mut total_gate_count = 0;
537 let target_qubits = base_sequences[0].target_qubits.clone();
538
539 for sequence in base_sequences {
540 for &timing in &sequence.pulse_timings {
542 composite_timings.push(total_duration + timing);
543 }
544 composite_phases.extend(&sequence.pulse_phases);
545 total_duration += sequence.duration;
546 total_gate_count += sequence.properties.pulse_count;
547
548 for qubit in &target_qubits {
550 for _ in 0..sequence.properties.pulse_count / target_qubits.len() {
551 composite_circuit.add_gate(PauliY { target: *qubit })?;
552 }
553 }
554 }
555
556 let mut combined_suppression = HashMap::new();
558 for sequence in base_sequences {
559 for (noise_type, suppression) in &sequence.properties.noise_suppression {
560 let current = combined_suppression.get(noise_type).unwrap_or(&0.0);
561 combined_suppression
563 .insert(noise_type.clone(), (current * suppression).sqrt());
564 }
565 }
566
567 let properties = DDSequenceProperties {
568 pulse_count: composite_timings.len(),
569 sequence_order: base_sequences
570 .iter()
571 .map(|s| s.properties.sequence_order)
572 .max()
573 .unwrap_or(1),
574 periodicity: base_sequences.len(),
575 symmetry: SequenceSymmetry {
576 time_reversal: base_sequences
577 .iter()
578 .all(|s| s.properties.symmetry.time_reversal),
579 phase_symmetry: base_sequences
580 .iter()
581 .all(|s| s.properties.symmetry.phase_symmetry),
582 rotational_symmetry: base_sequences
583 .iter()
584 .any(|s| s.properties.symmetry.rotational_symmetry),
585 inversion_symmetry: base_sequences
586 .iter()
587 .all(|s| s.properties.symmetry.inversion_symmetry),
588 },
589 noise_suppression: combined_suppression,
590 resource_requirements: ResourceRequirements {
591 gate_count: total_gate_count,
592 circuit_depth: base_sequences
593 .iter()
594 .map(|s| s.properties.resource_requirements.circuit_depth)
595 .sum(),
596 required_connectivity: Vec::new(),
597 execution_time: total_duration,
598 memory_requirements: total_gate_count * 8,
599 },
600 };
601
602 Ok(DDSequence {
603 sequence_type: DDSequenceType::Composite,
604 target_qubits,
605 duration: total_duration,
606 circuit: composite_circuit,
607 pulse_timings: composite_timings,
608 pulse_phases: composite_phases,
609 properties,
610 })
611 }
612 CompositionStrategy::Interleaved => {
613 Self::generate_composite_sequence(base_sequences, CompositionStrategy::Sequential)
615 }
616 CompositionStrategy::Nested => {
617 Self::generate_composite_sequence(base_sequences, CompositionStrategy::Sequential)
619 }
620 }
621 }
622
623 fn generate_qdd_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
625 let mut base =
626 DDSequenceGenerator::generate_udd_sequence_with_pulses(target_qubits, duration, 8)?;
627 base.sequence_type = DDSequenceType::QDD;
628 Ok(base)
629 }
630
631 fn generate_cdd_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
632 let mut base = DDSequenceGenerator::generate_xy8_sequence(target_qubits, duration)?;
633 base.sequence_type = DDSequenceType::CDD;
634 Ok(base)
635 }
636
637 fn generate_rdd_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
638 let mut base = DDSequenceGenerator::generate_xy4_sequence(target_qubits, duration)?;
639 base.sequence_type = DDSequenceType::RDD;
640 base.properties
641 .noise_suppression
642 .insert(NoiseType::RandomTelegraphNoise, 0.8);
643 Ok(base)
644 }
645
646 fn generate_cp_sequence(target_qubits: &[QubitId], duration: f64) -> DeviceResult<DDSequence> {
647 let mut base = DDSequenceGenerator::generate_cpmg_sequence(target_qubits, duration)?;
648 base.sequence_type = DDSequenceType::CarrPurcell;
649 base.properties.symmetry.phase_symmetry = false;
650 Ok(base)
651 }
652
653 fn generate_optimized_sequence(
654 target_qubits: &[QubitId],
655 duration: f64,
656 ) -> DeviceResult<DDSequence> {
657 let mut base = DDSequenceGenerator::generate_xy8_sequence(target_qubits, duration)?;
659 base.sequence_type = DDSequenceType::SciRS2Optimized;
660 base.properties.sequence_order = 5; Ok(base)
662 }
663
664 fn generate_custom_sequence(
665 name: &str,
666 target_qubits: &[QubitId],
667 duration: f64,
668 ) -> DeviceResult<DDSequence> {
669 let mut base = DDSequenceGenerator::generate_cpmg_sequence(target_qubits, duration)?;
671 base.sequence_type = DDSequenceType::Custom(name.to_string());
672 Ok(base)
673 }
674}
675
676#[derive(Debug, Clone)]
678pub struct SequenceCache {
679 pub cached_sequences: HashMap<String, DDSequence>,
680 pub cache_hits: usize,
681 pub cache_misses: usize,
682}
683
684impl SequenceCache {
685 pub fn new() -> Self {
686 Self {
687 cached_sequences: HashMap::new(),
688 cache_hits: 0,
689 cache_misses: 0,
690 }
691 }
692
693 pub fn get_sequence(&mut self, key: &str) -> Option<DDSequence> {
694 if let Some(sequence) = self.cached_sequences.get(key) {
695 self.cache_hits += 1;
696 Some(sequence.clone())
697 } else {
698 self.cache_misses += 1;
699 None
700 }
701 }
702
703 pub fn store_sequence(&mut self, key: String, sequence: DDSequence) {
704 self.cached_sequences.insert(key, sequence);
705 }
706
707 pub fn get_cache_statistics(&self) -> (usize, usize, f64) {
708 let total_requests = self.cache_hits + self.cache_misses;
709 let hit_rate = if total_requests > 0 {
710 self.cache_hits as f64 / total_requests as f64
711 } else {
712 0.0
713 };
714 (self.cache_hits, self.cache_misses, hit_rate)
715 }
716}
717
718#[derive(Debug, Clone, PartialEq)]
720pub enum CompositionStrategy {
721 Sequential,
723 Interleaved,
725 Nested,
727}
728
729pub struct MultiQubitDDCoordinator {
731 pub qubit_sequences: HashMap<Vec<QubitId>, DDSequence>,
733 pub crosstalk_mitigation: CrosstalkMitigationStrategy,
735 pub synchronization: crate::dynamical_decoupling::hardware::SynchronizationRequirements,
737}
738
739#[derive(Debug, Clone, PartialEq)]
741pub enum CrosstalkMitigationStrategy {
742 None,
744 TimeShifted,
746 PhaseRandomized,
748 Orthogonal,
750 Adaptive,
752 HybridApproach,
754 TemporalSeparation,
756 SpatialSeparation,
758}
759
760#[derive(Debug, Clone)]
762pub struct SynchronizationRequirements {
763 pub global_sync: bool,
765 pub phase_coherence: bool,
767 pub timing_tolerance: f64,
769 pub sync_points: Vec<f64>,
771}
772
773impl MultiQubitDDCoordinator {
774 pub fn new(
776 crosstalk_mitigation: CrosstalkMitigationStrategy,
777 synchronization: crate::dynamical_decoupling::hardware::SynchronizationRequirements,
778 ) -> Self {
779 Self {
780 qubit_sequences: HashMap::new(),
781 crosstalk_mitigation,
782 synchronization,
783 }
784 }
785
786 pub fn add_sequence(&mut self, qubits: Vec<QubitId>, sequence: DDSequence) {
788 self.qubit_sequences.insert(qubits, sequence);
789 }
790
791 pub fn generate_coordinated_sequence(&self) -> DeviceResult<DDSequence> {
793 if self.qubit_sequences.is_empty() {
794 return Err(crate::DeviceError::InvalidInput(
795 "No sequences to coordinate".to_string(),
796 ));
797 }
798
799 let sequences: Vec<_> = self.qubit_sequences.values().cloned().collect();
800
801 match self.crosstalk_mitigation {
802 CrosstalkMitigationStrategy::TimeShifted => {
803 self.generate_time_shifted_sequence(&sequences)
804 }
805 CrosstalkMitigationStrategy::PhaseRandomized => {
806 self.generate_phase_randomized_sequence(&sequences)
807 }
808 _ => {
809 DDSequenceGenerator::generate_composite_sequence(
811 &sequences,
812 CompositionStrategy::Sequential,
813 )
814 }
815 }
816 }
817
818 fn generate_time_shifted_sequence(&self, sequences: &[DDSequence]) -> DeviceResult<DDSequence> {
820 let base_sequence = &sequences[0];
821 let mut coordinated = base_sequence.clone();
822
823 let shift_increment = base_sequence.duration / (sequences.len() as f64 * 10.0);
825
826 for (i, sequence) in sequences.iter().enumerate() {
827 let time_shift = i as f64 * shift_increment;
828 for timing in &mut coordinated.pulse_timings {
829 *timing += time_shift;
830 }
831 }
832
833 coordinated.sequence_type = DDSequenceType::MultiQubitCoordinated;
834 Ok(coordinated)
835 }
836
837 fn generate_phase_randomized_sequence(
839 &self,
840 sequences: &[DDSequence],
841 ) -> DeviceResult<DDSequence> {
842 let base_sequence = &sequences[0];
843 let mut coordinated = base_sequence.clone();
844
845 use std::f64::consts::PI;
847 for phase in &mut coordinated.pulse_phases {
848 let random_phase = thread_rng().gen::<f64>() * 2.0 * PI;
849 *phase += random_phase;
850 }
851
852 coordinated.sequence_type = DDSequenceType::MultiQubitCoordinated;
853 Ok(coordinated)
854 }
855
856 fn generate_composite_sequence(
858 target_qubits: &[QubitId],
859 duration: f64,
860 ) -> DeviceResult<DDSequence> {
861 let xy4 = DDSequenceGenerator::generate_xy4_sequence(target_qubits, duration / 2.0)?;
863 let cpmg = DDSequenceGenerator::generate_cpmg_sequence(target_qubits, duration / 2.0)?;
864
865 let mut composite = xy4;
866 composite.pulse_timings.extend(cpmg.pulse_timings);
867 composite.pulse_phases.extend(cpmg.pulse_phases);
868 composite.duration = duration;
869 composite.sequence_type = DDSequenceType::Composite;
870
871 Ok(composite)
872 }
873
874 fn generate_multi_qubit_coordinated_sequence(
876 target_qubits: &[QubitId],
877 duration: f64,
878 ) -> DeviceResult<DDSequence> {
879 let mut base = DDSequenceGenerator::generate_xy4_sequence(target_qubits, duration)?;
881 base.sequence_type = DDSequenceType::MultiQubitCoordinated;
882
883 let shift_increment = duration / (target_qubits.len() as f64 * 10.0);
885 for (i, _) in target_qubits.iter().enumerate() {
886 let time_shift = i as f64 * shift_increment;
887 for timing in &mut base.pulse_timings {
888 *timing += time_shift;
889 }
890 }
891
892 Ok(base)
893 }
894
895 fn generate_adaptive_sequence(
897 target_qubits: &[QubitId],
898 duration: f64,
899 ) -> DeviceResult<DDSequence> {
900 let mut base = DDSequenceGenerator::generate_xy8_sequence(target_qubits, duration)?;
902 base.sequence_type = DDSequenceType::Adaptive;
903
904 let adaptation_factor = 1.1; for timing in &mut base.pulse_timings {
907 *timing *= adaptation_factor;
908 }
909
910 Ok(base)
911 }
912}