diff --git a/crates/circuit/src/bits.rs b/crates/circuit/src/bits.rs index 2fadd819f08c..773fba332340 100644 --- a/crates/circuit/src/bits.rs +++ b/crates/circuit/src/bits.rs @@ -12,11 +12,14 @@ use std::{ fmt::Display, + hash::{DefaultHasher, Hash, Hasher}, ops::{Deref, DerefMut}, }; use exceptions::CircuitError; use pyo3::{intern, prelude::*, types::PyDict}; + +use crate::imports::DEEPCOPY; pub(crate) mod exceptions { use pyo3::import_exception_bound; import_exception_bound! {qiskit.circuit.exceptions, CircuitError} @@ -24,30 +27,17 @@ pub(crate) mod exceptions { pub type RegisterKey = (String, u32); /// Opaque struct representing a bit instance which can be stored in any circuit or register. -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Bit(Option, Option); - -impl Bit { - pub fn new(&self, register: Option, index: Option) -> Self { - match (register, index) { - (None, None) => todo!(), - (Some(_), Some(_)) => todo!(), - _ => panic!("You should provide both an index and a register, not just one of them."), - } - } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Bit(); - pub fn index(&self) -> Option { - self.1 - } - - pub fn register_key(&self) -> Option<&RegisterKey> { - self.0.as_ref() +impl Display for Bit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} at {:p}", stringify!(Bit), self) } } macro_rules! create_bit { ($name:ident) => { - #[pyclass] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct $name(Bit); @@ -67,43 +57,36 @@ macro_rules! create_bit { impl Display for $name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let form = match (&self.0 .0, &self.0 .1) { - (None, None) => format!("{} at {:p}", stringify!($name), self), - _ => format!( - "{}({}Register({}, {}), {})", - stringify!($name), - stringify!($name), - self.register_key().unwrap().0, - self.register_key().unwrap().1, - self.index().unwrap() - ), - }; - write!(f, "{}", form,) + write!(f, "{} at {:p}", stringify!($name), self) } } }; } -#[pyclass(name = "Bit")] +#[pyclass(name = "Bit", subclass)] +#[derive(Debug, Clone)] pub struct PyBit { inner_bit: Bit, + #[pyo3(get)] + index: Option, + #[pyo3(get)] register: Option, } #[pymethods] impl PyBit { #[new] - #[pyo3(signature = (index=None, register=None))] - pub fn new(py: Python, index: Option, register: Option) -> PyResult { - let inner_bit = Bit(None, None); + #[pyo3(signature = (register=None, index=None,))] + pub fn py_new(py: Python, register: Option, index: Option) -> PyResult { + let inner_bit = Bit(); match (register, index) { (None, None) => Ok(Self { inner_bit, + index: None, register: None, }), (Some(reg), Some(idx)) => { let size: u32 = reg.getattr(py, intern!(py, "size"))?.extract(py)?; - let name: String = reg.getattr(py, intern!(py, "name"))?.extract(py)?; if idx >= size.try_into().unwrap() { return Err(CircuitError::new_err(format!( "index must be under the size of the register: {idx} was provided" @@ -117,7 +100,8 @@ impl PyBit { } }); Ok(Self { - inner_bit: Bit(Some((name, size)), index), + inner_bit: Bit(), + index, register: Some(reg), }) } @@ -127,32 +111,89 @@ impl PyBit { } } - #[getter] - fn get_index(&self) -> Option { - self.inner_bit.index() + fn __eq__<'py>(slf: Bound<'py, Self>, other: Bound<'py, PyBit>) -> PyResult { + let bit = slf.borrow(); + let other_borrow = other.borrow(); + if bit.register.is_none() && bit.index.is_none() { + return Ok(std::ptr::eq(&bit.inner_bit, &other_borrow.inner_bit)); + } + + Ok(slf.repr()?.to_string() == other.repr()?.to_string()) } - fn __eq__(&self, other: &PyBit) -> bool { - if self.register.is_none() && self.get_index().is_none() { - return std::ptr::eq(&self.inner_bit, &other.inner_bit); + fn __repr__(slf: Bound<'_, Self>) -> PyResult { + let py = slf.py(); + let bit = slf.borrow(); + match (bit.register.as_ref(), bit.index) { + (Some(reg), Some(idx)) => Ok(format!( + "{}({}, {})", + slf.get_type().name()?, + reg.bind(py).repr()?, + idx + )), + _ => Ok(bit.inner_bit.to_string()), } - - self.inner_bit == other.inner_bit } fn __copy__(slf: Bound) -> Bound { slf } - fn __deepcopy__<'py>(slf: Bound<'py, Self>, memo: Bound<'py, PyDict>) -> PyResult> { + #[pyo3(signature = (memo=None))] + fn __deepcopy__<'py>( + slf: Bound<'py, Self>, + memo: Option>, + ) -> PyResult> { + let py = slf.py(); let borrowed: PyRef = slf.borrow(); - if borrowed.get_index().is_none() && borrowed.register.is_none() { - return Ok(slf.into_any()) + if borrowed.index.is_none() && borrowed.register.is_none() { + return Ok(slf.into_any()); } - slf.get_type().call0() + let copied_reg = DEEPCOPY + .get_bound(py) + .call1((slf.getattr("register")?, memo))?; + println!("{}", copied_reg.repr()?); + slf.get_type().call1((copied_reg, borrowed.index)) + } + + fn __hash__(slf: Bound<'_, Self>, py: Python<'_>) -> PyResult { + let borrowed = slf.borrow(); + if let (Some(reg), Some(idx)) = (borrowed.register.as_ref(), borrowed.index) { + return (reg.bind(py), idx).to_object(py).bind(py).hash(); + } + + let mut hasher = DefaultHasher::new(); + borrowed.inner_bit.hash(&mut hasher); + Ok(hasher.finish() as isize) } } -create_bit! {Qubit} -create_bit! {Clbit} +macro_rules! create_py_bit { + ($name:ident, $pyname:literal) => { + #[pyclass(name=$pyname, extends=PyBit, subclass)] + #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] + pub struct $name; + + #[pymethods] + impl $name { + #[new] + #[pyo3(signature = (register=None, index=None))] + pub fn py_new( + py: Python, + register: Option, + index: Option, + ) -> PyResult<(Self, PyBit)> { + Ok((Self {}, PyBit::py_new(py, register, index)?)) + } + } + }; +} + +// Create rust instances +create_bit! {QubitObject} +create_bit! {ClbitObject} + +// Create python instances +create_py_bit! {PyQubit, "Qubit"} +create_py_bit! {PyClbit, "Clbit"} diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index bed49558cdd6..39d12052c8b9 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -132,6 +132,9 @@ pub fn circuit(m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; Ok(()) } diff --git a/qiskit/circuit/classicalregister.py b/qiskit/circuit/classicalregister.py index 802d8c602e2c..8955aa7f4c4c 100644 --- a/qiskit/circuit/classicalregister.py +++ b/qiskit/circuit/classicalregister.py @@ -21,30 +21,7 @@ from .register import Register from .bit import Bit - - -class Clbit(Bit): - """Implement a classical bit.""" - - __slots__ = () - - def __init__(self, register=None, index=None): - """Creates a classical bit. - - Args: - register (ClassicalRegister): Optional. A classical register containing the bit. - index (int): Optional. The index of the bit in its containing register. - - Raises: - CircuitError: if the provided register is not a valid :class:`ClassicalRegister` - """ - - if register is None or isinstance(register, ClassicalRegister): - super().__init__(register, index) - else: - raise CircuitError( - f"Clbit needs a ClassicalRegister and {type(register).__name__} was provided" - ) +from qiskit._accelerate.circuit import Clbit class ClassicalRegister(Register): diff --git a/qiskit/circuit/quantumregister.py b/qiskit/circuit/quantumregister.py index 97d1392698e3..9b8a1b388cba 100644 --- a/qiskit/circuit/quantumregister.py +++ b/qiskit/circuit/quantumregister.py @@ -21,30 +21,7 @@ from .register import Register from .bit import Bit - - -class Qubit(Bit): - """Implement a quantum bit.""" - - __slots__ = () - - def __init__(self, register=None, index=None): - """Creates a qubit. - - Args: - register (QuantumRegister): Optional. A quantum register containing the bit. - index (int): Optional. The index of the bit in its containing register. - - Raises: - CircuitError: if the provided register is not a valid :class:`QuantumRegister` - """ - - if register is None or isinstance(register, QuantumRegister): - super().__init__(register, index) - else: - raise CircuitError( - f"Qubit needs a QuantumRegister and {type(register).__name__} was provided" - ) +from qiskit._accelerate.circuit import Qubit class QuantumRegister(Register):