1use scirs2_core::ndarray::Array2;
8use scirs2_core::Complex64;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::f64::consts::PI;
12
13use quantrs2_circuit::builder::Circuit;
14use quantrs2_core::{
15 error::{QuantRS2Error, QuantRS2Result},
16 gate::{multi::*, single::*, GateOp},
17 qubit::QubitId,
18 synthesis::{decompose_single_qubit_zyz, decompose_two_qubit_kak},
19};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
23pub enum HardwareBackend {
24 IBMQuantum,
26 GoogleSycamore,
28 IonQ,
30 Rigetti,
32 AmazonBraket,
34 AzureQuantum,
36 Honeywell,
38 Custom(u32), }
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub struct NativeGateSet {
45 pub backend: HardwareBackend,
47 pub single_qubit_gates: Vec<String>,
49 pub two_qubit_gates: Vec<String>,
51 pub multi_qubit_gates: Vec<String>,
53 pub arbitrary_single_qubit: bool,
55 pub rotation_axes: Vec<RotationAxis>,
57 pub constraints: BackendConstraints,
59}
60
61impl Default for NativeGateSet {
62 fn default() -> Self {
63 Self {
64 backend: HardwareBackend::Custom(0),
65 single_qubit_gates: vec![
66 "H".to_string(),
67 "X".to_string(),
68 "Y".to_string(),
69 "Z".to_string(),
70 ],
71 two_qubit_gates: vec!["CNOT".to_string(), "CZ".to_string()],
72 multi_qubit_gates: Vec::new(),
73 arbitrary_single_qubit: true,
74 rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
75 constraints: BackendConstraints::default(),
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
82pub enum RotationAxis {
83 X,
84 Y,
85 Z,
86 XY(f64), Custom(f64, f64, f64), }
89
90#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
92pub struct BackendConstraints {
93 pub max_depth: Option<usize>,
95 pub discrete_angles: Option<Vec<f64>>,
97 pub virtual_z: bool,
99 pub coupling_map: Option<Vec<(usize, usize)>>,
101 pub timing_constraints: Option<TimingConstraints>,
103}
104
105impl Default for BackendConstraints {
106 fn default() -> Self {
107 Self {
108 max_depth: None,
109 discrete_angles: None,
110 virtual_z: false,
111 coupling_map: None,
112 timing_constraints: None,
113 }
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct TimingConstraints {
120 pub min_gate_spacing: f64,
122 pub time_alignment: f64,
124 pub max_duration: Option<f64>,
126}
127
128impl Default for TimingConstraints {
129 fn default() -> Self {
130 Self {
131 min_gate_spacing: 0.0,
132 time_alignment: 1.0,
133 max_duration: None,
134 }
135 }
136}
137
138pub struct GateTranslator {
140 native_gates: HashMap<HardwareBackend, NativeGateSet>,
142 translation_rules: HashMap<(HardwareBackend, String), TranslationRule>,
144 decomposition_cache: HashMap<String, Vec<DecomposedGate>>,
146}
147
148#[derive(Debug, Clone)]
150pub struct TranslationRule {
151 pub gate_name: String,
153 pub method: TranslationMethod,
155 pub fidelity: f64,
157 pub gate_count: usize,
159}
160
161pub enum TranslationMethod {
163 Direct(String),
165 FixedDecomposition(Vec<DecomposedGate>),
167 ParameterizedDecomposition(Box<dyn Fn(Vec<f64>) -> Vec<DecomposedGate> + Send + Sync>),
169 Synthesis(SynthesisMethod),
171 Custom(Box<dyn Fn(&dyn GateOp) -> QuantRS2Result<Vec<DecomposedGate>> + Send + Sync>),
173}
174
175impl std::fmt::Debug for TranslationMethod {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 match self {
178 Self::Direct(s) => write!(f, "Direct({})", s),
179 Self::FixedDecomposition(gates) => write!(f, "FixedDecomposition({:?})", gates),
180 Self::ParameterizedDecomposition(_) => {
181 write!(f, "ParameterizedDecomposition(<function>)")
182 }
183 Self::Synthesis(method) => write!(f, "Synthesis({:?})", method),
184 Self::Custom(_) => write!(f, "Custom(<function>)"),
185 }
186 }
187}
188
189impl Clone for TranslationMethod {
190 fn clone(&self) -> Self {
191 match self {
192 Self::Direct(s) => Self::Direct(s.clone()),
193 Self::FixedDecomposition(gates) => Self::FixedDecomposition(gates.clone()),
194 Self::ParameterizedDecomposition(_) => {
195 panic!(
196 "Cannot clone ParameterizedDecomposition - use Arc<TranslationMethod> instead"
197 )
198 }
199 Self::Synthesis(method) => Self::Synthesis(method.clone()),
200 Self::Custom(_) => {
201 panic!("Cannot clone Custom - use Arc<TranslationMethod> instead")
202 }
203 }
204 }
205}
206
207#[derive(Debug, Clone)]
209pub struct DecomposedGate {
210 pub native_gate: String,
212 pub qubits: Vec<QubitId>,
214 pub parameters: Vec<f64>,
216 pub global_phase: Option<f64>,
218}
219
220#[derive(Debug, Clone, Copy)]
222pub enum SynthesisMethod {
223 SingleQubitZYZ,
225 SingleQubitXYX,
226 SingleQubitU3,
227 KAKDecomposition,
229 CliffordT,
231 SolovayKitaev,
233}
234
235impl GateTranslator {
236 pub fn new() -> Self {
238 let mut translator = Self {
239 native_gates: HashMap::new(),
240 translation_rules: HashMap::new(),
241 decomposition_cache: HashMap::new(),
242 };
243
244 translator.init_ibm_gates();
246 translator.init_google_gates();
247 translator.init_ionq_gates();
248 translator.init_rigetti_gates();
249 translator.init_amazon_gates();
250 translator.init_azure_gates();
251 translator.init_honeywell_gates();
252
253 translator
254 }
255
256 fn init_ibm_gates(&mut self) {
258 let gate_set = NativeGateSet {
259 backend: HardwareBackend::IBMQuantum,
260 single_qubit_gates: vec![
261 "id".to_string(),
262 "rz".to_string(),
263 "sx".to_string(),
264 "x".to_string(),
265 ],
266 two_qubit_gates: vec!["cx".to_string()],
267 multi_qubit_gates: vec![],
268 arbitrary_single_qubit: false,
269 rotation_axes: vec![RotationAxis::Z],
270 constraints: BackendConstraints {
271 max_depth: None,
272 discrete_angles: None,
273 virtual_z: true,
274 coupling_map: None,
275 timing_constraints: None,
276 },
277 };
278
279 self.native_gates
280 .insert(HardwareBackend::IBMQuantum, gate_set);
281
282 self.add_ibm_translation_rules();
284 }
285
286 fn add_ibm_translation_rules(&mut self) {
288 let backend = HardwareBackend::IBMQuantum;
289
290 self.translation_rules.insert(
292 (backend, "H".to_string()),
293 TranslationRule {
294 gate_name: "H".to_string(),
295 method: TranslationMethod::FixedDecomposition(vec![
296 DecomposedGate {
297 native_gate: "rz".to_string(),
298 qubits: vec![QubitId(0)],
299 parameters: vec![PI / 2.0],
300 global_phase: None,
301 },
302 DecomposedGate {
303 native_gate: "sx".to_string(),
304 qubits: vec![QubitId(0)],
305 parameters: vec![],
306 global_phase: None,
307 },
308 DecomposedGate {
309 native_gate: "rz".to_string(),
310 qubits: vec![QubitId(0)],
311 parameters: vec![PI / 2.0],
312 global_phase: None,
313 },
314 ]),
315 fidelity: 0.9999,
316 gate_count: 3,
317 },
318 );
319
320 self.translation_rules.insert(
322 (backend, "Y".to_string()),
323 TranslationRule {
324 gate_name: "Y".to_string(),
325 method: TranslationMethod::FixedDecomposition(vec![
326 DecomposedGate {
327 native_gate: "rz".to_string(),
328 qubits: vec![QubitId(0)],
329 parameters: vec![PI],
330 global_phase: None,
331 },
332 DecomposedGate {
333 native_gate: "x".to_string(),
334 qubits: vec![QubitId(0)],
335 parameters: vec![],
336 global_phase: None,
337 },
338 ]),
339 fidelity: 0.9999,
340 gate_count: 2,
341 },
342 );
343
344 self.translation_rules.insert(
346 (backend, "S".to_string()),
347 TranslationRule {
348 gate_name: "S".to_string(),
349 method: TranslationMethod::Direct("rz".to_string()),
350 fidelity: 1.0,
351 gate_count: 1,
352 },
353 );
354
355 self.translation_rules.insert(
357 (backend, "T".to_string()),
358 TranslationRule {
359 gate_name: "T".to_string(),
360 method: TranslationMethod::Direct("rz".to_string()),
361 fidelity: 1.0,
362 gate_count: 1,
363 },
364 );
365
366 self.translation_rules.insert(
368 (backend, "RX".to_string()),
369 TranslationRule {
370 gate_name: "RX".to_string(),
371 method: TranslationMethod::ParameterizedDecomposition(Box::new(|params| {
372 let theta = params[0];
373 vec![
374 DecomposedGate {
375 native_gate: "rz".to_string(),
376 qubits: vec![QubitId(0)],
377 parameters: vec![PI / 2.0],
378 global_phase: None,
379 },
380 DecomposedGate {
381 native_gate: "sx".to_string(),
382 qubits: vec![QubitId(0)],
383 parameters: vec![],
384 global_phase: None,
385 },
386 DecomposedGate {
387 native_gate: "rz".to_string(),
388 qubits: vec![QubitId(0)],
389 parameters: vec![theta - PI / 2.0],
390 global_phase: None,
391 },
392 DecomposedGate {
393 native_gate: "sx".to_string(),
394 qubits: vec![QubitId(0)],
395 parameters: vec![],
396 global_phase: None,
397 },
398 DecomposedGate {
399 native_gate: "rz".to_string(),
400 qubits: vec![QubitId(0)],
401 parameters: vec![-PI / 2.0],
402 global_phase: None,
403 },
404 ]
405 })),
406 fidelity: 0.9998,
407 gate_count: 5,
408 },
409 );
410
411 self.translation_rules.insert(
413 (backend, "CNOT".to_string()),
414 TranslationRule {
415 gate_name: "CNOT".to_string(),
416 method: TranslationMethod::Direct("cx".to_string()),
417 fidelity: 1.0,
418 gate_count: 1,
419 },
420 );
421 }
422
423 fn init_google_gates(&mut self) {
425 let gate_set = NativeGateSet {
426 backend: HardwareBackend::GoogleSycamore,
427 single_qubit_gates: vec![
428 "ph".to_string(), "x_pow".to_string(), "y_pow".to_string(), "z_pow".to_string(), ],
433 two_qubit_gates: vec![
434 "syc".to_string(), "sqrt_iswap".to_string(),
436 ],
437 multi_qubit_gates: vec![],
438 arbitrary_single_qubit: true,
439 rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
440 constraints: BackendConstraints {
441 max_depth: None,
442 discrete_angles: None,
443 virtual_z: false,
444 coupling_map: None,
445 timing_constraints: None,
446 },
447 };
448
449 self.native_gates
450 .insert(HardwareBackend::GoogleSycamore, gate_set);
451 self.add_google_translation_rules();
452 }
453
454 fn add_google_translation_rules(&mut self) {
456 let backend = HardwareBackend::GoogleSycamore;
457
458 self.translation_rules.insert(
460 (backend, "X".to_string()),
461 TranslationRule {
462 gate_name: "X".to_string(),
463 method: TranslationMethod::FixedDecomposition(vec![DecomposedGate {
464 native_gate: "x_pow".to_string(),
465 qubits: vec![QubitId(0)],
466 parameters: vec![1.0],
467 global_phase: None,
468 }]),
469 fidelity: 1.0,
470 gate_count: 1,
471 },
472 );
473
474 self.translation_rules.insert(
476 (backend, "CNOT".to_string()),
477 TranslationRule {
478 gate_name: "CNOT".to_string(),
479 method: TranslationMethod::FixedDecomposition(vec![
480 DecomposedGate {
482 native_gate: "syc".to_string(),
483 qubits: vec![QubitId(0), QubitId(1)],
484 parameters: vec![],
485 global_phase: None,
486 },
487 ]),
489 fidelity: 0.998,
490 gate_count: 3,
491 },
492 );
493 }
494
495 fn init_ionq_gates(&mut self) {
497 let gate_set = NativeGateSet {
498 backend: HardwareBackend::IonQ,
499 single_qubit_gates: vec!["rx".to_string(), "ry".to_string(), "rz".to_string()],
500 two_qubit_gates: vec![
501 "xx".to_string(), ],
503 multi_qubit_gates: vec![],
504 arbitrary_single_qubit: true,
505 rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
506 constraints: BackendConstraints {
507 max_depth: None,
508 discrete_angles: None,
509 virtual_z: false,
510 coupling_map: None, timing_constraints: None,
512 },
513 };
514
515 self.native_gates.insert(HardwareBackend::IonQ, gate_set);
516 self.add_ionq_translation_rules();
517 }
518
519 fn add_ionq_translation_rules(&mut self) {
521 let backend = HardwareBackend::IonQ;
522
523 self.translation_rules.insert(
525 (backend, "CNOT".to_string()),
526 TranslationRule {
527 gate_name: "CNOT".to_string(),
528 method: TranslationMethod::FixedDecomposition(vec![
529 DecomposedGate {
530 native_gate: "ry".to_string(),
531 qubits: vec![QubitId(0)],
532 parameters: vec![PI / 2.0],
533 global_phase: None,
534 },
535 DecomposedGate {
536 native_gate: "xx".to_string(),
537 qubits: vec![QubitId(0), QubitId(1)],
538 parameters: vec![PI / 2.0],
539 global_phase: None,
540 },
541 DecomposedGate {
542 native_gate: "rx".to_string(),
543 qubits: vec![QubitId(0)],
544 parameters: vec![-PI / 2.0],
545 global_phase: None,
546 },
547 DecomposedGate {
548 native_gate: "rx".to_string(),
549 qubits: vec![QubitId(1)],
550 parameters: vec![-PI / 2.0],
551 global_phase: None,
552 },
553 DecomposedGate {
554 native_gate: "ry".to_string(),
555 qubits: vec![QubitId(0)],
556 parameters: vec![-PI / 2.0],
557 global_phase: None,
558 },
559 ]),
560 fidelity: 0.999,
561 gate_count: 5,
562 },
563 );
564 }
565
566 fn init_rigetti_gates(&mut self) {
568 let gate_set = NativeGateSet {
569 backend: HardwareBackend::Rigetti,
570 single_qubit_gates: vec!["rx".to_string(), "rz".to_string()],
571 two_qubit_gates: vec![
572 "cz".to_string(),
573 "xy".to_string(), ],
575 multi_qubit_gates: vec![],
576 arbitrary_single_qubit: true,
577 rotation_axes: vec![RotationAxis::X, RotationAxis::Z],
578 constraints: BackendConstraints {
579 max_depth: None,
580 discrete_angles: None,
581 virtual_z: false,
582 coupling_map: None,
583 timing_constraints: None,
584 },
585 };
586
587 self.native_gates.insert(HardwareBackend::Rigetti, gate_set);
588 }
589
590 fn init_amazon_gates(&mut self) {
592 let gate_set = NativeGateSet {
594 backend: HardwareBackend::AmazonBraket,
595 single_qubit_gates: vec![
596 "h".to_string(),
597 "x".to_string(),
598 "y".to_string(),
599 "z".to_string(),
600 "rx".to_string(),
601 "ry".to_string(),
602 "rz".to_string(),
603 ],
604 two_qubit_gates: vec!["cnot".to_string(), "cz".to_string(), "swap".to_string()],
605 multi_qubit_gates: vec!["ccnot".to_string()],
606 arbitrary_single_qubit: true,
607 rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
608 constraints: BackendConstraints {
609 max_depth: None,
610 discrete_angles: None,
611 virtual_z: false,
612 coupling_map: None,
613 timing_constraints: None,
614 },
615 };
616
617 self.native_gates
618 .insert(HardwareBackend::AmazonBraket, gate_set);
619 }
620
621 fn init_azure_gates(&mut self) {
623 let gate_set = NativeGateSet {
625 backend: HardwareBackend::AzureQuantum,
626 single_qubit_gates: vec![
627 "h".to_string(),
628 "x".to_string(),
629 "y".to_string(),
630 "z".to_string(),
631 "s".to_string(),
632 "t".to_string(),
633 "rx".to_string(),
634 "ry".to_string(),
635 "rz".to_string(),
636 ],
637 two_qubit_gates: vec!["cnot".to_string(), "cz".to_string()],
638 multi_qubit_gates: vec![],
639 arbitrary_single_qubit: true,
640 rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
641 constraints: BackendConstraints {
642 max_depth: None,
643 discrete_angles: None,
644 virtual_z: false,
645 coupling_map: None,
646 timing_constraints: None,
647 },
648 };
649
650 self.native_gates
651 .insert(HardwareBackend::AzureQuantum, gate_set);
652 }
653
654 fn init_honeywell_gates(&mut self) {
656 let gate_set = NativeGateSet {
657 backend: HardwareBackend::Honeywell,
658 single_qubit_gates: vec![
659 "u1".to_string(), "u2".to_string(), "u3".to_string(), ],
663 two_qubit_gates: vec![
664 "zz".to_string(), ],
666 multi_qubit_gates: vec![],
667 arbitrary_single_qubit: true,
668 rotation_axes: vec![RotationAxis::Custom(1.0, 0.0, 0.0)],
669 constraints: BackendConstraints {
670 max_depth: None,
671 discrete_angles: None,
672 virtual_z: false,
673 coupling_map: None, timing_constraints: None,
675 },
676 };
677
678 self.native_gates
679 .insert(HardwareBackend::Honeywell, gate_set);
680 }
681
682 pub fn get_native_gates(&self, backend: HardwareBackend) -> Option<&NativeGateSet> {
684 self.native_gates.get(&backend)
685 }
686
687 pub fn is_native_gate(&self, backend: HardwareBackend, gate_name: &str) -> bool {
689 if let Some(gate_set) = self.native_gates.get(&backend) {
690 gate_set.single_qubit_gates.contains(&gate_name.to_string())
691 || gate_set.two_qubit_gates.contains(&gate_name.to_string())
692 || gate_set.multi_qubit_gates.contains(&gate_name.to_string())
693 } else {
694 false
695 }
696 }
697
698 pub fn translate_gate(
700 &mut self,
701 gate: &dyn GateOp,
702 backend: HardwareBackend,
703 ) -> QuantRS2Result<Vec<DecomposedGate>> {
704 let gate_name = gate.name();
705
706 if self.is_native_gate(backend, gate_name) {
708 return Ok(vec![DecomposedGate {
709 native_gate: gate_name.to_string(),
710 qubits: gate.qubits(),
711 parameters: self.extract_parameters(gate)?,
712 global_phase: None,
713 }]);
714 }
715
716 let cache_key = format!("{}_{:?}", gate_name, backend);
718 if let Some(cached) = self.decomposition_cache.get(&cache_key) {
719 return Ok(self.remap_qubits(cached.clone(), &gate.qubits()));
720 }
721
722 if let Some(rule) = self
724 .translation_rules
725 .get(&(backend, gate_name.to_string()))
726 {
727 let decomposition = match &rule.method {
728 TranslationMethod::Direct(native_name) => {
729 vec![DecomposedGate {
730 native_gate: native_name.clone(),
731 qubits: gate.qubits(),
732 parameters: self.extract_parameters(gate)?,
733 global_phase: None,
734 }]
735 }
736 TranslationMethod::FixedDecomposition(gates) => {
737 self.remap_qubits(gates.clone(), &gate.qubits())
738 }
739 TranslationMethod::ParameterizedDecomposition(func) => {
740 let params = self.extract_parameters(gate)?;
741 let gates = func(params);
742 self.remap_qubits(gates, &gate.qubits())
743 }
744 TranslationMethod::Synthesis(method) => {
745 self.synthesize_gate(gate, *method, backend)?
746 }
747 TranslationMethod::Custom(func) => func(gate)?,
748 };
749
750 self.decomposition_cache
752 .insert(cache_key, decomposition.clone());
753 return Ok(decomposition);
754 }
755
756 match gate.num_qubits() {
758 1 => self.synthesize_gate(gate, SynthesisMethod::SingleQubitZYZ, backend),
759 2 => self.synthesize_gate(gate, SynthesisMethod::KAKDecomposition, backend),
760 _ => Err(QuantRS2Error::InvalidInput(format!(
761 "No translation available for {}-qubit gate {}",
762 gate.num_qubits(),
763 gate_name
764 ))),
765 }
766 }
767
768 pub fn translate_circuit<const N: usize>(
770 &mut self,
771 circuit: &Circuit<N>,
772 backend: HardwareBackend,
773 ) -> QuantRS2Result<Circuit<N>> {
774 let mut translated = Circuit::<N>::new();
775
776 for gate in circuit.gates() {
777 let decomposed = self.translate_gate(gate.as_ref(), backend)?;
778
779 for dec_gate in decomposed {
780 self.add_decomposed_gate(&mut translated, &dec_gate)?;
781 }
782 }
783
784 Ok(translated)
785 }
786
787 fn extract_parameters(&self, gate: &dyn GateOp) -> QuantRS2Result<Vec<f64>> {
789 Ok(vec![])
792 }
793
794 fn remap_qubits(
796 &self,
797 mut gates: Vec<DecomposedGate>,
798 actual_qubits: &[QubitId],
799 ) -> Vec<DecomposedGate> {
800 for gate in &mut gates {
801 for qubit in &mut gate.qubits {
802 if qubit.id() < actual_qubits.len() as u32 {
803 *qubit = actual_qubits[qubit.id() as usize];
804 }
805 }
806 }
807 gates
808 }
809
810 fn synthesize_gate(
812 &self,
813 gate: &dyn GateOp,
814 method: SynthesisMethod,
815 backend: HardwareBackend,
816 ) -> QuantRS2Result<Vec<DecomposedGate>> {
817 match method {
818 SynthesisMethod::SingleQubitZYZ => {
819 if gate.num_qubits() != 1 {
821 return Err(QuantRS2Error::InvalidInput(
822 "ZYZ synthesis only works for single-qubit gates".into(),
823 ));
824 }
825
826 let matrix_vec = gate.matrix()?;
827 let matrix = Array2::from_shape_vec((2, 2), matrix_vec)
828 .map_err(|_| QuantRS2Error::InvalidInput("Invalid matrix shape".into()))?;
829 let decomp = decompose_single_qubit_zyz(&matrix.view())?;
830
831 Ok(vec![
832 DecomposedGate {
833 native_gate: "rz".to_string(),
834 qubits: gate.qubits(),
835 parameters: vec![decomp.theta1],
836 global_phase: None,
837 },
838 DecomposedGate {
839 native_gate: "ry".to_string(),
840 qubits: gate.qubits(),
841 parameters: vec![decomp.phi],
842 global_phase: None,
843 },
844 DecomposedGate {
845 native_gate: "rz".to_string(),
846 qubits: gate.qubits(),
847 parameters: vec![decomp.theta2],
848 global_phase: Some(decomp.global_phase),
849 },
850 ])
851 }
852 SynthesisMethod::KAKDecomposition => {
853 if gate.num_qubits() != 2 {
855 return Err(QuantRS2Error::InvalidInput(
856 "KAK decomposition only works for two-qubit gates".into(),
857 ));
858 }
859
860 Ok(vec![])
863 }
864 _ => Err(QuantRS2Error::InvalidInput(format!(
865 "Synthesis method {:?} not yet implemented",
866 method
867 ))),
868 }
869 }
870
871 fn add_decomposed_gate<const N: usize>(
873 &self,
874 circuit: &mut Circuit<N>,
875 gate: &DecomposedGate,
876 ) -> QuantRS2Result<()> {
877 match gate.native_gate.as_str() {
878 "id" => {} "x" => {
881 let _ = circuit.x(gate.qubits[0]);
882 }
883 "sx" => {
884 let _ = circuit.sx(gate.qubits[0]);
885 }
886 "rz" => {
887 let _ = circuit.rz(gate.qubits[0], gate.parameters[0]);
888 }
889 "cx" => {
890 let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
891 }
892
893 "rx" => {
895 let _ = circuit.rx(gate.qubits[0], gate.parameters[0]);
896 }
897 "ry" => {
898 let _ = circuit.ry(gate.qubits[0], gate.parameters[0]);
899 }
900 "xx" => {
901 let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
904 }
905
906 "h" => {
908 let _ = circuit.h(gate.qubits[0]);
909 }
910 "y" => {
911 let _ = circuit.y(gate.qubits[0]);
912 }
913 "z" => {
914 let _ = circuit.z(gate.qubits[0]);
915 }
916 "s" => {
917 let _ = circuit.s(gate.qubits[0]);
918 }
919 "t" => {
920 let _ = circuit.t(gate.qubits[0]);
921 }
922 "cnot" => {
923 let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
924 }
925 "cz" => {
926 let _ = circuit.cz(gate.qubits[0], gate.qubits[1]);
927 }
928 "swap" => {
929 let _ = circuit.swap(gate.qubits[0], gate.qubits[1]);
930 }
931 "ccnot" => {
932 let _ = circuit.toffoli(gate.qubits[0], gate.qubits[1], gate.qubits[2]);
933 }
934
935 _ => {
936 return Err(QuantRS2Error::InvalidInput(format!(
937 "Unknown native gate: {}",
938 gate.native_gate
939 )));
940 }
941 }
942
943 Ok(())
944 }
945}
946
947pub struct TranslationOptimizer {
949 translator: GateTranslator,
951 strategy: OptimizationStrategy,
953}
954
955#[derive(Debug, Clone, Copy)]
957pub enum OptimizationStrategy {
958 MinimizeGateCount,
960 MinimizeError,
962 MinimizeDepth,
964 Balanced { weight: f64 },
966}
967
968impl TranslationOptimizer {
969 pub fn new(strategy: OptimizationStrategy) -> Self {
971 Self {
972 translator: GateTranslator::new(),
973 strategy,
974 }
975 }
976
977 pub fn optimize_translation(
979 &mut self,
980 gate: &dyn GateOp,
981 backend: HardwareBackend,
982 ) -> QuantRS2Result<Vec<DecomposedGate>> {
983 let candidates = vec![
985 self.translator.translate_gate(gate, backend)?,
986 ];
988
989 let best = match self.strategy {
991 OptimizationStrategy::MinimizeGateCount => candidates
992 .into_iter()
993 .min_by_key(|c| c.len())
994 .unwrap_or_default(),
995 OptimizationStrategy::MinimizeError => {
996 candidates.into_iter().next().unwrap_or_default()
998 }
999 OptimizationStrategy::MinimizeDepth => {
1000 candidates.into_iter().next().unwrap_or_default()
1002 }
1003 OptimizationStrategy::Balanced { weight } => {
1004 candidates.into_iter().next().unwrap_or_default()
1006 }
1007 };
1008
1009 Ok(best)
1010 }
1011}
1012
1013pub fn validate_native_circuit<const N: usize>(
1015 circuit: &Circuit<N>,
1016 backend: HardwareBackend,
1017) -> QuantRS2Result<bool> {
1018 let translator = GateTranslator::new();
1019
1020 for gate in circuit.gates() {
1021 if !translator.is_native_gate(backend, gate.name()) {
1022 return Ok(false);
1023 }
1024 }
1025
1026 Ok(true)
1027}
1028
1029pub struct TranslationStats {
1031 pub original_gates: usize,
1033 pub native_gates: usize,
1035 pub gate_counts: HashMap<String, usize>,
1037 pub fidelity_loss: f64,
1039 pub depth_ratio: f64,
1041}
1042
1043impl TranslationStats {
1044 pub fn calculate<const N: usize>(
1046 original: &Circuit<N>,
1047 translated: &Circuit<N>,
1048 backend: HardwareBackend,
1049 ) -> Self {
1050 let mut gate_counts = HashMap::new();
1051
1052 for gate in translated.gates() {
1053 *gate_counts.entry(gate.name().to_string()).or_insert(0) += 1;
1054 }
1055
1056 Self {
1057 original_gates: original.gates().len(),
1058 native_gates: translated.gates().len(),
1059 gate_counts,
1060 fidelity_loss: 0.0, depth_ratio: 1.0, }
1063 }
1064}
1065
1066#[cfg(test)]
1067mod tests {
1068 use super::*;
1069
1070 #[test]
1071 fn test_gate_translator_creation() {
1072 let translator = GateTranslator::new();
1073
1074 assert!(translator
1076 .get_native_gates(HardwareBackend::IBMQuantum)
1077 .is_some());
1078 assert!(translator
1079 .get_native_gates(HardwareBackend::GoogleSycamore)
1080 .is_some());
1081 assert!(translator.get_native_gates(HardwareBackend::IonQ).is_some());
1082 }
1083
1084 #[test]
1085 fn test_native_gate_check() {
1086 let translator = GateTranslator::new();
1087
1088 assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "rz"));
1090 assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "sx"));
1091 assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "cx"));
1092 assert!(!translator.is_native_gate(HardwareBackend::IBMQuantum, "h"));
1093
1094 assert!(translator.is_native_gate(HardwareBackend::IonQ, "rx"));
1096 assert!(translator.is_native_gate(HardwareBackend::IonQ, "xx"));
1097 assert!(!translator.is_native_gate(HardwareBackend::IonQ, "cnot"));
1098 }
1099
1100 #[test]
1101 fn test_hadamard_translation_ibm() {
1102 let mut translator = GateTranslator::new();
1103 let h_gate = Hadamard { target: QubitId(0) };
1104
1105 let decomposed = translator
1106 .translate_gate(&h_gate, HardwareBackend::IBMQuantum)
1107 .unwrap();
1108
1109 assert_eq!(decomposed.len(), 3);
1111 assert_eq!(decomposed[0].native_gate, "rz");
1112 assert_eq!(decomposed[1].native_gate, "sx");
1113 assert_eq!(decomposed[2].native_gate, "rz");
1114 }
1115
1116 #[test]
1117 fn test_circuit_translation() {
1118 let mut translator = GateTranslator::new();
1119
1120 let mut circuit = Circuit::<2>::new();
1121 let _ = circuit.h(QubitId(0));
1122 let _ = circuit.cnot(QubitId(0), QubitId(1));
1123
1124 let translated = translator
1125 .translate_circuit(&circuit, HardwareBackend::IBMQuantum)
1126 .unwrap();
1127
1128 assert!(translated.gates().len() >= 4);
1131 }
1132}