use crate::device::{LogicalQubit, PhysicalQubit};
use std::fmt;
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum DeviceError {
EmptyDevice,
InvalidOnlineQubit(PhysicalQubit),
QubitNotInDevice(PhysicalQubit),
QubitNotInTopology(PhysicalQubit),
EdgeNotInTopology(PhysicalQubit, PhysicalQubit),
InvalidTopology(TopologyError),
NonStandardNativeInstruction {
instruction: String,
},
InvalidNativeInstructionArity {
instruction: String,
expected: std::ops::RangeInclusive<usize>,
actual: usize,
},
InvalidNativeInstructionErrorRate {
instruction: String,
value: String,
},
InvalidNativeInstructionDuration {
instruction: String,
value: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeviceValidationError {
UnusablePhysicalQubit {
device: String,
qubit: PhysicalQubit,
},
MissingDirectedCoupling {
device: String,
instruction: String,
control: PhysicalQubit,
target: PhysicalQubit,
},
UnsupportedInstruction {
device: String,
instruction: String,
qargs: Vec<PhysicalQubit>,
},
UndecomposedInstruction {
device: String,
instruction: String,
qargs: Vec<PhysicalQubit>,
},
}
impl fmt::Display for DeviceValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnusablePhysicalQubit { device, qubit } => write!(
f,
"device '{device}' cannot execute an operation on unusable physical qubit {qubit}"
),
Self::UnsupportedInstruction {
device,
instruction,
qargs,
} => {
let qargs = qargs
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"device '{device}' does not support instruction {instruction} on ordered physical qargs [{qargs}]"
)
}
Self::MissingDirectedCoupling {
device,
instruction,
control,
target,
} => write!(
f,
"device '{device}' has no directed coupling {control} -> {target} required by instruction {instruction}"
),
Self::UndecomposedInstruction {
device,
instruction,
qargs,
} => {
let qargs = qargs
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"device '{device}' cannot validate undecomposed instruction {instruction} on ordered physical qargs [{qargs}]"
)
}
}
}
}
impl std::error::Error for DeviceValidationError {}
impl fmt::Display for DeviceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EmptyDevice => {
write!(f, "Device must contain at least one physical qubit")
}
Self::InvalidOnlineQubit(q) => {
write!(
f,
"Specified online qubit {} does not exist in the device topology",
q
)
}
Self::QubitNotInDevice(q) => {
write!(f, "Qubit {} is not registered with the device", q)
}
Self::QubitNotInTopology(q) => {
write!(f, "Qubit {} is not in the device topology", q)
}
Self::EdgeNotInTopology(control, target) => {
write!(
f,
"Edge ({}, {}) is not in the device topology",
control, target
)
}
Self::InvalidTopology(error) => {
write!(f, "Invalid device topology: {error}")
}
Self::NonStandardNativeInstruction { instruction } => write!(
f,
"instruction {instruction} cannot be stored as a native capability: native instructions must be standard gates"
),
Self::InvalidNativeInstructionArity {
instruction,
expected,
actual,
} => {
let expected = if expected.start() == expected.end() {
expected.start().to_string()
} else {
format!("{}..={}", expected.start(), expected.end())
};
write!(
f,
"instruction {instruction} cannot be stored as a native capability: expected {expected} qubits, got {actual}"
)
}
Self::InvalidNativeInstructionErrorRate { instruction, value } => write!(
f,
"instruction {instruction} has invalid native error rate {value}: expected a finite value in [0, 1]"
),
Self::InvalidNativeInstructionDuration { instruction, value } => write!(
f,
"instruction {instruction} has invalid native duration {value}: expected a finite non-negative value"
),
}
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum LayoutError {
TooManyLogicalQubits { logical: usize, physical: usize },
DuplicateLogicalQubit(LogicalQubit),
DuplicatePhysicalQubit(PhysicalQubit),
InvalidLogicalQubit(LogicalQubit),
InvalidPhysicalQubit(PhysicalQubit),
LogicalQubitAlreadyBound(LogicalQubit),
PhysicalQubitAlreadyOccupied(PhysicalQubit),
LogicalQubitNotBound(LogicalQubit),
}
impl fmt::Display for LayoutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TooManyLogicalQubits { logical, physical } => {
write!(
f,
"Logical qubits ({}) exceed physical qubits ({})",
logical, physical
)
}
Self::DuplicateLogicalQubit(q) => {
write!(f, "Logical qubit {} appears more than once", q)
}
Self::DuplicatePhysicalQubit(q) => {
write!(f, "Physical qubit {} appears more than once", q)
}
Self::InvalidLogicalQubit(q) => {
write!(f, "Logical qubit {} not in logical qubit list", q)
}
Self::InvalidPhysicalQubit(q) => {
write!(f, "Physical qubit {} not in physical qubit list", q)
}
Self::LogicalQubitAlreadyBound(q) => {
write!(f, "Logical qubit {} is already bound", q)
}
Self::PhysicalQubitAlreadyOccupied(q) => {
write!(f, "Physical qubit {} is already occupied", q)
}
Self::LogicalQubitNotBound(q) => write!(f, "Logical qubit {} is not bound", q),
}
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum TopologyError {
QubitNotFound(PhysicalQubit),
CouplingNotFound {
control: PhysicalQubit,
target: PhysicalQubit,
},
QubitAlreadyExists(PhysicalQubit),
CouplingAlreadyExists {
control: PhysicalQubit,
target: PhysicalQubit,
},
SelfCoupling { qubit: PhysicalQubit },
DuplicateQubitRemoval(PhysicalQubit),
DuplicateCouplingRemoval {
control: PhysicalQubit,
target: PhysicalQubit,
},
}
impl fmt::Display for TopologyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TopologyError::QubitNotFound(q) => write!(f, "Qubit {:?} not found", q),
TopologyError::CouplingNotFound { control, target } => {
write!(f, "Coupling ({:?} -> {:?}) not found", control, target)
}
TopologyError::QubitAlreadyExists(q) => write!(f, "Qubit {:?} already exists", q),
TopologyError::CouplingAlreadyExists { control, target } => {
write!(f, "Coupling ({:?} -> {:?}) already exists", control, target)
}
TopologyError::SelfCoupling { qubit } => {
write!(
f,
"Self coupling ({:?} -> {:?}) is not allowed",
qubit, qubit
)
}
TopologyError::DuplicateQubitRemoval(q) => {
write!(f, "Qubit {:?} appears more than once in removal request", q)
}
TopologyError::DuplicateCouplingRemoval { control, target } => {
write!(
f,
"Coupling ({:?} -> {:?}) appears more than once in removal request",
control, target
)
}
}
}
}