use std::cmp::Ordering;
use std::fmt;
use qudit_core::CompactStorage;
use serde::{Deserialize, Serialize};
#[derive(Hash, PartialEq, Eq, Clone, Debug, Copy, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Wire(isize);
pub const MAX_QUANTUM_INDEX: usize = (isize::MAX - 1) as usize;
pub const MAX_CLASSICAL_INDEX: usize = isize::MIN.unsigned_abs() - 2;
impl Wire {
#[inline]
pub fn quantum(idx: usize) -> Self {
if idx > MAX_QUANTUM_INDEX {
panic!("Quantum wire overflow.");
}
Wire((idx + 1) as isize)
}
#[inline]
pub fn classical(idx: usize) -> Self {
if idx > MAX_CLASSICAL_INDEX {
panic!("Classical wire overflow.");
}
Wire(-((idx + 1) as isize))
}
#[inline(always)]
pub const fn from_raw(val: isize) -> Self {
Wire(val)
}
#[inline(always)]
pub const fn is_quantum(self) -> bool {
self.0 > 0
}
#[inline(always)]
pub const fn is_classical(self) -> bool {
self.0 < 0
}
#[inline(always)]
pub const fn is_null(self) -> bool {
self.0 == 0
}
#[inline(always)]
pub const fn is_valid(self) -> bool {
!self.is_null()
}
#[inline]
pub const fn index(self) -> usize {
self.0.unsigned_abs().wrapping_sub(1)
}
#[inline(always)]
pub const fn raw_value(self) -> isize {
self.0
}
}
impl PartialOrd for Wire {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Wire {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match (self.is_null(), other.is_null()) {
(true, true) => Ordering::Equal,
(true, false) => Ordering::Less, (false, true) => Ordering::Greater, (false, false) => {
match (self.is_quantum(), other.is_quantum()) {
(true, true) => self.index().cmp(&other.index()), (false, false) => self.index().cmp(&other.index()), (true, false) => Ordering::Less, (false, true) => Ordering::Greater, }
}
}
}
}
impl From<i32> for Wire {
#[inline(always)]
fn from(val: i32) -> Self {
Wire::from_raw(val as isize)
}
}
impl From<isize> for Wire {
#[inline(always)]
fn from(val: isize) -> Self {
Wire(val)
}
}
impl fmt::Display for Wire {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_quantum() {
write!(f, "q{}", self.index())
} else if self.is_classical() {
write!(f, "c{}", self.index())
} else {
write!(f, "null")
}
}
}
impl CompactStorage for Wire {
type InlineType = i8;
const CONVERSION_INFALLIBLE: bool = false;
#[inline]
fn to_inline(value: Self) -> Result<Self::InlineType, Self> {
let raw = value.raw_value();
if raw >= i8::MIN as isize && raw <= i8::MAX as isize {
Ok(raw as i8)
} else {
Err(value)
}
}
#[inline(always)]
fn from_inline(value: Self::InlineType) -> Self {
Self::from_raw(value as isize)
}
#[inline(always)]
fn to_inline_unchecked(value: Self) -> Self::InlineType {
value.raw_value() as i8
}
}
#[cfg(feature = "python")]
mod python {
use super::Wire;
use crate::python::PyCircuitRegistrar;
use pyo3::prelude::*;
use pyo3_stub_gen::derive::*;
use pyo3_stub_gen::impl_stub_type;
impl_stub_type!(Wire = PyWire);
#[gen_stub_pyclass]
#[pyclass(
name = "Wire",
module = "openqudit.circuit",
frozen,
hash,
eq,
ord,
from_py_object
)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct PyWire {
inner: Wire,
}
#[gen_stub_pymethods]
#[pymethods]
impl PyWire {
#[staticmethod]
fn quantum(idx: usize) -> PyResult<Self> {
if idx > super::MAX_QUANTUM_INDEX {
return Err(pyo3::exceptions::PyOverflowError::new_err(
"Quantum wire index overflow",
));
}
Ok(PyWire {
inner: Wire::quantum(idx),
})
}
#[staticmethod]
fn classical(idx: usize) -> PyResult<Self> {
if idx > super::MAX_CLASSICAL_INDEX {
return Err(pyo3::exceptions::PyOverflowError::new_err(
"Classical wire index overflow",
));
}
Ok(PyWire {
inner: Wire::classical(idx),
})
}
#[staticmethod]
fn from_raw(val: isize) -> Self {
PyWire {
inner: Wire::from_raw(val),
}
}
#[getter]
fn is_quantum(&self) -> bool {
self.inner.is_quantum()
}
#[getter]
fn is_classical(&self) -> bool {
self.inner.is_classical()
}
#[getter]
fn is_null(&self) -> bool {
self.inner.is_null()
}
#[getter]
fn is_valid(&self) -> bool {
self.inner.is_valid()
}
#[getter]
fn index(&self) -> usize {
self.inner.index()
}
#[getter]
fn raw_value(&self) -> isize {
self.inner.raw_value()
}
fn __str__(&self) -> String {
format!("{}", self.inner)
}
fn __repr__(&self) -> String {
if self.inner.is_quantum() {
format!("Wire.quantum({})", self.inner.index())
} else if self.inner.is_classical() {
format!("Wire.classical({})", self.inner.index())
} else {
format!("Wire.from_raw({})", self.inner.raw_value())
}
}
}
impl From<Wire> for PyWire {
fn from(wire: Wire) -> Self {
PyWire { inner: wire }
}
}
impl From<PyWire> for Wire {
fn from(py_wire: PyWire) -> Self {
py_wire.inner
}
}
impl<'py> IntoPyObject<'py> for Wire {
type Target = <PyWire as IntoPyObject<'py>>::Target;
type Output = <PyWire as IntoPyObject<'py>>::Output;
type Error = <PyWire as IntoPyObject<'py>>::Error;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
PyWire::from(self).into_pyobject(py)
}
}
impl<'a, 'py> FromPyObject<'a, 'py> for Wire {
type Error = PyErr;
fn extract(obj: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let py_wire: PyWire = obj.extract()?;
Ok(py_wire.inner)
}
}
fn register(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
parent_module.add_class::<PyWire>()?;
parent_module.add("MAX_QUANTUM_INDEX", super::MAX_QUANTUM_INDEX)?;
parent_module.add("MAX_CLASSICAL_INDEX", super::MAX_CLASSICAL_INDEX)?;
Ok(())
}
inventory::submit!(PyCircuitRegistrar { func: register });
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quantum_wire_creation() {
let q0 = Wire::quantum(0);
let q1 = Wire::quantum(1);
let q10 = Wire::quantum(10);
assert_eq!(q0.raw_value(), 1);
assert_eq!(q1.raw_value(), 2);
assert_eq!(q10.raw_value(), 11);
}
#[test]
fn test_classical_wire_creation() {
let c0 = Wire::classical(0);
let c1 = Wire::classical(1);
let c10 = Wire::classical(10);
assert_eq!(c0.raw_value(), -1);
assert_eq!(c1.raw_value(), -2);
assert_eq!(c10.raw_value(), -11);
}
#[test]
fn test_wire_creation_from_raw_values() {
let positive = Wire::from_raw(5);
let negative = Wire::from_raw(-3);
let zero = Wire::from_raw(0);
assert_eq!(positive.raw_value(), 5);
assert_eq!(negative.raw_value(), -3);
assert_eq!(zero.raw_value(), 0);
}
#[test]
fn test_wire_creation_from_isize() {
let quantum: Wire = 1.into();
let classical: Wire = (-1).into();
let null: Wire = 0.into();
assert!(quantum.is_quantum());
assert!(classical.is_classical());
assert!(null.is_null());
}
#[test]
fn test_quantum_wire_identification() {
let quantum_wire = Wire::quantum(0);
let classical_wire = Wire::classical(0);
let null_wire = Wire::from_raw(0);
assert!(quantum_wire.is_quantum());
assert!(!classical_wire.is_quantum());
assert!(!null_wire.is_quantum());
}
#[test]
fn test_classical_wire_identification() {
let quantum_wire = Wire::quantum(0);
let classical_wire = Wire::classical(0);
let null_wire = Wire::from_raw(0);
assert!(!quantum_wire.is_classical());
assert!(classical_wire.is_classical());
assert!(!null_wire.is_classical());
}
#[test]
fn test_null_wire_identification() {
let quantum_wire = Wire::quantum(0);
let classical_wire = Wire::classical(0);
let null_wire = Wire::from_raw(0);
assert!(!quantum_wire.is_null());
assert!(!classical_wire.is_null());
assert!(null_wire.is_null());
}
#[test]
fn test_valid_wire_identification() {
let quantum_wire = Wire::quantum(0);
let classical_wire = Wire::classical(0);
let null_wire = Wire::from_raw(0);
assert!(quantum_wire.is_valid());
assert!(classical_wire.is_valid());
assert!(!null_wire.is_valid());
}
#[test]
fn test_quantum_wire_index_extraction() {
let q0 = Wire::quantum(0);
let q5 = Wire::quantum(5);
let q100 = Wire::quantum(100);
assert_eq!(q0.index(), 0);
assert_eq!(q5.index(), 5);
assert_eq!(q100.index(), 100);
}
#[test]
fn test_classical_wire_index_extraction() {
let c0 = Wire::classical(0);
let c5 = Wire::classical(5);
let c100 = Wire::classical(100);
assert_eq!(c0.index(), 0);
assert_eq!(c5.index(), 5);
assert_eq!(c100.index(), 100);
}
#[test]
fn test_wire_display_formatting() {
let quantum = Wire::quantum(42);
let classical = Wire::classical(7);
let null = Wire::from_raw(0);
assert_eq!(format!("{}", quantum), "q42");
assert_eq!(format!("{}", classical), "c7");
assert_eq!(format!("{}", null), "null");
}
#[test]
fn test_raw_value_retrieval() {
let quantum = Wire::quantum(42);
let classical = Wire::classical(42);
let from_raw = Wire::from_raw(999);
assert_eq!(quantum.raw_value(), 43); assert_eq!(classical.raw_value(), -43); assert_eq!(from_raw.raw_value(), 999);
}
#[test]
fn test_wire_ordering_and_comparison() {
let null = Wire::from_raw(0);
let q0 = Wire::quantum(0);
let q1 = Wire::quantum(1);
let q2 = Wire::quantum(2);
let c0 = Wire::classical(0);
let c1 = Wire::classical(1);
let c2 = Wire::classical(2);
assert!(null < q0);
assert!(q0 < q1);
assert!(q1 < q2);
assert!(q2 < c0);
assert!(c0 < c1);
assert!(c1 < c2);
assert!(q0 < q1);
assert!(q1 < q2);
assert!(c0 < c1);
assert!(c1 < c2);
assert!(null < q0);
assert!(q1 < c0);
}
#[test]
fn test_wire_equality() {
let q0_first = Wire::quantum(0);
let q0_second = Wire::quantum(0);
let q1 = Wire::quantum(1);
assert_eq!(q0_first, q0_second);
assert_ne!(q0_first, q1);
}
#[test]
fn test_wire_cloning_and_copying() {
let original = Wire::quantum(5);
#[allow(clippy::clone_on_copy)]
let cloned = original.clone();
let copied = original;
assert_eq!(original, cloned);
assert_eq!(original, copied);
}
#[test]
#[should_panic(expected = "Quantum wire overflow")]
fn test_quantum_wire_overflow_protection() {
Wire::quantum((isize::MAX) as usize);
}
#[test]
#[should_panic(expected = "Classical wire overflow")]
fn test_classical_wire_overflow_protection() {
Wire::classical(MAX_CLASSICAL_INDEX + 1);
}
#[test]
fn test_maximum_valid_quantum_wire_creation() {
let max_idx = MAX_QUANTUM_INDEX;
let max_wire = Wire::quantum(max_idx);
assert!(max_wire.is_quantum());
assert_eq!(max_wire.index(), max_idx);
assert_eq!(max_wire.raw_value(), isize::MAX);
}
#[test]
fn test_maximum_valid_classical_wire_creation() {
let max_idx = MAX_CLASSICAL_INDEX;
let max_wire = Wire::classical(max_idx);
assert!(max_wire.is_classical());
assert_eq!(max_wire.index(), max_idx);
assert_eq!(max_wire.raw_value(), isize::MIN + 1);
}
}