use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Provider {
IbmEagle,
IbmKyoto,
Rigetti,
IonQ,
Quantinuum,
Simulator,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum QuantumGate {
H, X, Y, Z, S, Sdg, T, Tdg, SX,
RX, RY, RZ, P, U1, U2, U3,
Rx90, Rx180,
CX, CZ, CY, SWAP, ISWAP, ECR,
RZX, XX, YY, ZZ,
CPhase, XY,
CP,
GPI, GPI2, MS,
CCX, CSWAP,
MCX, MCZ,
GlobalPhase,
Delay,
VirtualRZ,
IfElse,
Measure, MeasureAll, Reset, Barrier, Init,
ParamGate,
}
impl QuantumGate {
pub fn op_name(&self) -> &'static str {
match self {
Self::H => "quantum.h", Self::X => "quantum.x",
Self::Y => "quantum.y", Self::Z => "quantum.z",
Self::S => "quantum.s", Self::Sdg => "quantum.sdg",
Self::T => "quantum.t", Self::Tdg => "quantum.tdg",
Self::SX => "quantum.sx",
Self::RX => "quantum.rx", Self::RY => "quantum.ry",
Self::RZ => "quantum.rz", Self::P => "quantum.p",
Self::U1 => "quantum.u1", Self::U2 => "quantum.u2",
Self::U3 => "quantum.u3",
Self::Rx90 => "quantum.rx90", Self::Rx180 => "quantum.rx180",
Self::CX => "quantum.cx", Self::CZ => "quantum.cz",
Self::CY => "quantum.cy", Self::SWAP => "quantum.swap",
Self::ISWAP => "quantum.iswap", Self::ECR => "quantum.ecr",
Self::RZX => "quantum.rzx",
Self::XX => "quantum.xx", Self::YY => "quantum.yy",
Self::ZZ => "quantum.zz",
Self::CPhase => "quantum.cphase", Self::XY => "quantum.xy",
Self::CP => "quantum.cp",
Self::GPI => "quantum.gpi", Self::GPI2 => "quantum.gpi2",
Self::MS => "quantum.ms",
Self::CCX => "quantum.ccx", Self::CSWAP => "quantum.cswap",
Self::MCX => "quantum.mcx", Self::MCZ => "quantum.mcz",
Self::GlobalPhase => "quantum.global_phase",
Self::Delay => "quantum.delay",
Self::VirtualRZ => "quantum.virtual_rz",
Self::IfElse => "quantum.if_else",
Self::Measure => "quantum.measure",
Self::MeasureAll => "quantum.measure_all",
Self::Reset => "quantum.reset",
Self::Barrier => "quantum.barrier",
Self::Init => "quantum.init",
Self::ParamGate => "quantum.param_gate",
}
}
pub fn from_name(name: &str) -> Option<Self> {
match name {
"quantum.h" => Some(Self::H), "quantum.x" => Some(Self::X),
"quantum.y" => Some(Self::Y), "quantum.z" => Some(Self::Z),
"quantum.s" => Some(Self::S), "quantum.sdg" => Some(Self::Sdg),
"quantum.t" => Some(Self::T), "quantum.tdg" => Some(Self::Tdg),
"quantum.sx" => Some(Self::SX),
"quantum.rx" => Some(Self::RX), "quantum.ry" => Some(Self::RY),
"quantum.rz" => Some(Self::RZ), "quantum.p" => Some(Self::P),
"quantum.u1" => Some(Self::U1), "quantum.u2" => Some(Self::U2),
"quantum.u3" => Some(Self::U3),
"quantum.rx90" => Some(Self::Rx90), "quantum.rx180" => Some(Self::Rx180),
"quantum.cx" => Some(Self::CX), "quantum.cz" => Some(Self::CZ),
"quantum.cy" => Some(Self::CY), "quantum.swap" => Some(Self::SWAP),
"quantum.iswap" => Some(Self::ISWAP), "quantum.ecr" => Some(Self::ECR),
"quantum.rzx" => Some(Self::RZX),
"quantum.xx" => Some(Self::XX), "quantum.yy" => Some(Self::YY),
"quantum.zz" => Some(Self::ZZ),
"quantum.cphase" => Some(Self::CPhase), "quantum.xy" => Some(Self::XY),
"quantum.cp" => Some(Self::CP),
"quantum.gpi" => Some(Self::GPI), "quantum.gpi2" => Some(Self::GPI2),
"quantum.ms" => Some(Self::MS),
"quantum.ccx" => Some(Self::CCX), "quantum.cswap" => Some(Self::CSWAP),
"quantum.mcx" => Some(Self::MCX), "quantum.mcz" => Some(Self::MCZ),
"quantum.global_phase" => Some(Self::GlobalPhase),
"quantum.delay" => Some(Self::Delay),
"quantum.virtual_rz" => Some(Self::VirtualRZ),
"quantum.if_else" => Some(Self::IfElse),
"quantum.measure" => Some(Self::Measure),
"quantum.measure_all" => Some(Self::MeasureAll),
"quantum.reset" => Some(Self::Reset),
"quantum.barrier" => Some(Self::Barrier),
"quantum.init" => Some(Self::Init),
"quantum.param_gate" => Some(Self::ParamGate),
_ => None,
}
}
pub fn num_qubits(&self) -> usize {
match self {
Self::H | Self::X | Self::Y | Self::Z | Self::S | Self::Sdg |
Self::T | Self::Tdg | Self::SX | Self::RX | Self::RY | Self::RZ |
Self::P | Self::U1 | Self::U2 | Self::U3 |
Self::Rx90 | Self::Rx180 |
Self::GPI | Self::GPI2 | Self::VirtualRZ |
Self::Measure | Self::Reset | Self::Init => 1,
Self::CX | Self::CZ | Self::CY | Self::SWAP | Self::ISWAP |
Self::ECR | Self::RZX | Self::XX | Self::YY | Self::ZZ |
Self::CPhase | Self::XY | Self::CP | Self::MS => 2,
Self::CCX | Self::CSWAP => 3,
Self::MCX | Self::MCZ => 0,
Self::GlobalPhase | Self::Delay | Self::IfElse |
Self::MeasureAll | Self::Barrier | Self::ParamGate => 0,
}
}
pub fn is_parametric(&self) -> bool {
matches!(self,
Self::RX | Self::RY | Self::RZ | Self::P |
Self::U1 | Self::U2 | Self::U3 | Self::RZX |
Self::XX | Self::YY | Self::ZZ |
Self::CPhase | Self::XY | Self::CP |
Self::GPI | Self::GPI2 | Self::MS |
Self::GlobalPhase | Self::VirtualRZ |
Self::ParamGate
)
}
pub fn is_self_inverse(&self) -> bool {
matches!(self,
Self::H | Self::X | Self::Y | Self::Z |
Self::CX | Self::CZ | Self::SWAP |
Self::Rx180
)
}
pub fn is_clifford(&self) -> bool {
matches!(self,
Self::H | Self::X | Self::Y | Self::Z | Self::S | Self::Sdg |
Self::CX | Self::CZ | Self::SWAP | Self::ISWAP
)
}
pub fn native_basis(provider: Provider) -> &'static [QuantumGate] {
match provider {
Provider::IbmEagle | Provider::IbmKyoto => &[
Self::RZ, Self::SX, Self::X, Self::CX, Self::ECR,
],
Provider::Rigetti => &[
Self::RZ, Self::RX, Self::CZ, Self::CPhase, Self::XY,
],
Provider::IonQ => &[
Self::GPI, Self::GPI2, Self::MS,
],
Provider::Quantinuum => &[
Self::RZ, Self::RX, Self::RY, Self::ZZ,
],
Provider::Simulator => &[
Self::H, Self::X, Self::Y, Self::Z, Self::S, Self::T,
Self::RX, Self::RY, Self::RZ, Self::CX, Self::CZ,
Self::CCX, Self::SWAP,
],
}
}
#[inline]
pub fn is_measurement(&self) -> bool {
matches!(self, Self::Measure | Self::MeasureAll)
}
#[inline]
pub fn is_entangling(&self) -> bool {
matches!(self,
Self::CX | Self::CZ | Self::CY | Self::SWAP | Self::ISWAP |
Self::ECR | Self::RZX | Self::XX | Self::YY | Self::ZZ |
Self::CPhase | Self::XY | Self::CP | Self::MS |
Self::CCX | Self::CSWAP | Self::MCX | Self::MCZ
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gate_roundtrip() {
for gate in &[QuantumGate::H, QuantumGate::CX, QuantumGate::RZ, QuantumGate::CCX] {
assert_eq!(QuantumGate::from_name(gate.op_name()).as_ref(), Some(gate));
}
}
#[test]
fn test_qubit_counts() {
assert_eq!(QuantumGate::H.num_qubits(), 1);
assert_eq!(QuantumGate::CX.num_qubits(), 2);
assert_eq!(QuantumGate::CCX.num_qubits(), 3);
}
}