1use std::collections::{HashMap, HashSet};
10use std::sync::{Arc, Mutex, RwLock};
11use std::time::{Duration, Instant, SystemTime};
12
13use quantrs2_circuit::prelude::*;
14use quantrs2_core::{
15 error::{QuantRS2Error, QuantRS2Result},
16 gate::GateOp,
17 qubit::QubitId,
18};
19
20#[cfg(feature = "scirs2")]
22use scirs2_graph::{
23 betweenness_centrality, closeness_centrality, dijkstra_path, minimum_spanning_tree, Graph,
24};
25#[cfg(feature = "scirs2")]
26use scirs2_optimize::{differential_evolution, minimize, OptimizeResult};
27#[cfg(feature = "scirs2")]
28use scirs2_stats::{corrcoef, mean, pearsonr, spearmanr, std};
29
30#[cfg(not(feature = "scirs2"))]
32mod fallback_scirs2 {
33 use scirs2_core::ndarray::{Array1, Array2};
34
35 pub fn mean(_data: &Array1<f64>) -> Result<f64, String> {
36 Ok(0.0)
37 }
38 pub fn std(_data: &Array1<f64>, _ddof: i32) -> Result<f64, String> {
39 Ok(1.0)
40 }
41 pub fn pearsonr(_x: &Array1<f64>, _y: &Array1<f64>) -> Result<(f64, f64), String> {
42 Ok((0.0, 0.5))
43 }
44
45 pub struct OptimizeResult {
46 pub x: Array1<f64>,
47 pub fun: f64,
48 pub success: bool,
49 }
50
51 pub fn minimize(
52 _func: fn(&Array1<f64>) -> f64,
53 _x0: &Array1<f64>,
54 ) -> Result<OptimizeResult, String> {
55 Ok(OptimizeResult {
56 x: Array1::zeros(2),
57 fun: 0.0,
58 success: true,
59 })
60 }
61}
62
63#[cfg(not(feature = "scirs2"))]
64use fallback_scirs2::*;
65
66use scirs2_core::ndarray::{Array1, Array2};
67use scirs2_core::Complex64;
68
69use crate::{
70 backend_traits::{query_backend_capabilities, BackendCapabilities},
71 calibration::{CalibrationManager, DeviceCalibration},
72 mapping_scirs2::{SciRS2MappingConfig, SciRS2QubitMapper},
73 optimization::{CalibrationOptimizer, OptimizationConfig},
74 topology::HardwareTopology,
75 translation::{GateTranslator, HardwareBackend},
76 DeviceError, DeviceResult,
77};
78
79use super::analysis::{CircuitAnalysis, ConnectivityAnalysis, GateAnalysis, ResourceAnalysis};
80use super::{
81 AppliedTransformation, CircuitMetrics, DistributionComparison, ErrorAnalysis,
82 FidelityComparison, GateTranslationStrategy, MigrationConfig, MigrationMetrics,
83 MigrationResult, MigrationStage, MigrationStatistics, MigrationWarning, OptimizationPass,
84 PerformanceComparison, ResourceMetrics, StatisticalValidationResult, TransformationImpact,
85 TransformationType, ValidationMethod, ValidationMethodResult, ValidationResult,
86 WarningSeverity, WarningType,
87};
88
89pub struct CircuitMigrationEngine {
91 calibration_manager: CalibrationManager,
92 mapper: SciRS2QubitMapper,
93 optimizer: CalibrationOptimizer,
94 translator: GateTranslator,
95 migration_cache: RwLock<HashMap<String, CachedMigration>>,
96 performance_tracker: Mutex<PerformanceTracker>,
97}
98
99#[derive(Debug, Clone)]
101struct CachedMigration {
102 config_hash: u64,
103 result: Vec<u8>, created_at: SystemTime,
105 access_count: usize,
106}
107
108#[derive(Debug, Clone)]
110struct PerformanceTracker {
111 migration_history: Vec<MigrationPerformanceRecord>,
112 average_migration_time: Duration,
113 success_rate: f64,
114 common_issues: HashMap<String, usize>,
115}
116
117#[derive(Debug, Clone)]
119struct MigrationPerformanceRecord {
120 config: MigrationConfig,
121 execution_time: Duration,
122 success: bool,
123 quality_score: f64,
124 timestamp: SystemTime,
125}
126
127const SELF_INVERSE_GATE_NAMES: &[&str] = &[
132 "X", "x", "Y", "y", "Z", "z", "H", "h", "CNOT", "cnot", "cx", "CZ", "cz", "SWAP", "swap",
133];
134
135pub(crate) fn cancel_adjacent_self_inverse_gates<const N: usize>(
142 circuit: &Circuit<N>,
143) -> DeviceResult<Circuit<N>> {
144 let boxed_gates = circuit.gates_as_boxes();
145 let mut output: Vec<Option<Box<dyn GateOp>>> = Vec::with_capacity(boxed_gates.len());
147 let mut history: HashMap<QubitId, Vec<usize>> = HashMap::new();
149
150 for gate in boxed_gates {
151 let qubits = gate.qubits();
152 let name = gate.name();
153
154 let mut cancel_idx = None;
155 if !qubits.is_empty() && SELF_INVERSE_GATE_NAMES.contains(&name) {
156 if let Some(&top) = history.get(&qubits[0]).and_then(|stack| stack.last()) {
157 let all_same_top = qubits
158 .iter()
159 .all(|q| history.get(q).and_then(|s| s.last()) == Some(&top));
160 if all_same_top {
161 if let Some(Some(prev)) = output.get(top) {
162 if prev.name() == name && prev.qubits() == qubits {
163 cancel_idx = Some(top);
164 }
165 }
166 }
167 }
168 }
169
170 if let Some(idx) = cancel_idx {
171 output[idx] = None;
172 for q in &qubits {
173 if let Some(stack) = history.get_mut(q) {
174 stack.pop();
175 }
176 }
177 } else {
178 let new_idx = output.len();
179 for q in &qubits {
180 history.entry(*q).or_default().push(new_idx);
181 }
182 output.push(Some(gate));
183 }
184 }
185
186 let surviving: Vec<Box<dyn GateOp>> = output.into_iter().flatten().collect();
187 Circuit::from_gates(surviving).map_err(|e| {
188 DeviceError::CircuitConversion(format!(
189 "Failed to rebuild circuit after gate cancellation: {e}"
190 ))
191 })
192}
193
194fn apply_gate_to_statevector(state: &mut [Complex64], gate: &dyn GateOp) -> DeviceResult<()> {
201 let qubits = gate.qubits();
202 let k = qubits.len();
203 if k == 0 {
204 return Ok(());
205 }
206
207 let matrix = gate.matrix().map_err(|e| {
208 DeviceError::CircuitConversion(format!(
209 "Failed to obtain matrix for gate '{}': {e}",
210 gate.name()
211 ))
212 })?;
213 let dim_gate = 1usize << k;
214 if matrix.len() != dim_gate * dim_gate {
215 return Err(DeviceError::CircuitConversion(format!(
216 "Gate '{}' matrix has {} entries, expected {dim_gate}x{dim_gate} for a {k}-qubit gate",
217 gate.name(),
218 matrix.len()
219 )));
220 }
221
222 let dim = state.len();
223 let qubit_idx: Vec<usize> = qubits.iter().map(|q| q.id() as usize).collect();
224 let zero = Complex64::new(0.0, 0.0);
225 let mut new_state = vec![zero; dim];
226
227 for i in 0..dim {
228 let amp = state[i];
229 if amp == zero {
230 continue;
231 }
232
233 let mut sub_in = 0usize;
234 for (pos, &q) in qubit_idx.iter().enumerate() {
235 let bit = (i >> q) & 1;
236 sub_in |= bit << (k - 1 - pos);
237 }
238
239 for sub_out in 0..dim_gate {
240 let m = matrix[sub_out * dim_gate + sub_in];
241 if m == zero {
242 continue;
243 }
244 let mut out_idx = i;
245 for (pos, &q) in qubit_idx.iter().enumerate() {
246 let bit_out = (sub_out >> (k - 1 - pos)) & 1;
247 let bit_in = (sub_in >> (k - 1 - pos)) & 1;
248 if bit_out != bit_in {
249 out_idx ^= 1 << q;
250 }
251 }
252 new_state[out_idx] += m * amp;
253 }
254 }
255
256 state.copy_from_slice(&new_state);
257 Ok(())
258}
259
260pub(crate) fn simulate_basis_state<const N: usize>(
267 circuit: &Circuit<N>,
268 state_idx: usize,
269) -> DeviceResult<Vec<Complex64>> {
270 let dim = 1usize << N;
271 let mut state = vec![Complex64::new(0.0, 0.0); dim];
272 state[state_idx] = Complex64::new(1.0, 0.0);
273
274 for gate in circuit.gates() {
275 apply_gate_to_statevector(&mut state, gate.as_ref())?;
276 }
277
278 Ok(state)
279}
280
281fn measurement_probabilities<const N: usize>(
284 circuit: &Circuit<N>,
285 state_idx: usize,
286) -> DeviceResult<Vec<f64>> {
287 Ok(simulate_basis_state(circuit, state_idx)?
288 .iter()
289 .map(scirs2_core::Complex64::norm_sqr)
290 .collect())
291}
292
293pub(crate) fn state_fidelity(a: &[Complex64], b: &[Complex64]) -> f64 {
295 let overlap: Complex64 = a.iter().zip(b.iter()).map(|(x, y)| x.conj() * y).sum();
296 overlap.norm_sqr().clamp(0.0, 1.0)
297}
298
299fn append_decomposed_gate<const N: usize>(
305 circuit: &mut Circuit<N>,
306 gate: &crate::translation::DecomposedGate,
307) -> DeviceResult<()> {
308 let qubits = &gate.qubits;
309 let params = &gate.parameters;
310 let err = |e: QuantRS2Error| {
311 DeviceError::CircuitConversion(format!(
312 "Failed to append decomposed gate '{}': {e}",
313 gate.native_gate
314 ))
315 };
316
317 match gate.native_gate.as_str() {
318 "id" => {}
319 "x" => {
320 circuit.x(qubits[0]).map_err(err)?;
321 }
322 "sx" => {
323 circuit.sx(qubits[0]).map_err(err)?;
324 }
325 "rz" => {
326 circuit.rz(qubits[0], params[0]).map_err(err)?;
327 }
328 "rx" => {
329 circuit.rx(qubits[0], params[0]).map_err(err)?;
330 }
331 "ry" => {
332 circuit.ry(qubits[0], params[0]).map_err(err)?;
333 }
334 "h" => {
335 circuit.h(qubits[0]).map_err(err)?;
336 }
337 "y" => {
338 circuit.y(qubits[0]).map_err(err)?;
339 }
340 "z" => {
341 circuit.z(qubits[0]).map_err(err)?;
342 }
343 "s" => {
344 circuit.s(qubits[0]).map_err(err)?;
345 }
346 "t" => {
347 circuit.t(qubits[0]).map_err(err)?;
348 }
349 "cx" | "cnot" | "xx" => {
350 circuit.cnot(qubits[0], qubits[1]).map_err(err)?;
351 }
352 "cz" => {
353 circuit.cz(qubits[0], qubits[1]).map_err(err)?;
354 }
355 "swap" => {
356 circuit.swap(qubits[0], qubits[1]).map_err(err)?;
357 }
358 "ccnot" | "toffoli" => {
359 circuit
360 .toffoli(qubits[0], qubits[1], qubits[2])
361 .map_err(err)?;
362 }
363 other => {
364 return Err(DeviceError::CircuitConversion(format!(
365 "Unknown decomposed native gate: {other}"
366 )));
367 }
368 }
369
370 Ok(())
371}
372
373impl CircuitMigrationEngine {
374 pub fn new(
376 calibration_manager: CalibrationManager,
377 mapper: SciRS2QubitMapper,
378 optimizer: CalibrationOptimizer,
379 translator: GateTranslator,
380 ) -> Self {
381 Self {
382 calibration_manager,
383 mapper,
384 optimizer,
385 translator,
386 migration_cache: RwLock::new(HashMap::new()),
387 performance_tracker: Mutex::new(PerformanceTracker {
388 migration_history: Vec::new(),
389 average_migration_time: Duration::from_secs(0),
390 success_rate: 1.0,
391 common_issues: HashMap::new(),
392 }),
393 }
394 }
395
396 pub async fn migrate_circuit<const N: usize>(
398 &mut self,
399 circuit: &Circuit<N>,
400 config: &MigrationConfig,
401 ) -> DeviceResult<MigrationResult<N>> {
402 let start_time = Instant::now();
403 let mut warnings = Vec::new();
404 let mut transformations = Vec::new();
405
406 let analysis = self.analyze_circuit(circuit, config)?;
408
409 let (translated_circuit, translation_transforms) =
411 self.translate_circuit(circuit, config, &analysis).await?;
412 transformations.extend(translation_transforms);
413
414 let (mapped_circuit, mapping_transforms) = self
416 .map_circuit(&translated_circuit, config, &analysis)
417 .await?;
418 transformations.extend(mapping_transforms);
419
420 let (optimized_circuit, optimization_transforms) = self
422 .optimize_migrated_circuit(&mapped_circuit, config, &analysis)
423 .await?;
424 transformations.extend(optimization_transforms);
425
426 let validation_result = if config.validation_config.enable_validation {
428 Some(
429 self.validate_migration(circuit, &optimized_circuit, config)
430 .await?,
431 )
432 } else {
433 None
434 };
435
436 let metrics = self.calculate_migration_metrics(
438 circuit,
439 &optimized_circuit,
440 &transformations,
441 start_time.elapsed(),
442 )?;
443
444 let success = self.check_migration_requirements(&metrics, config, &mut warnings)?;
446
447 self.record_migration_performance(config, start_time.elapsed(), success, &metrics)
449 .await?;
450
451 Ok(MigrationResult {
452 migrated_circuit: optimized_circuit,
453 metrics,
454 transformations,
455 validation: validation_result,
456 warnings,
457 success,
458 })
459 }
460
461 fn analyze_circuit<const N: usize>(
463 &self,
464 circuit: &Circuit<N>,
465 config: &MigrationConfig,
466 ) -> DeviceResult<CircuitAnalysis> {
467 let gate_analysis = self.analyze_gates(circuit, config)?;
469 let connectivity_analysis = self.analyze_connectivity(circuit, config)?;
470 let resource_analysis = self.analyze_resources(circuit, config)?;
471
472 Ok(CircuitAnalysis {
473 gate_analysis,
474 connectivity_analysis,
475 resource_analysis,
476 compatibility_score: self.calculate_compatibility_score(circuit, config)?,
477 })
478 }
479
480 async fn translate_circuit<const N: usize>(
482 &mut self,
483 circuit: &Circuit<N>,
484 config: &MigrationConfig,
485 analysis: &CircuitAnalysis,
486 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
487 let mut translated_circuit = circuit.clone();
488 let mut transformations = Vec::new();
489
490 let target_caps = query_backend_capabilities(config.target_platform);
492
493 match config.translation_config.gate_strategy {
495 GateTranslationStrategy::PreferNative => {
496 self.translate_to_native_gates(
497 &mut translated_circuit,
498 &target_caps,
499 &mut transformations,
500 )?;
501 }
502 GateTranslationStrategy::MinimizeGates => {
503 self.translate_minimize_gates(
504 &mut translated_circuit,
505 &target_caps,
506 &mut transformations,
507 )?;
508 }
509 GateTranslationStrategy::PreserveFidelity => {
510 self.translate_preserve_fidelity(
511 &mut translated_circuit,
512 &target_caps,
513 &mut transformations,
514 )?;
515 }
516 GateTranslationStrategy::MinimizeDepth => {
517 self.translate_minimize_depth(
518 &mut translated_circuit,
519 &target_caps,
520 &mut transformations,
521 )?;
522 }
523 GateTranslationStrategy::CustomPriority(ref priorities) => {
524 self.translate_custom_priority(
525 &mut translated_circuit,
526 &target_caps,
527 priorities,
528 &mut transformations,
529 )?;
530 }
531 }
532
533 Ok((translated_circuit, transformations))
534 }
535
536 async fn map_circuit<const N: usize>(
538 &mut self,
539 circuit: &Circuit<N>,
540 config: &MigrationConfig,
541 analysis: &CircuitAnalysis,
542 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
543 let mut mapped_circuit = circuit.clone();
544 let mut transformations = Vec::new();
545
546 if config.mapping_config.scirs2_config_placeholder {
547 transformations.push(AppliedTransformation {
553 transformation_type: TransformationType::QubitMapping,
554 description: "SciRS2 mapping (placeholder)".to_string(),
555 impact: TransformationImpact {
556 fidelity_impact: -0.01,
557 time_impact: 0.1,
558 resource_impact: 0.05,
559 confidence: 0.8,
560 },
561 stage: MigrationStage::Mapping,
562 });
563 } else {
564 let simple_mapping = self.create_simple_mapping(circuit, config)?;
566 mapped_circuit = self.apply_simple_mapping(circuit, &simple_mapping)?;
567
568 transformations.push(AppliedTransformation {
569 transformation_type: TransformationType::QubitMapping,
570 description: "Simple qubit mapping".to_string(),
571 impact: TransformationImpact {
572 fidelity_impact: 0.0,
573 time_impact: 0.0,
574 resource_impact: 0.0,
575 confidence: 0.7,
576 },
577 stage: MigrationStage::Mapping,
578 });
579 }
580
581 Ok((mapped_circuit, transformations))
582 }
583
584 async fn optimize_migrated_circuit<const N: usize>(
586 &self,
587 circuit: &Circuit<N>,
588 config: &MigrationConfig,
589 analysis: &CircuitAnalysis,
590 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
591 let mut optimized_circuit = circuit.clone();
592 let mut transformations = Vec::new();
593
594 if config.optimization.enable_optimization {
595 for pass in &config.optimization.optimization_passes {
597 let (new_circuit, pass_transforms) = self
598 .apply_optimization_pass(&optimized_circuit, pass, config)
599 .await?;
600 optimized_circuit = new_circuit;
601 transformations.extend(pass_transforms);
602 }
603
604 if config.optimization.enable_scirs2_optimization {
606 let (sci_optimized, sci_transforms) = self
607 .apply_scirs2_optimization(&optimized_circuit, config)
608 .await?;
609 optimized_circuit = sci_optimized;
610 transformations.extend(sci_transforms);
611 }
612 }
613
614 Ok((optimized_circuit, transformations))
615 }
616
617 async fn validate_migration<const N: usize>(
619 &self,
620 original: &Circuit<N>,
621 migrated: &Circuit<N>,
622 config: &MigrationConfig,
623 ) -> DeviceResult<ValidationResult> {
624 let mut method_results = HashMap::new();
625
626 for method in &config.validation_config.validation_methods {
627 let result = match method {
628 ValidationMethod::FunctionalEquivalence => {
629 self.validate_functional_equivalence(original, migrated)
630 .await?
631 }
632 ValidationMethod::StatisticalComparison => {
633 self.validate_statistical_comparison(original, migrated, config)
634 .await?
635 }
636 ValidationMethod::FidelityMeasurement => {
637 self.validate_fidelity_measurement(original, migrated, config)
638 .await?
639 }
640 ValidationMethod::ProcessTomography => {
641 self.validate_process_tomography(original, migrated, config)
642 .await?
643 }
644 ValidationMethod::BenchmarkTesting => {
645 self.validate_benchmark_testing(original, migrated, config)
646 .await?
647 }
648 };
649 method_results.insert(method.clone(), result);
650 }
651
652 let overall_success = method_results.values().all(|r| r.success);
653 let confidence_score =
654 method_results.values().map(|r| r.score).sum::<f64>() / method_results.len() as f64;
655
656 let statistical_results = self
657 .perform_statistical_validation(original, migrated, config)
658 .await?;
659
660 Ok(ValidationResult {
661 overall_success,
662 method_results,
663 statistical_results,
664 confidence_score,
665 })
666 }
667
668 fn calculate_migration_metrics<const N: usize>(
672 &self,
673 original: &Circuit<N>,
674 migrated: &Circuit<N>,
675 transformations: &[AppliedTransformation],
676 migration_time: Duration,
677 ) -> DeviceResult<MigrationMetrics> {
678 let original_metrics = self.calculate_circuit_metrics(original)?;
679 let migrated_metrics = self.calculate_circuit_metrics(migrated)?;
680
681 let migration_stats = MigrationStatistics {
682 migration_time,
683 transformations_applied: transformations.len(),
684 optimization_iterations: transformations
685 .iter()
686 .filter(|t| t.transformation_type == TransformationType::CircuitOptimization)
687 .count(),
688 mapping_overhead: self.calculate_mapping_overhead(transformations),
689 translation_efficiency: self.calculate_translation_efficiency(transformations),
690 };
691
692 let performance_comparison = PerformanceComparison {
693 fidelity_change: migrated_metrics.estimated_fidelity
694 - original_metrics.estimated_fidelity,
695 execution_time_change: (migrated_metrics.estimated_execution_time.as_secs_f64()
696 / original_metrics.estimated_execution_time.as_secs_f64())
697 - 1.0,
698 depth_change: (migrated_metrics.depth as f64 / original_metrics.depth as f64) - 1.0,
699 gate_count_change: (migrated_metrics.gate_count as f64
700 / original_metrics.gate_count as f64)
701 - 1.0,
702 resource_change: self.calculate_resource_change(&original_metrics, &migrated_metrics),
703 quality_score: self.calculate_quality_score(&original_metrics, &migrated_metrics),
704 };
705
706 Ok(MigrationMetrics {
707 original: original_metrics,
708 migrated: migrated_metrics,
709 migration_stats,
710 performance_comparison,
711 })
712 }
713
714 async fn record_migration_performance(
716 &self,
717 config: &MigrationConfig,
718 execution_time: Duration,
719 success: bool,
720 metrics: &MigrationMetrics,
721 ) -> DeviceResult<()> {
722 let mut tracker = self
723 .performance_tracker
724 .lock()
725 .unwrap_or_else(|e| e.into_inner());
726
727 let record = MigrationPerformanceRecord {
728 config: config.clone(),
729 execution_time,
730 success,
731 quality_score: metrics.performance_comparison.quality_score,
732 timestamp: SystemTime::now(),
733 };
734
735 tracker.migration_history.push(record);
736
737 let total_migrations = tracker.migration_history.len();
739 let successful_migrations = tracker
740 .migration_history
741 .iter()
742 .filter(|r| r.success)
743 .count();
744
745 tracker.success_rate = successful_migrations as f64 / total_migrations as f64;
746
747 let total_time: Duration = tracker
748 .migration_history
749 .iter()
750 .map(|r| r.execution_time)
751 .sum();
752 tracker.average_migration_time = total_time / total_migrations as u32;
753
754 Ok(())
755 }
756
757 fn analyze_gates<const N: usize>(
763 &self,
764 circuit: &Circuit<N>,
765 config: &MigrationConfig,
766 ) -> DeviceResult<GateAnalysis> {
767 let mut gate_types = HashSet::new();
768 let mut unsupported_gates = Vec::new();
769 let mut decomposition_required = HashMap::new();
770
771 for gate in circuit.gates() {
772 let name = gate.name();
773 gate_types.insert(name.to_string());
774
775 let is_native = self.translator.is_native_gate(config.target_platform, name)
776 || self
777 .translator
778 .is_native_gate(config.target_platform, &name.to_lowercase());
779
780 if !is_native {
781 *decomposition_required.entry(name.to_string()).or_insert(0) += 1;
782
783 if gate.num_qubits() > 3 && !unsupported_gates.contains(&name.to_string()) {
784 unsupported_gates.push(name.to_string());
785 }
786 }
787 }
788
789 Ok(GateAnalysis {
790 gate_types,
791 unsupported_gates,
792 decomposition_required,
793 })
794 }
795
796 fn analyze_connectivity<const N: usize>(
797 &self,
798 _circuit: &Circuit<N>,
799 _config: &MigrationConfig,
800 ) -> DeviceResult<ConnectivityAnalysis> {
801 Ok(ConnectivityAnalysis::default())
802 }
803
804 fn analyze_resources<const N: usize>(
805 &self,
806 _circuit: &Circuit<N>,
807 _config: &MigrationConfig,
808 ) -> DeviceResult<ResourceAnalysis> {
809 Ok(ResourceAnalysis::default())
810 }
811
812 fn calculate_compatibility_score<const N: usize>(
816 &self,
817 circuit: &Circuit<N>,
818 config: &MigrationConfig,
819 ) -> DeviceResult<f64> {
820 let gates = circuit.gates();
821 if gates.is_empty() {
822 return Ok(1.0);
823 }
824
825 let native_count = gates
826 .iter()
827 .filter(|gate| {
828 let name = gate.name();
829 self.translator.is_native_gate(config.target_platform, name)
830 || self
831 .translator
832 .is_native_gate(config.target_platform, &name.to_lowercase())
833 })
834 .count();
835
836 Ok(native_count as f64 / gates.len() as f64)
837 }
838
839 fn calculate_circuit_metrics<const N: usize>(
848 &self,
849 circuit: &Circuit<N>,
850 ) -> DeviceResult<CircuitMetrics> {
851 let gates = circuit.gates();
852 let gate_count = gates.len();
853 let depth = circuit.calculate_depth();
854 let latest_calibration = self.calibration_manager.get_latest_calibration();
855
856 let mut gate_counts: HashMap<String, usize> = HashMap::new();
857 let mut estimated_fidelity = 1.0_f64;
858 let mut total_duration_ns = 0.0_f64;
859
860 for gate in gates {
861 *gate_counts.entry(gate.name().to_string()).or_insert(0) += 1;
862
863 let qubits = gate.qubits();
864 let (default_fidelity, default_duration_ns) = match qubits.len() {
865 0 => (1.0, 0.0),
866 1 => (0.9995, 30.0),
867 2 => (0.99, 250.0),
868 _ => (0.95, 500.0),
869 };
870
871 let fidelity = latest_calibration
872 .and_then(|cal| {
873 self.calibration_manager
874 .get_gate_fidelity(&cal.device_id, gate.name(), &qubits)
875 })
876 .unwrap_or(default_fidelity);
877 estimated_fidelity *= fidelity;
878
879 let duration_ns = latest_calibration
880 .and_then(|cal| {
881 self.calibration_manager
882 .get_gate_duration(&cal.device_id, gate.name(), &qubits)
883 })
884 .unwrap_or(default_duration_ns);
885 total_duration_ns += duration_ns.max(0.0);
886 }
887
888 let estimated_execution_time = Duration::from_nanos(total_duration_ns.round() as u64);
889 let amplitude_count = 1u64 << (N.min(30) as u32);
890 let memory_mb = (amplitude_count as f64 * 16.0) / (1024.0 * 1024.0);
892
893 Ok(CircuitMetrics {
894 qubit_count: N,
895 depth,
896 gate_count,
897 gate_counts,
898 estimated_fidelity: estimated_fidelity.clamp(0.0, 1.0),
899 estimated_execution_time,
900 resource_requirements: ResourceMetrics {
901 memory_mb: memory_mb.max(1e-6),
902 cpu_time: Duration::from_micros(gate_count as u64 + 1),
903 qpu_time: estimated_execution_time,
904 network_bandwidth: None,
905 },
906 })
907 }
908
909 fn translate_to_native_gates<const N: usize>(
924 &mut self,
925 circuit: &mut Circuit<N>,
926 caps: &BackendCapabilities,
927 transforms: &mut Vec<AppliedTransformation>,
928 ) -> DeviceResult<()> {
929 let before_gate_count = circuit.gates().len();
930 let translated = self.translate_circuit_case_aware(circuit, caps.backend)?;
931 let after_gate_count = translated.gates().len();
932 *circuit = translated;
933
934 transforms.push(AppliedTransformation {
935 transformation_type: TransformationType::GateTranslation,
936 description: format!(
937 "Translated circuit to {:?} native gate set ({before_gate_count} -> {after_gate_count} gates)",
938 caps.backend
939 ),
940 impact: TransformationImpact {
941 fidelity_impact: 0.0,
942 time_impact: (after_gate_count as f64 - before_gate_count as f64)
943 / before_gate_count.max(1) as f64,
944 resource_impact: 0.0,
945 confidence: 0.9,
946 },
947 stage: MigrationStage::Translation,
948 });
949 Ok(())
950 }
951
952 pub(crate) fn translate_circuit_case_aware<const N: usize>(
958 &mut self,
959 circuit: &Circuit<N>,
960 backend: HardwareBackend,
961 ) -> DeviceResult<Circuit<N>> {
962 let mut translated = Circuit::<N>::new();
963
964 for gate_arc in circuit.gates() {
965 let name = gate_arc.name();
966 let already_native = self.translator.is_native_gate(backend, name)
967 || self
968 .translator
969 .is_native_gate(backend, &name.to_lowercase());
970
971 if already_native {
972 translated.add_gate_arc(Arc::clone(gate_arc)).map_err(|e| {
973 DeviceError::CircuitConversion(format!(
974 "Failed to copy already-native gate '{name}': {e}"
975 ))
976 })?;
977 continue;
978 }
979
980 let decomposed = self
981 .translator
982 .translate_gate(gate_arc.as_ref(), backend)
983 .map_err(|e| {
984 DeviceError::CircuitConversion(format!(
985 "Native gate translation to {backend:?} failed for gate '{name}': {e}"
986 ))
987 })?;
988
989 for dec in &decomposed {
990 append_decomposed_gate(&mut translated, dec)?;
991 }
992 }
993
994 Ok(translated)
995 }
996
997 fn translate_minimize_gates<const N: usize>(
1000 &mut self,
1001 circuit: &mut Circuit<N>,
1002 caps: &BackendCapabilities,
1003 transforms: &mut Vec<AppliedTransformation>,
1004 ) -> DeviceResult<()> {
1005 self.translate_to_native_gates(circuit, caps, transforms)?;
1006
1007 let before_gate_count = circuit.gates().len();
1008 let cancelled = cancel_adjacent_self_inverse_gates(circuit)?;
1009 let after_gate_count = cancelled.gates().len();
1010 *circuit = cancelled;
1011
1012 transforms.push(AppliedTransformation {
1013 transformation_type: TransformationType::CircuitOptimization,
1014 description: format!(
1015 "Cancelled adjacent self-inverse gate pairs to minimize gate count ({before_gate_count} -> {after_gate_count} gates)"
1016 ),
1017 impact: TransformationImpact {
1018 fidelity_impact: 0.0,
1019 time_impact: (after_gate_count as f64 - before_gate_count as f64)
1020 / before_gate_count.max(1) as f64,
1021 resource_impact: (after_gate_count as f64 - before_gate_count as f64)
1022 / before_gate_count.max(1) as f64,
1023 confidence: 1.0,
1024 },
1025 stage: MigrationStage::Translation,
1026 });
1027 Ok(())
1028 }
1029
1030 fn translate_preserve_fidelity<const N: usize>(
1036 &mut self,
1037 circuit: &mut Circuit<N>,
1038 caps: &BackendCapabilities,
1039 transforms: &mut Vec<AppliedTransformation>,
1040 ) -> DeviceResult<()> {
1041 self.translate_to_native_gates(circuit, caps, transforms)?;
1042
1043 let before_gate_count = circuit.gates().len();
1044 let cancelled = cancel_adjacent_self_inverse_gates(circuit)?;
1045 let after_gate_count = cancelled.gates().len();
1046 *circuit = cancelled;
1047
1048 transforms.push(AppliedTransformation {
1049 transformation_type: TransformationType::CircuitOptimization,
1050 description: format!(
1051 "Removed {} identity-composing gate pair(s) to avoid unnecessary accumulated gate error",
1052 (before_gate_count.saturating_sub(after_gate_count)) / 2
1053 ),
1054 impact: TransformationImpact {
1055 fidelity_impact: if after_gate_count < before_gate_count {
1056 0.0005 * (before_gate_count - after_gate_count) as f64
1057 } else {
1058 0.0
1059 },
1060 time_impact: (after_gate_count as f64 - before_gate_count as f64)
1061 / before_gate_count.max(1) as f64,
1062 resource_impact: 0.0,
1063 confidence: 1.0,
1064 },
1065 stage: MigrationStage::Translation,
1066 });
1067 Ok(())
1068 }
1069
1070 fn translate_minimize_depth<const N: usize>(
1075 &mut self,
1076 circuit: &mut Circuit<N>,
1077 caps: &BackendCapabilities,
1078 transforms: &mut Vec<AppliedTransformation>,
1079 ) -> DeviceResult<()> {
1080 self.translate_to_native_gates(circuit, caps, transforms)?;
1081
1082 let before_depth = circuit.calculate_depth();
1083 let cancelled = cancel_adjacent_self_inverse_gates(circuit)?;
1084 let after_depth = cancelled.calculate_depth();
1085 *circuit = cancelled;
1086
1087 transforms.push(AppliedTransformation {
1088 transformation_type: TransformationType::CircuitOptimization,
1089 description: format!(
1090 "Applied gate cancellation for depth reduction (depth {before_depth} -> {after_depth})"
1091 ),
1092 impact: TransformationImpact {
1093 fidelity_impact: 0.0,
1094 time_impact: (after_depth as f64 - before_depth as f64) / before_depth.max(1) as f64,
1095 resource_impact: 0.0,
1096 confidence: 0.85,
1097 },
1098 stage: MigrationStage::Translation,
1099 });
1100 Ok(())
1101 }
1102
1103 fn translate_custom_priority<const N: usize>(
1108 &mut self,
1109 circuit: &mut Circuit<N>,
1110 caps: &BackendCapabilities,
1111 priorities: &[String],
1112 transforms: &mut Vec<AppliedTransformation>,
1113 ) -> DeviceResult<()> {
1114 self.translate_to_native_gates(circuit, caps, transforms)?;
1115
1116 let gates = circuit.gates();
1117 let total = gates.len().max(1);
1118 let matching = gates
1119 .iter()
1120 .filter(|g| priorities.iter().any(|p| p.eq_ignore_ascii_case(g.name())))
1121 .count();
1122 let adherence = matching as f64 / total as f64;
1123
1124 transforms.push(AppliedTransformation {
1125 transformation_type: TransformationType::GateTranslation,
1126 description: format!(
1127 "Custom-priority translation: {:.1}% of translated gates ({matching}/{total}) match the supplied priority list {priorities:?}",
1128 adherence * 100.0
1129 ),
1130 impact: TransformationImpact {
1131 fidelity_impact: 0.0,
1132 time_impact: 0.0,
1133 resource_impact: 0.0,
1134 confidence: adherence,
1135 },
1136 stage: MigrationStage::Translation,
1137 });
1138 Ok(())
1139 }
1140
1141 fn create_simple_mapping<const N: usize>(
1143 &self,
1144 _circuit: &Circuit<N>,
1145 _config: &MigrationConfig,
1146 ) -> DeviceResult<HashMap<QubitId, QubitId>> {
1147 Ok(HashMap::new())
1148 }
1149 fn apply_simple_mapping<const N: usize>(
1150 &self,
1151 circuit: &Circuit<N>,
1152 _mapping: &HashMap<QubitId, QubitId>,
1153 ) -> DeviceResult<Circuit<N>> {
1154 Ok(circuit.clone())
1155 }
1156
1157 async fn apply_optimization_pass<const N: usize>(
1164 &self,
1165 circuit: &Circuit<N>,
1166 pass: &OptimizationPass,
1167 _config: &MigrationConfig,
1168 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
1169 match pass {
1170 OptimizationPass::GateSetReduction
1171 | OptimizationPass::DepthMinimization
1172 | OptimizationPass::SchedulingOptimization
1173 | OptimizationPass::Parallelization
1174 | OptimizationPass::ResourceOptimization => {
1175 let before_gate_count = circuit.gates().len();
1176 let before_depth = circuit.calculate_depth();
1177 let optimized = cancel_adjacent_self_inverse_gates(circuit)?;
1178 let after_gate_count = optimized.gates().len();
1179 let after_depth = optimized.calculate_depth();
1180
1181 let transforms = vec![AppliedTransformation {
1182 transformation_type: TransformationType::CircuitOptimization,
1183 description: format!(
1184 "{pass:?}: gate cancellation ({before_gate_count} -> {after_gate_count} gates, depth {before_depth} -> {after_depth})"
1185 ),
1186 impact: TransformationImpact {
1187 fidelity_impact: 0.0,
1188 time_impact: (after_gate_count as f64 - before_gate_count as f64)
1189 / before_gate_count.max(1) as f64,
1190 resource_impact: (after_depth as f64 - before_depth as f64)
1191 / before_depth.max(1) as f64,
1192 confidence: 0.9,
1193 },
1194 stage: MigrationStage::Optimization,
1195 }];
1196 Ok((optimized, transforms))
1197 }
1198 OptimizationPass::LayoutOptimization => {
1199 Ok((circuit.clone(), vec![]))
1203 }
1204 OptimizationPass::ErrorMitigation => {
1205 Ok((
1210 circuit.clone(),
1211 vec![AppliedTransformation {
1212 transformation_type: TransformationType::ErrorMitigation,
1213 description:
1214 "Error mitigation insertion not implemented for this pass; circuit left unchanged"
1215 .to_string(),
1216 impact: TransformationImpact {
1217 fidelity_impact: 0.0,
1218 time_impact: 0.0,
1219 resource_impact: 0.0,
1220 confidence: 0.0,
1221 },
1222 stage: MigrationStage::Optimization,
1223 }],
1224 ))
1225 }
1226 }
1227 }
1228
1229 #[cfg(feature = "scirs2")]
1234 async fn apply_scirs2_optimization<const N: usize>(
1235 &self,
1236 circuit: &Circuit<N>,
1237 config: &MigrationConfig,
1238 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
1239 use scirs2_core::ndarray::ArrayView1;
1240
1241 let max_iterations = config.optimization.max_iterations.clamp(1, 8);
1242 let weights = &config.optimization.multi_objective_weights;
1243 let fidelity_weight = weights.get("fidelity").copied().unwrap_or(0.4);
1244 let time_weight = weights.get("time").copied().unwrap_or(0.3);
1245 let resource_weight = weights.get("resources").copied().unwrap_or(0.3);
1246
1247 let original_metrics = self.calculate_circuit_metrics(circuit)?;
1248
1249 let mut candidates: Vec<Circuit<N>> = vec![circuit.clone()];
1252 for _ in 0..max_iterations {
1253 let last = candidates
1254 .last()
1255 .ok_or_else(|| DeviceError::CircuitConversion("candidate ladder empty".into()))?;
1256 let next = cancel_adjacent_self_inverse_gates(last)?;
1257 let converged = next.gates().len() == last.gates().len();
1258 candidates.push(next);
1259 if converged {
1260 break;
1261 }
1262 }
1263
1264 let objective = |params: &ArrayView1<f64>| -> f64 {
1265 let idx = (params[0].round().max(0.0) as usize).min(candidates.len() - 1);
1266 let candidate = &candidates[idx];
1267 let metrics = self
1268 .calculate_circuit_metrics(candidate)
1269 .unwrap_or_else(|_| original_metrics.clone());
1270
1271 let fidelity_cost = 1.0 - metrics.estimated_fidelity;
1272 let time_cost = metrics.estimated_execution_time.as_secs_f64()
1273 / original_metrics
1274 .estimated_execution_time
1275 .as_secs_f64()
1276 .max(1e-12);
1277 let resource_cost = metrics.resource_requirements.memory_mb
1278 / original_metrics.resource_requirements.memory_mb.max(1e-12);
1279
1280 fidelity_weight.mul_add(
1281 fidelity_cost,
1282 time_weight.mul_add(time_cost, resource_weight * resource_cost),
1283 )
1284 };
1285
1286 let initial = [(candidates.len() as f64 - 1.0).max(0.0)];
1287 let opt_result = minimize(
1288 objective,
1289 &initial,
1290 scirs2_optimize::unconstrained::Method::NelderMead,
1291 None,
1292 )
1293 .map_err(|e| DeviceError::CircuitConversion(format!("SciRS2 optimization failed: {e}")))?;
1294
1295 let best_idx = (opt_result.x[0].round().max(0.0) as usize).min(candidates.len() - 1);
1296 let optimized_circuit = candidates[best_idx].clone();
1297 let optimized_metrics = self.calculate_circuit_metrics(&optimized_circuit)?;
1298
1299 let transforms = vec![AppliedTransformation {
1300 transformation_type: TransformationType::CircuitOptimization,
1301 description: format!(
1302 "SciRS2 multi-objective search selected {best_idx} cancellation pass(es) (objective={:.4}, gates {} -> {})",
1303 opt_result.fun, original_metrics.gate_count, optimized_metrics.gate_count
1304 ),
1305 impact: TransformationImpact {
1306 fidelity_impact: optimized_metrics.estimated_fidelity
1307 - original_metrics.estimated_fidelity,
1308 time_impact: optimized_metrics.estimated_execution_time.as_secs_f64()
1309 - original_metrics.estimated_execution_time.as_secs_f64(),
1310 resource_impact: optimized_metrics.resource_requirements.memory_mb
1311 - original_metrics.resource_requirements.memory_mb,
1312 confidence: if opt_result.success { 0.9 } else { 0.5 },
1313 },
1314 stage: MigrationStage::Optimization,
1315 }];
1316
1317 Ok((optimized_circuit, transforms))
1318 }
1319
1320 #[cfg(not(feature = "scirs2"))]
1325 async fn apply_scirs2_optimization<const N: usize>(
1326 &self,
1327 circuit: &Circuit<N>,
1328 config: &MigrationConfig,
1329 ) -> DeviceResult<(Circuit<N>, Vec<AppliedTransformation>)> {
1330 let before_gate_count = circuit.gates().len();
1331 let iterations = config.optimization.max_iterations.clamp(1, 8);
1332
1333 let mut optimized = circuit.clone();
1334 for _ in 0..iterations {
1335 let next = cancel_adjacent_self_inverse_gates(&optimized)?;
1336 let converged = next.gates().len() == optimized.gates().len();
1337 optimized = next;
1338 if converged {
1339 break;
1340 }
1341 }
1342 let after_gate_count = optimized.gates().len();
1343
1344 let transforms = vec![AppliedTransformation {
1345 transformation_type: TransformationType::CircuitOptimization,
1346 description: format!(
1347 "Non-SciRS2 fallback optimization: cancellation passes ({before_gate_count} -> {after_gate_count} gates)"
1348 ),
1349 impact: TransformationImpact {
1350 fidelity_impact: 0.0,
1351 time_impact: (after_gate_count as f64 - before_gate_count as f64)
1352 / before_gate_count.max(1) as f64,
1353 resource_impact: 0.0,
1354 confidence: 0.6,
1355 },
1356 stage: MigrationStage::Optimization,
1357 }];
1358
1359 Ok((optimized, transforms))
1360 }
1361
1362 async fn validate_functional_equivalence<const N: usize>(
1366 &self,
1367 original: &Circuit<N>,
1368 migrated: &Circuit<N>,
1369 ) -> DeviceResult<ValidationMethodResult> {
1370 let mut checker = EquivalenceChecker::default();
1371 match checker.check_equivalence(original, migrated) {
1372 Ok(result) => Ok(ValidationMethodResult {
1373 success: result.equivalent,
1374 score: result.confidence_score,
1375 details: result.details,
1376 p_value: result.statistical_significance,
1377 }),
1378 Err(_) => {
1379 let num_states = (1usize << N).min(16);
1386 let mut max_infidelity = 0.0_f64;
1387 for state_idx in 0..num_states {
1388 let original_state = simulate_basis_state(original, state_idx)?;
1389 let migrated_state = simulate_basis_state(migrated, state_idx)?;
1390 let fidelity = state_fidelity(&original_state, &migrated_state);
1391 max_infidelity = max_infidelity.max((1.0 - fidelity).max(0.0));
1392 }
1393 let score = (1.0 - max_infidelity).clamp(0.0, 1.0);
1394 Ok(ValidationMethodResult {
1395 success: max_infidelity < 1e-6,
1396 score,
1397 details: format!(
1398 "Fallback basis-state simulation over {num_states} input(s) (EquivalenceChecker's built-in gate table did not cover every gate in this circuit): max infidelity {max_infidelity:.3e}"
1399 ),
1400 p_value: None,
1401 })
1402 }
1403 }
1404 }
1405
1406 async fn validate_statistical_comparison<const N: usize>(
1411 &self,
1412 original: &Circuit<N>,
1413 migrated: &Circuit<N>,
1414 config: &MigrationConfig,
1415 ) -> DeviceResult<ValidationMethodResult> {
1416 let num_states = (1usize << N).min(16);
1417 let mut original_probs = Vec::with_capacity(num_states << N);
1418 let mut migrated_probs = Vec::with_capacity(num_states << N);
1419
1420 for state_idx in 0..num_states {
1421 original_probs.extend(measurement_probabilities(original, state_idx)?);
1422 migrated_probs.extend(measurement_probabilities(migrated, state_idx)?);
1423 }
1424
1425 let x = Array1::from_vec(original_probs);
1426 let y = Array1::from_vec(migrated_probs);
1427 let (statistic, p_value) = scirs2_stats::ks_2samp(&x.view(), &y.view(), "two-sided")
1428 .map_err(|e| {
1429 DeviceError::CircuitConversion(format!(
1430 "Statistical (KS-test) comparison failed: {e}"
1431 ))
1432 })?;
1433
1434 let alpha = 1.0 - config.validation_config.confidence_level;
1435 let success = p_value > alpha;
1436
1437 Ok(ValidationMethodResult {
1438 success,
1439 score: (1.0 - statistic).clamp(0.0, 1.0),
1440 details: format!(
1441 "Two-sample KS test over {num_states} basis-state measurement distributions: D={statistic:.4}, p={p_value:.4} (alpha={alpha:.3})"
1442 ),
1443 p_value: Some(p_value),
1444 })
1445 }
1446
1447 async fn validate_fidelity_measurement<const N: usize>(
1456 &self,
1457 original: &Circuit<N>,
1458 migrated: &Circuit<N>,
1459 config: &MigrationConfig,
1460 ) -> DeviceResult<ValidationMethodResult> {
1461 let num_states = (1usize << N).min(16);
1462 let mut min_fidelity_observed = 1.0_f64;
1463
1464 for state_idx in 0..num_states {
1465 let original_state = simulate_basis_state(original, state_idx)?;
1466 let migrated_state = simulate_basis_state(migrated, state_idx)?;
1467 let fidelity = state_fidelity(&original_state, &migrated_state);
1468 min_fidelity_observed = min_fidelity_observed.min(fidelity);
1469 }
1470
1471 let min_required = config.performance_requirements.min_fidelity.unwrap_or(0.0);
1472
1473 Ok(ValidationMethodResult {
1474 success: min_fidelity_observed >= min_required,
1475 score: min_fidelity_observed,
1476 details: format!(
1477 "State-vector fidelity (worst case over {num_states} basis-state input(s)): {min_fidelity_observed:.6}"
1478 ),
1479 p_value: None,
1480 })
1481 }
1482
1483 async fn validate_process_tomography<const N: usize>(
1492 &self,
1493 original: &Circuit<N>,
1494 migrated: &Circuit<N>,
1495 config: &MigrationConfig,
1496 ) -> DeviceResult<ValidationMethodResult> {
1497 let num_states = (1usize << N).min(16);
1498 let mut fidelities = Vec::with_capacity(num_states);
1499
1500 for state_idx in 0..num_states {
1501 let original_state = simulate_basis_state(original, state_idx)?;
1502 let migrated_state = simulate_basis_state(migrated, state_idx)?;
1503 fidelities.push(state_fidelity(&original_state, &migrated_state));
1504 }
1505
1506 let avg_fidelity = fidelities.iter().sum::<f64>() / fidelities.len().max(1) as f64;
1507 let min_fidelity = fidelities.iter().copied().fold(f64::INFINITY, f64::min);
1508 let min_required = config.performance_requirements.min_fidelity.unwrap_or(0.99);
1509
1510 Ok(ValidationMethodResult {
1511 success: min_fidelity >= min_required,
1512 score: avg_fidelity,
1513 details: format!(
1514 "Basis-state-averaged process fidelity estimate over {num_states} input(s): mean={avg_fidelity:.6}, min={min_fidelity:.6} (approximate process comparison, not a full process-tomography reconstruction)"
1515 ),
1516 p_value: None,
1517 })
1518 }
1519
1520 async fn validate_benchmark_testing<const N: usize>(
1524 &self,
1525 original: &Circuit<N>,
1526 migrated: &Circuit<N>,
1527 config: &MigrationConfig,
1528 ) -> DeviceResult<ValidationMethodResult> {
1529 let original_metrics = self.calculate_circuit_metrics(original)?;
1530 let migrated_metrics = self.calculate_circuit_metrics(migrated)?;
1531
1532 let depth_ratio = migrated_metrics.depth as f64 / original_metrics.depth.max(1) as f64;
1533 let gate_ratio =
1534 migrated_metrics.gate_count as f64 / original_metrics.gate_count.max(1) as f64;
1535
1536 let depth_ok = config
1537 .performance_requirements
1538 .max_depth_increase
1539 .is_none_or(|max| (depth_ratio - 1.0) <= max);
1540 let gate_ok = config
1541 .performance_requirements
1542 .max_gate_increase
1543 .is_none_or(|max| (gate_ratio - 1.0) <= max);
1544
1545 let success = depth_ok && gate_ok;
1546 let score = (2.0 - (depth_ratio - 1.0).max(0.0) - (gate_ratio - 1.0).max(0.0))
1547 .clamp(0.0, 2.0)
1548 / 2.0;
1549
1550 Ok(ValidationMethodResult {
1551 success,
1552 score,
1553 details: format!(
1554 "Benchmark comparison: depth {} -> {} ({depth_ratio:.2}x), gates {} -> {} ({gate_ratio:.2}x)",
1555 original_metrics.depth,
1556 migrated_metrics.depth,
1557 original_metrics.gate_count,
1558 migrated_metrics.gate_count
1559 ),
1560 p_value: None,
1561 })
1562 }
1563
1564 async fn perform_statistical_validation<const N: usize>(
1573 &self,
1574 original: &Circuit<N>,
1575 migrated: &Circuit<N>,
1576 _config: &MigrationConfig,
1577 ) -> DeviceResult<StatisticalValidationResult> {
1578 let num_states = (1usize << N).min(16);
1579 let mut original_probs = Vec::new();
1580 let mut migrated_probs = Vec::new();
1581 let mut fidelities = Vec::with_capacity(num_states);
1582
1583 for state_idx in 0..num_states {
1584 let original_state = simulate_basis_state(original, state_idx)?;
1585 let migrated_state = simulate_basis_state(migrated, state_idx)?;
1586 fidelities.push(state_fidelity(&original_state, &migrated_state));
1587 original_probs.extend(original_state.iter().map(scirs2_core::Complex64::norm_sqr));
1588 migrated_probs.extend(migrated_state.iter().map(scirs2_core::Complex64::norm_sqr));
1589 }
1590
1591 let x = Array1::from_vec(original_probs.clone());
1592 let y = Array1::from_vec(migrated_probs.clone());
1593 let (ks_statistic, ks_p_value) = scirs2_stats::ks_2samp(&x.view(), &y.view(), "two-sided")
1594 .map_err(|e| DeviceError::CircuitConversion(format!("KS test failed: {e}")))?;
1595
1596 let chi_square: f64 = original_probs
1599 .iter()
1600 .zip(migrated_probs.iter())
1601 .map(|(o, m)| {
1602 let denom = (o + m).max(1e-12);
1603 (o - m).powi(2) / denom
1604 })
1605 .sum();
1606 let degrees_of_freedom = original_probs.len().saturating_sub(1).max(1) as f64;
1607 let chi_square_p_value = (-chi_square / (2.0 * degrees_of_freedom))
1608 .exp()
1609 .clamp(0.0, 1.0);
1610
1611 let distance = original_probs
1612 .iter()
1613 .zip(migrated_probs.iter())
1614 .map(|(o, m)| (o - m).abs())
1615 .fold(0.0_f64, f64::max);
1616 let similarity_score = (1.0 - distance).clamp(0.0, 1.0);
1617
1618 let avg_state_fidelity = fidelities.iter().sum::<f64>() / fidelities.len().max(1) as f64;
1619
1620 Ok(StatisticalValidationResult {
1621 distribution_comparison: DistributionComparison {
1622 ks_test_p_value: ks_p_value,
1623 chi_square_p_value,
1624 distance,
1625 similarity_score,
1626 },
1627 fidelity_comparison: FidelityComparison {
1628 original_fidelity: 1.0,
1629 migrated_fidelity: avg_state_fidelity,
1630 fidelity_loss: (1.0 - avg_state_fidelity).max(0.0),
1631 significance: ks_p_value,
1632 },
1633 error_analysis: ErrorAnalysis {
1634 error_rate_comparison: (1.0 - avg_state_fidelity).max(0.0),
1635 error_correlation: (1.0 - distance).clamp(0.0, 1.0),
1636 systematic_errors: if avg_state_fidelity < 0.999 {
1637 vec![format!(
1638 "Average state fidelity {avg_state_fidelity:.6} indicates the migrated circuit diverges from the original"
1639 )]
1640 } else {
1641 Vec::new()
1642 },
1643 random_error_estimate: ks_statistic,
1644 },
1645 })
1646 }
1647
1648 fn calculate_mapping_overhead(&self, transformations: &[AppliedTransformation]) -> f64 {
1649 transformations
1650 .iter()
1651 .filter(|t| t.transformation_type == TransformationType::QubitMapping)
1652 .map(|t| t.impact.time_impact.abs())
1653 .sum()
1654 }
1655
1656 fn calculate_translation_efficiency(&self, transformations: &[AppliedTransformation]) -> f64 {
1657 let translation_transforms = transformations
1658 .iter()
1659 .filter(|t| t.transformation_type == TransformationType::GateTranslation)
1660 .count();
1661
1662 if translation_transforms > 0 {
1663 1.0 / (translation_transforms as f64).mul_add(0.1, 1.0)
1664 } else {
1665 1.0
1666 }
1667 }
1668
1669 fn calculate_resource_change(
1670 &self,
1671 original: &CircuitMetrics,
1672 migrated: &CircuitMetrics,
1673 ) -> f64 {
1674 let memory_change = migrated.resource_requirements.memory_mb
1675 / original.resource_requirements.memory_mb
1676 - 1.0;
1677 let cpu_change = migrated.resource_requirements.cpu_time.as_secs_f64()
1678 / original.resource_requirements.cpu_time.as_secs_f64()
1679 - 1.0;
1680 let qpu_change = migrated.resource_requirements.qpu_time.as_secs_f64()
1681 / original.resource_requirements.qpu_time.as_secs_f64()
1682 - 1.0;
1683
1684 (memory_change + cpu_change + qpu_change) / 3.0
1685 }
1686
1687 fn calculate_quality_score(&self, original: &CircuitMetrics, migrated: &CircuitMetrics) -> f64 {
1688 let fidelity_ratio = migrated.estimated_fidelity / original.estimated_fidelity;
1689 let depth_penalty = if migrated.depth > original.depth {
1690 ((migrated.depth - original.depth) as f64 / original.depth as f64).mul_add(-0.1, 1.0)
1691 } else {
1692 1.0
1693 };
1694 let gate_penalty = if migrated.gate_count > original.gate_count {
1695 ((migrated.gate_count - original.gate_count) as f64 / original.gate_count as f64)
1696 .mul_add(-0.05, 1.0)
1697 } else {
1698 1.0
1699 };
1700
1701 (fidelity_ratio * depth_penalty * gate_penalty).clamp(0.0, 1.0)
1702 }
1703
1704 fn check_migration_requirements(
1705 &self,
1706 metrics: &MigrationMetrics,
1707 config: &MigrationConfig,
1708 warnings: &mut Vec<MigrationWarning>,
1709 ) -> DeviceResult<bool> {
1710 let mut success = true;
1711
1712 if let Some(min_fidelity) = config.performance_requirements.min_fidelity {
1714 if metrics.migrated.estimated_fidelity < min_fidelity {
1715 warnings.push(MigrationWarning {
1716 warning_type: WarningType::FidelityLoss,
1717 message: format!(
1718 "Migrated fidelity ({:.3}) below requirement ({:.3})",
1719 metrics.migrated.estimated_fidelity, min_fidelity
1720 ),
1721 severity: WarningSeverity::Error,
1722 suggested_actions: vec![
1723 "Adjust migration strategy to preserve fidelity".to_string()
1724 ],
1725 });
1726 success = false;
1727 }
1728 }
1729
1730 if let Some(max_depth_increase) = config.performance_requirements.max_depth_increase {
1732 if metrics.performance_comparison.depth_change > max_depth_increase {
1733 warnings.push(MigrationWarning {
1734 warning_type: WarningType::PerformanceDegradation,
1735 message: format!(
1736 "Circuit depth increased by {:.1}%, exceeding limit of {:.1}%",
1737 metrics.performance_comparison.depth_change * 100.0,
1738 max_depth_increase * 100.0
1739 ),
1740 severity: WarningSeverity::Warning,
1741 suggested_actions: vec!["Enable depth optimization passes".to_string()],
1742 });
1743 }
1744 }
1745
1746 if let Some(max_gate_increase) = config.performance_requirements.max_gate_increase {
1748 if metrics.performance_comparison.gate_count_change > max_gate_increase {
1749 warnings.push(MigrationWarning {
1750 warning_type: WarningType::PerformanceDegradation,
1751 message: format!("Gate count increased by {:.1}%, exceeding limit of {:.1}%",
1752 metrics.performance_comparison.gate_count_change * 100.0,
1753 max_gate_increase * 100.0),
1754 severity: WarningSeverity::Warning,
1755 suggested_actions: vec!["Enable gate reduction optimization passes".to_string()],
1756 });
1757 }
1758 }
1759
1760 Ok(success)
1761 }
1762}