diff --git a/crates/circuit/src/bits.rs b/crates/circuit/src/bits.rs index 39bd3a91b32b..2fadd819f08c 100644 --- a/crates/circuit/src/bits.rs +++ b/crates/circuit/src/bits.rs @@ -10,20 +10,45 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -use std::ops::{Deref, DerefMut}; +use std::{ + fmt::Display, + ops::{Deref, DerefMut}, +}; -use pyo3::prelude::*; +use exceptions::CircuitError; +use pyo3::{intern, prelude::*, types::PyDict}; +pub(crate) mod exceptions { + use pyo3::import_exception_bound; + import_exception_bound! {qiskit.circuit.exceptions, CircuitError} +} +pub type RegisterKey = (String, u32); /// Opaque struct representing a bit instance which can be stored in any circuit or register. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Bit { - // This is an opaque type, so it doesn't store anything but an alias. +#[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."), + } + } + + pub fn index(&self) -> Option { + self.1 + } + + pub fn register_key(&self) -> Option<&RegisterKey> { + self.0.as_ref() + } } macro_rules! create_bit { ($name:ident) => { #[pyclass] - #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct $name(Bit); impl Deref for $name { @@ -39,8 +64,95 @@ macro_rules! create_bit { &mut self.0 } } + + 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,) + } + } }; } -create_bit!{Qubit} -create_bit!{Clbit} \ No newline at end of file +#[pyclass(name = "Bit")] +pub struct PyBit { + inner_bit: Bit, + 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); + match (register, index) { + (None, None) => Ok(Self { + inner_bit, + 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" + ))); + } + let index: Option = index.map(|index| { + if index.is_negative() { + size - index as u32 + } else { + index as u32 + } + }); + Ok(Self { + inner_bit: Bit(Some((name, size)), index), + register: Some(reg), + }) + } + _ => Err(CircuitError::new_err( + "You should provide both an index and a register, not just one of them.", + )), + } + } + + #[getter] + fn get_index(&self) -> Option { + self.inner_bit.index() + } + + 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); + } + + self.inner_bit == other.inner_bit + } + + fn __copy__(slf: Bound) -> Bound { + slf + } + + fn __deepcopy__<'py>(slf: Bound<'py, Self>, memo: Bound<'py, PyDict>) -> PyResult> { + let borrowed: PyRef = slf.borrow(); + if borrowed.get_index().is_none() && borrowed.register.is_none() { + return Ok(slf.into_any()) + } + + slf.get_type().call0() + } +} + +create_bit! {Qubit} +create_bit! {Clbit} diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index a65cd24612d2..bed49558cdd6 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -10,8 +10,8 @@ // copyright notice, and modified files need to carry a notice indicating // that they have been altered from the originals. -pub mod bits; pub mod bit_data; +pub mod bits; pub mod circuit_data; pub mod circuit_instruction; pub mod converters;