use scirs2_core::ndarray::Array2;
use scirs2_core::Complex64;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::f64::consts::PI;
use quantrs2_circuit::builder::Circuit;
use quantrs2_core::{
error::{QuantRS2Error, QuantRS2Result},
gate::{multi::*, single::*, GateOp},
qubit::QubitId,
synthesis::{decompose_single_qubit_zyz, decompose_two_qubit_kak},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum HardwareBackend {
IBMQuantum,
GoogleSycamore,
IonQ,
Rigetti,
AmazonBraket,
AzureQuantum,
Honeywell,
Custom(u32), }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeGateSet {
pub backend: HardwareBackend,
pub single_qubit_gates: Vec<String>,
pub two_qubit_gates: Vec<String>,
pub multi_qubit_gates: Vec<String>,
pub arbitrary_single_qubit: bool,
pub rotation_axes: Vec<RotationAxis>,
pub constraints: BackendConstraints,
}
impl Default for NativeGateSet {
fn default() -> Self {
Self {
backend: HardwareBackend::Custom(0),
single_qubit_gates: vec![
"H".to_string(),
"X".to_string(),
"Y".to_string(),
"Z".to_string(),
],
two_qubit_gates: vec!["CNOT".to_string(), "CZ".to_string()],
multi_qubit_gates: Vec::new(),
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
constraints: BackendConstraints::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum RotationAxis {
X,
Y,
Z,
XY(f64), Custom(f64, f64, f64), }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct BackendConstraints {
pub max_depth: Option<usize>,
pub discrete_angles: Option<Vec<f64>>,
pub virtual_z: bool,
pub coupling_map: Option<Vec<(usize, usize)>>,
pub timing_constraints: Option<TimingConstraints>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TimingConstraints {
pub min_gate_spacing: f64,
pub time_alignment: f64,
pub max_duration: Option<f64>,
}
impl Default for TimingConstraints {
fn default() -> Self {
Self {
min_gate_spacing: 0.0,
time_alignment: 1.0,
max_duration: None,
}
}
}
pub struct GateTranslator {
native_gates: HashMap<HardwareBackend, NativeGateSet>,
translation_rules: HashMap<(HardwareBackend, String), TranslationRule>,
decomposition_cache: HashMap<String, Vec<DecomposedGate>>,
}
#[derive(Debug, Clone)]
pub struct TranslationRule {
pub gate_name: String,
pub method: TranslationMethod,
pub fidelity: f64,
pub gate_count: usize,
}
pub enum TranslationMethod {
Direct(String),
FixedDecomposition(Vec<DecomposedGate>),
ParameterizedDecomposition(Box<dyn Fn(Vec<f64>) -> Vec<DecomposedGate> + Send + Sync>),
Synthesis(SynthesisMethod),
Custom(Box<dyn Fn(&dyn GateOp) -> QuantRS2Result<Vec<DecomposedGate>> + Send + Sync>),
}
impl std::fmt::Debug for TranslationMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Direct(s) => write!(f, "Direct({s})"),
Self::FixedDecomposition(gates) => write!(f, "FixedDecomposition({gates:?})"),
Self::ParameterizedDecomposition(_) => {
write!(f, "ParameterizedDecomposition(<function>)")
}
Self::Synthesis(method) => write!(f, "Synthesis({method:?})"),
Self::Custom(_) => write!(f, "Custom(<function>)"),
}
}
}
impl Clone for TranslationMethod {
fn clone(&self) -> Self {
match self {
Self::Direct(s) => Self::Direct(s.clone()),
Self::FixedDecomposition(gates) => Self::FixedDecomposition(gates.clone()),
Self::ParameterizedDecomposition(_) => {
panic!(
"Cannot clone ParameterizedDecomposition - use Arc<TranslationMethod> instead"
)
}
Self::Synthesis(method) => Self::Synthesis(*method),
Self::Custom(_) => {
panic!("Cannot clone Custom - use Arc<TranslationMethod> instead")
}
}
}
}
#[derive(Debug, Clone)]
pub struct DecomposedGate {
pub native_gate: String,
pub qubits: Vec<QubitId>,
pub parameters: Vec<f64>,
pub global_phase: Option<f64>,
}
#[derive(Debug, Clone, Copy)]
pub enum SynthesisMethod {
SingleQubitZYZ,
SingleQubitXYX,
SingleQubitU3,
KAKDecomposition,
CliffordT,
SolovayKitaev,
}
impl GateTranslator {
pub fn new() -> Self {
let mut translator = Self {
native_gates: HashMap::new(),
translation_rules: HashMap::new(),
decomposition_cache: HashMap::new(),
};
translator.init_ibm_gates();
translator.init_google_gates();
translator.init_ionq_gates();
translator.init_rigetti_gates();
translator.init_amazon_gates();
translator.init_azure_gates();
translator.init_honeywell_gates();
translator
}
fn init_ibm_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::IBMQuantum,
single_qubit_gates: vec![
"id".to_string(),
"rz".to_string(),
"sx".to_string(),
"x".to_string(),
],
two_qubit_gates: vec!["cx".to_string()],
multi_qubit_gates: vec![],
arbitrary_single_qubit: false,
rotation_axes: vec![RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: true,
coupling_map: None,
timing_constraints: None,
},
};
self.native_gates
.insert(HardwareBackend::IBMQuantum, gate_set);
self.add_ibm_translation_rules();
}
fn add_ibm_translation_rules(&mut self) {
let backend = HardwareBackend::IBMQuantum;
self.translation_rules.insert(
(backend, "H".to_string()),
TranslationRule {
gate_name: "H".to_string(),
method: TranslationMethod::FixedDecomposition(vec![
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "sx".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![],
global_phase: None,
},
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![PI / 2.0],
global_phase: None,
},
]),
fidelity: 0.9999,
gate_count: 3,
},
);
self.translation_rules.insert(
(backend, "Y".to_string()),
TranslationRule {
gate_name: "Y".to_string(),
method: TranslationMethod::FixedDecomposition(vec![
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![PI],
global_phase: None,
},
DecomposedGate {
native_gate: "x".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![],
global_phase: None,
},
]),
fidelity: 0.9999,
gate_count: 2,
},
);
self.translation_rules.insert(
(backend, "S".to_string()),
TranslationRule {
gate_name: "S".to_string(),
method: TranslationMethod::Direct("rz".to_string()),
fidelity: 1.0,
gate_count: 1,
},
);
self.translation_rules.insert(
(backend, "T".to_string()),
TranslationRule {
gate_name: "T".to_string(),
method: TranslationMethod::Direct("rz".to_string()),
fidelity: 1.0,
gate_count: 1,
},
);
self.translation_rules.insert(
(backend, "RX".to_string()),
TranslationRule {
gate_name: "RX".to_string(),
method: TranslationMethod::ParameterizedDecomposition(Box::new(|params| {
let theta = params[0];
vec![
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "sx".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![],
global_phase: None,
},
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![theta - PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "sx".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![],
global_phase: None,
},
DecomposedGate {
native_gate: "rz".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![-PI / 2.0],
global_phase: None,
},
]
})),
fidelity: 0.9998,
gate_count: 5,
},
);
self.translation_rules.insert(
(backend, "CNOT".to_string()),
TranslationRule {
gate_name: "CNOT".to_string(),
method: TranslationMethod::Direct("cx".to_string()),
fidelity: 1.0,
gate_count: 1,
},
);
}
fn init_google_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::GoogleSycamore,
single_qubit_gates: vec![
"ph".to_string(), "x_pow".to_string(), "y_pow".to_string(), "z_pow".to_string(), ],
two_qubit_gates: vec![
"syc".to_string(), "sqrt_iswap".to_string(),
],
multi_qubit_gates: vec![],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None,
timing_constraints: None,
},
};
self.native_gates
.insert(HardwareBackend::GoogleSycamore, gate_set);
self.add_google_translation_rules();
}
fn add_google_translation_rules(&mut self) {
let backend = HardwareBackend::GoogleSycamore;
self.translation_rules.insert(
(backend, "X".to_string()),
TranslationRule {
gate_name: "X".to_string(),
method: TranslationMethod::FixedDecomposition(vec![DecomposedGate {
native_gate: "x_pow".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![1.0],
global_phase: None,
}]),
fidelity: 1.0,
gate_count: 1,
},
);
self.translation_rules.insert(
(backend, "CNOT".to_string()),
TranslationRule {
gate_name: "CNOT".to_string(),
method: TranslationMethod::FixedDecomposition(vec![
DecomposedGate {
native_gate: "syc".to_string(),
qubits: vec![QubitId(0), QubitId(1)],
parameters: vec![],
global_phase: None,
},
]),
fidelity: 0.998,
gate_count: 3,
},
);
}
fn init_ionq_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::IonQ,
single_qubit_gates: vec!["rx".to_string(), "ry".to_string(), "rz".to_string()],
two_qubit_gates: vec![
"xx".to_string(), ],
multi_qubit_gates: vec![],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None, timing_constraints: None,
},
};
self.native_gates.insert(HardwareBackend::IonQ, gate_set);
self.add_ionq_translation_rules();
}
fn add_ionq_translation_rules(&mut self) {
let backend = HardwareBackend::IonQ;
self.translation_rules.insert(
(backend, "CNOT".to_string()),
TranslationRule {
gate_name: "CNOT".to_string(),
method: TranslationMethod::FixedDecomposition(vec![
DecomposedGate {
native_gate: "ry".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "xx".to_string(),
qubits: vec![QubitId(0), QubitId(1)],
parameters: vec![PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "rx".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![-PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "rx".to_string(),
qubits: vec![QubitId(1)],
parameters: vec![-PI / 2.0],
global_phase: None,
},
DecomposedGate {
native_gate: "ry".to_string(),
qubits: vec![QubitId(0)],
parameters: vec![-PI / 2.0],
global_phase: None,
},
]),
fidelity: 0.999,
gate_count: 5,
},
);
}
fn init_rigetti_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::Rigetti,
single_qubit_gates: vec!["rx".to_string(), "rz".to_string()],
two_qubit_gates: vec![
"cz".to_string(),
"xy".to_string(), ],
multi_qubit_gates: vec![],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None,
timing_constraints: None,
},
};
self.native_gates.insert(HardwareBackend::Rigetti, gate_set);
}
fn init_amazon_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::AmazonBraket,
single_qubit_gates: vec![
"h".to_string(),
"x".to_string(),
"y".to_string(),
"z".to_string(),
"rx".to_string(),
"ry".to_string(),
"rz".to_string(),
],
two_qubit_gates: vec!["cnot".to_string(), "cz".to_string(), "swap".to_string()],
multi_qubit_gates: vec!["ccnot".to_string()],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None,
timing_constraints: None,
},
};
self.native_gates
.insert(HardwareBackend::AmazonBraket, gate_set);
}
fn init_azure_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::AzureQuantum,
single_qubit_gates: vec![
"h".to_string(),
"x".to_string(),
"y".to_string(),
"z".to_string(),
"s".to_string(),
"t".to_string(),
"rx".to_string(),
"ry".to_string(),
"rz".to_string(),
],
two_qubit_gates: vec!["cnot".to_string(), "cz".to_string()],
multi_qubit_gates: vec![],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::X, RotationAxis::Y, RotationAxis::Z],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None,
timing_constraints: None,
},
};
self.native_gates
.insert(HardwareBackend::AzureQuantum, gate_set);
}
fn init_honeywell_gates(&mut self) {
let gate_set = NativeGateSet {
backend: HardwareBackend::Honeywell,
single_qubit_gates: vec![
"u1".to_string(), "u2".to_string(), "u3".to_string(), ],
two_qubit_gates: vec![
"zz".to_string(), ],
multi_qubit_gates: vec![],
arbitrary_single_qubit: true,
rotation_axes: vec![RotationAxis::Custom(1.0, 0.0, 0.0)],
constraints: BackendConstraints {
max_depth: None,
discrete_angles: None,
virtual_z: false,
coupling_map: None, timing_constraints: None,
},
};
self.native_gates
.insert(HardwareBackend::Honeywell, gate_set);
}
pub fn get_native_gates(&self, backend: HardwareBackend) -> Option<&NativeGateSet> {
self.native_gates.get(&backend)
}
pub fn is_native_gate(&self, backend: HardwareBackend, gate_name: &str) -> bool {
self.native_gates.get(&backend).map_or(false, |gate_set| {
gate_set.single_qubit_gates.contains(&gate_name.to_string())
|| gate_set.two_qubit_gates.contains(&gate_name.to_string())
|| gate_set.multi_qubit_gates.contains(&gate_name.to_string())
})
}
pub fn translate_gate(
&mut self,
gate: &dyn GateOp,
backend: HardwareBackend,
) -> QuantRS2Result<Vec<DecomposedGate>> {
let gate_name = gate.name();
if self.is_native_gate(backend, gate_name) {
return Ok(vec![DecomposedGate {
native_gate: gate_name.to_string(),
qubits: gate.qubits(),
parameters: self.extract_parameters(gate)?,
global_phase: None,
}]);
}
let cache_key = format!("{gate_name}_{backend:?}");
if let Some(cached) = self.decomposition_cache.get(&cache_key) {
return Ok(self.remap_qubits(cached.clone(), &gate.qubits()));
}
if let Some(rule) = self
.translation_rules
.get(&(backend, gate_name.to_string()))
{
let decomposition = match &rule.method {
TranslationMethod::Direct(native_name) => {
vec![DecomposedGate {
native_gate: native_name.clone(),
qubits: gate.qubits(),
parameters: self.extract_parameters(gate)?,
global_phase: None,
}]
}
TranslationMethod::FixedDecomposition(gates) => {
self.remap_qubits(gates.clone(), &gate.qubits())
}
TranslationMethod::ParameterizedDecomposition(func) => {
let params = self.extract_parameters(gate)?;
let gates = func(params);
self.remap_qubits(gates, &gate.qubits())
}
TranslationMethod::Synthesis(method) => {
self.synthesize_gate(gate, *method, backend)?
}
TranslationMethod::Custom(func) => func(gate)?,
};
self.decomposition_cache
.insert(cache_key, decomposition.clone());
return Ok(decomposition);
}
match gate.num_qubits() {
1 => self.synthesize_gate(gate, SynthesisMethod::SingleQubitZYZ, backend),
2 => self.synthesize_gate(gate, SynthesisMethod::KAKDecomposition, backend),
_ => Err(QuantRS2Error::InvalidInput(format!(
"No translation available for {}-qubit gate {}",
gate.num_qubits(),
gate_name
))),
}
}
pub fn translate_circuit<const N: usize>(
&mut self,
circuit: &Circuit<N>,
backend: HardwareBackend,
) -> QuantRS2Result<Circuit<N>> {
let mut translated = Circuit::<N>::new();
for gate in circuit.gates() {
let decomposed = self.translate_gate(gate.as_ref(), backend)?;
for dec_gate in decomposed {
self.add_decomposed_gate(&mut translated, &dec_gate)?;
}
}
Ok(translated)
}
fn extract_parameters(&self, gate: &dyn GateOp) -> QuantRS2Result<Vec<f64>> {
Ok(vec![])
}
fn remap_qubits(
&self,
mut gates: Vec<DecomposedGate>,
actual_qubits: &[QubitId],
) -> Vec<DecomposedGate> {
for gate in &mut gates {
for qubit in &mut gate.qubits {
if qubit.id() < actual_qubits.len() as u32 {
*qubit = actual_qubits[qubit.id() as usize];
}
}
}
gates
}
fn synthesize_gate(
&self,
gate: &dyn GateOp,
method: SynthesisMethod,
backend: HardwareBackend,
) -> QuantRS2Result<Vec<DecomposedGate>> {
match method {
SynthesisMethod::SingleQubitZYZ => {
if gate.num_qubits() != 1 {
return Err(QuantRS2Error::InvalidInput(
"ZYZ synthesis only works for single-qubit gates".into(),
));
}
let matrix_vec = gate.matrix()?;
let matrix = Array2::from_shape_vec((2, 2), matrix_vec)
.map_err(|_| QuantRS2Error::InvalidInput("Invalid matrix shape".into()))?;
let decomp = decompose_single_qubit_zyz(&matrix.view())?;
Ok(vec![
DecomposedGate {
native_gate: "rz".to_string(),
qubits: gate.qubits(),
parameters: vec![decomp.theta1],
global_phase: None,
},
DecomposedGate {
native_gate: "ry".to_string(),
qubits: gate.qubits(),
parameters: vec![decomp.phi],
global_phase: None,
},
DecomposedGate {
native_gate: "rz".to_string(),
qubits: gate.qubits(),
parameters: vec![decomp.theta2],
global_phase: Some(decomp.global_phase),
},
])
}
SynthesisMethod::KAKDecomposition => {
if gate.num_qubits() != 2 {
return Err(QuantRS2Error::InvalidInput(
"KAK decomposition only works for two-qubit gates".into(),
));
}
Ok(vec![])
}
_ => Err(QuantRS2Error::InvalidInput(format!(
"Synthesis method {method:?} not yet implemented"
))),
}
}
fn add_decomposed_gate<const N: usize>(
&self,
circuit: &mut Circuit<N>,
gate: &DecomposedGate,
) -> QuantRS2Result<()> {
match gate.native_gate.as_str() {
"id" => {} "x" => {
let _ = circuit.x(gate.qubits[0]);
}
"sx" => {
let _ = circuit.sx(gate.qubits[0]);
}
"rz" => {
let _ = circuit.rz(gate.qubits[0], gate.parameters[0]);
}
"cx" => {
let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
}
"rx" => {
let _ = circuit.rx(gate.qubits[0], gate.parameters[0]);
}
"ry" => {
let _ = circuit.ry(gate.qubits[0], gate.parameters[0]);
}
"xx" => {
let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
}
"h" => {
let _ = circuit.h(gate.qubits[0]);
}
"y" => {
let _ = circuit.y(gate.qubits[0]);
}
"z" => {
let _ = circuit.z(gate.qubits[0]);
}
"s" => {
let _ = circuit.s(gate.qubits[0]);
}
"t" => {
let _ = circuit.t(gate.qubits[0]);
}
"cnot" => {
let _ = circuit.cnot(gate.qubits[0], gate.qubits[1]);
}
"cz" => {
let _ = circuit.cz(gate.qubits[0], gate.qubits[1]);
}
"swap" => {
let _ = circuit.swap(gate.qubits[0], gate.qubits[1]);
}
"ccnot" => {
let _ = circuit.toffoli(gate.qubits[0], gate.qubits[1], gate.qubits[2]);
}
_ => {
return Err(QuantRS2Error::InvalidInput(format!(
"Unknown native gate: {}",
gate.native_gate
)));
}
}
Ok(())
}
}
pub struct TranslationOptimizer {
translator: GateTranslator,
strategy: OptimizationStrategy,
}
#[derive(Debug, Clone, Copy)]
pub enum OptimizationStrategy {
MinimizeGateCount,
MinimizeError,
MinimizeDepth,
Balanced { weight: f64 },
}
impl TranslationOptimizer {
pub fn new(strategy: OptimizationStrategy) -> Self {
Self {
translator: GateTranslator::new(),
strategy,
}
}
pub fn optimize_translation(
&mut self,
gate: &dyn GateOp,
backend: HardwareBackend,
) -> QuantRS2Result<Vec<DecomposedGate>> {
let candidates = vec![
self.translator.translate_gate(gate, backend)?,
];
let best = match self.strategy {
OptimizationStrategy::MinimizeGateCount => candidates
.into_iter()
.min_by_key(|c| c.len())
.unwrap_or_default(),
OptimizationStrategy::MinimizeError => {
candidates.into_iter().next().unwrap_or_default()
}
OptimizationStrategy::MinimizeDepth => {
candidates.into_iter().next().unwrap_or_default()
}
OptimizationStrategy::Balanced { weight } => {
candidates.into_iter().next().unwrap_or_default()
}
};
Ok(best)
}
}
pub fn validate_native_circuit<const N: usize>(
circuit: &Circuit<N>,
backend: HardwareBackend,
) -> QuantRS2Result<bool> {
let translator = GateTranslator::new();
for gate in circuit.gates() {
if !translator.is_native_gate(backend, gate.name()) {
return Ok(false);
}
}
Ok(true)
}
pub struct TranslationStats {
pub original_gates: usize,
pub native_gates: usize,
pub gate_counts: HashMap<String, usize>,
pub fidelity_loss: f64,
pub depth_ratio: f64,
}
impl TranslationStats {
pub fn calculate<const N: usize>(
original: &Circuit<N>,
translated: &Circuit<N>,
backend: HardwareBackend,
) -> Self {
let mut gate_counts = HashMap::new();
for gate in translated.gates() {
*gate_counts.entry(gate.name().to_string()).or_insert(0) += 1;
}
Self {
original_gates: original.gates().len(),
native_gates: translated.gates().len(),
gate_counts,
fidelity_loss: 0.0, depth_ratio: 1.0, }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gate_translator_creation() {
let translator = GateTranslator::new();
assert!(translator
.get_native_gates(HardwareBackend::IBMQuantum)
.is_some());
assert!(translator
.get_native_gates(HardwareBackend::GoogleSycamore)
.is_some());
assert!(translator.get_native_gates(HardwareBackend::IonQ).is_some());
}
#[test]
fn test_native_gate_check() {
let translator = GateTranslator::new();
assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "rz"));
assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "sx"));
assert!(translator.is_native_gate(HardwareBackend::IBMQuantum, "cx"));
assert!(!translator.is_native_gate(HardwareBackend::IBMQuantum, "h"));
assert!(translator.is_native_gate(HardwareBackend::IonQ, "rx"));
assert!(translator.is_native_gate(HardwareBackend::IonQ, "xx"));
assert!(!translator.is_native_gate(HardwareBackend::IonQ, "cnot"));
}
#[test]
fn test_hadamard_translation_ibm() {
let mut translator = GateTranslator::new();
let h_gate = Hadamard { target: QubitId(0) };
let decomposed = translator
.translate_gate(&h_gate, HardwareBackend::IBMQuantum)
.expect("Hadamard gate translation should succeed");
assert_eq!(decomposed.len(), 3);
assert_eq!(decomposed[0].native_gate, "rz");
assert_eq!(decomposed[1].native_gate, "sx");
assert_eq!(decomposed[2].native_gate, "rz");
}
#[test]
fn test_circuit_translation() {
let mut translator = GateTranslator::new();
let mut circuit = Circuit::<2>::new();
let _ = circuit.h(QubitId(0));
let _ = circuit.cnot(QubitId(0), QubitId(1));
let translated = translator
.translate_circuit(&circuit, HardwareBackend::IBMQuantum)
.expect("Circuit translation should succeed");
assert!(translated.gates().len() >= 4);
}
}