Skip to content

Commit

Permalink
Initial implementation of Bits from rust
Browse files Browse the repository at this point in the history
  • Loading branch information
raynelfss committed Dec 16, 2024
1 parent 88fac7b commit b320e12
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 98 deletions.
141 changes: 91 additions & 50 deletions crates/circuit/src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,32 @@

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}
}

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<RegisterKey>, Option<u32>);

impl Bit {
pub fn new(&self, register: Option<RegisterKey>, index: Option<u32>) -> 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<u32> {
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);

Expand All @@ -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<u32>,
#[pyo3(get)]
register: Option<PyObject>,
}

#[pymethods]
impl PyBit {
#[new]
#[pyo3(signature = (index=None, register=None))]
pub fn new(py: Python, index: Option<i32>, register: Option<PyObject>) -> PyResult<Self> {
let inner_bit = Bit(None, None);
#[pyo3(signature = (register=None, index=None,))]
pub fn py_new(py: Python, register: Option<PyObject>, index: Option<i32>) -> PyResult<Self> {
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"
Expand All @@ -117,7 +100,8 @@ impl PyBit {
}
});
Ok(Self {
inner_bit: Bit(Some((name, size)), index),
inner_bit: Bit(),
index,
register: Some(reg),
})
}
Expand All @@ -127,32 +111,89 @@ impl PyBit {
}
}

#[getter]
fn get_index(&self) -> Option<u32> {
self.inner_bit.index()
fn __eq__<'py>(slf: Bound<'py, Self>, other: Bound<'py, PyBit>) -> PyResult<bool> {
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<String> {
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<Self>) -> Bound<Self> {
slf
}

fn __deepcopy__<'py>(slf: Bound<'py, Self>, memo: Bound<'py, PyDict>) -> PyResult<Bound<'py, PyAny>> {
#[pyo3(signature = (memo=None))]
fn __deepcopy__<'py>(
slf: Bound<'py, Self>,
memo: Option<Bound<'py, PyDict>>,
) -> PyResult<Bound<'py, PyAny>> {
let py = slf.py();
let borrowed: PyRef<Self> = 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<isize> {
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<PyObject>,
index: Option<i32>,
) -> 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"}
3 changes: 3 additions & 0 deletions crates/circuit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ pub fn circuit(m: &Bound<PyModule>) -> PyResult<()> {
m.add_class::<dag_node::DAGOutNode>()?;
m.add_class::<dag_node::DAGOpNode>()?;
m.add_class::<operations::StandardGate>()?;
m.add_class::<bits::PyBit>()?;
m.add_class::<bits::PyClbit>()?;
m.add_class::<bits::PyQubit>()?;
Ok(())
}

Expand Down
25 changes: 1 addition & 24 deletions qiskit/circuit/classicalregister.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
25 changes: 1 addition & 24 deletions qiskit/circuit/quantumregister.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit b320e12

Please sign in to comment.