use serde::{Deserialize, Serialize};
#[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);
}
}