Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Use native bits and registers for CircuitData. #13686

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
af13dd2
Initial: Register Infrastructure in Rust
raynelfss Dec 27, 2024
cf673db
Add: `bits` method for register.
raynelfss Dec 30, 2024
00eeb7d
Use interners for registry
raynelfss Dec 31, 2024
bfa7389
Fix: Add functional python `Bits`
raynelfss Jan 2, 2025
db42bab
Initial Python registers
raynelfss Jan 3, 2025
20f0ebf
Finalize Python Registers, prepare for replacements.
raynelfss Jan 3, 2025
66bee69
Fix serialization in registers
raynelfss Jan 4, 2025
3a0c5bb
`BitData` refactor: Store Registers
raynelfss Jan 16, 2025
f8bdfa6
Add new `BitData` to `CircuitData`
raynelfss Jan 17, 2025
53a7979
Add more rust native connections to `CircuitData` and `QuantumCircuit`.
raynelfss Jan 21, 2025
8b80738
Fix: Do not re-add bits when adding registers.
raynelfss Jan 21, 2025
ff9958f
Fix: Incorrect addition of register cache
raynelfss Jan 22, 2025
8c6c2ea
Fix: Incorrect serialization and mutability
raynelfss Jan 22, 2025
1744b12
Merge remote-tracking branch 'upstream/main' into bit_u32_sequel
raynelfss Jan 22, 2025
e5ebe22
Refactor `BitInfo` to account for bits added from registers.
raynelfss Jan 23, 2025
2162f1f
Fix: Resolve strange behavior of `BitLocations`.
raynelfss Jan 27, 2025
03fbbc2
Update bit.rs
raynelfss Jan 28, 2025
02c4d1a
Merge remote-tracking branch 'upstream/main' into bit_u32_sequel
raynelfss Jan 28, 2025
2cd46a5
Fix: Add registers correctly in `circuit_to_instruction`.
raynelfss Jan 28, 2025
8283370
Fix: Remaining tests (-1)
raynelfss Jan 28, 2025
a353334
Fix: incorrect circuit initalization on the rust-side.
raynelfss Jan 28, 2025
6be25c5
Fix: Regenerate cache if any rust bits are missing.
raynelfss Jan 29, 2025
5169fc6
Lint: Remove unused `Qubit` import
raynelfss Jan 29, 2025
c2461ba
Docs: Add header strings in `bit.rs` and `register.rs`
raynelfss Jan 29, 2025
ae3385e
Merge branch 'main' into bit_u32_sequel
raynelfss Jan 30, 2025
b18c5ab
Merge branch 'main' into bit_u32_sequel
raynelfss Jan 30, 2025
f1ffc16
Fix: Remove changes to the `Interner`
raynelfss Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
BitData refactor: Store Registers
  • Loading branch information
raynelfss committed Jan 16, 2025
commit 3a0c5bb6b41e56fa914580612f62652d7b2bebfb
161 changes: 7 additions & 154 deletions crates/circuit/src/bit.rs
Original file line number Diff line number Diff line change
@@ -1,168 +1,21 @@
use std::hash::{DefaultHasher, Hash, Hasher};

use pyo3::{exceptions::PyTypeError, prelude::*, types::PyDict};

use crate::{
circuit_data::CircuitError,
interner::Interned,
register::{Register, RegisterAsKey},
};

/// Object representing a Python bit, that allows us to keep backwards compatibility
/// with the previous structure.
#[pyclass(name = "Bit", module = "qiskit._accelerate.bit", subclass)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PyBit {
register: Option<RegisterAsKey>, // Register identifier
index: Option<u32>, // Index within Register
}

#[pymethods]
impl PyBit {
#[new]
#[pyo3(signature=(register=None, index=None))]
pub fn new(register: Option<RegisterAsKey>, index: Option<u32>) -> PyResult<Self> {
match (&register, index) {
(None, None) => Ok(Self { register, index }),
(Some(_), Some(_)) => Ok(Self { register, index }),
_ => Err(CircuitError::new_err(
"You should provide both an index and a register, not just one of them.",
)),
}
}

fn __eq__<'py>(slf: Bound<'py, Self>, other: Bound<'py, Self>) -> bool {
let borrowed = slf.borrow();
let other_borrowed = other.borrow();
if borrowed.register.is_some() && borrowed.index.is_some() {
return borrowed.register == other_borrowed.register
&& borrowed.index == other_borrowed.index;
}

slf.is(&other)
}

fn __hash__(&self, py: Python<'_>) -> PyResult<isize> {
if let (Some(reg), Some(idx)) = (self.register.as_ref(), self.index) {
return (reg.reduce(), idx).to_object(py).bind(py).hash();
}

// If registers are unavailable, hash by pointer value.
let mut hasher = DefaultHasher::new();
let pointer_val = self as *const Self;
pointer_val.hash(&mut hasher);
Ok(hasher.finish() as isize)
}

fn __copy__(slf: Bound<Self>) -> Bound<Self> {
slf
}

#[pyo3(signature = (_memo=None))]
fn __deepcopy__<'py>(
slf: Bound<'py, Self>,
_memo: Option<Bound<'py, PyDict>>,
) -> PyResult<Bound<'py, PyBit>> {
let borrowed: PyRef<Self> = slf.borrow();
if borrowed.index.is_none() && borrowed.register.is_none() {
return Ok(slf);
}
let copy = slf
.get_type()
.call_method1("__new__", (slf.get_type(),))?
.downcast_into::<PyBit>()?;
let mut copy_mut = copy.borrow_mut();
copy_mut.register = borrowed.register.clone();
copy_mut.index = borrowed.index;
Ok(copy)
}

fn __getstate__(slf: PyRef<'_, Self>) -> (Option<(String, u32)>, Option<u32>) {
(
slf.register.as_ref().map(|reg| {
let (name, num_qubits) = reg.reduce();
(name.to_string(), num_qubits)
}),
slf.index.as_ref().copied(),
)
}

fn __setstate__(mut slf: PyRefMut<'_, Self>, state: (Option<(String, u32)>, Option<u32>)) {
slf.register = state
.0
.map(|(name, num_qubits)| RegisterAsKey::Register((name, num_qubits)));
slf.index = state.1;
}

fn __repr__(slf: Bound<Self>) -> PyResult<String> {
let borrowed = slf.borrow();
if borrowed.register.is_none() && borrowed.index.is_none() {
return Ok(slf.py_super()?.repr()?.to_string());
}
let reg = borrowed.register.as_ref().unwrap();
Ok(format!(
"{}({}({}, '{}'), {})",
slf.get_type().name()?,
reg.type_identifier(),
reg.index(),
reg.name(),
borrowed.index.unwrap()
))
}

pub fn is_new(&self) -> bool {
self.index.is_none() && self.register.is_none()
}
}

macro_rules! create_py_bit {
($name:ident, $pyname:literal, $reg_type:pat, $module:literal) => {
#[pyclass(name=$pyname, extends=PyBit, subclass, module=$module)]
#[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(
register: Option<RegisterAsKey>,
index: Option<u32>,
) -> PyResult<(Self, PyBit)> {
if register.is_none() || matches!(register, Some($reg_type)) {
Ok((Self(), PyBit::new(register, index)?))
} else {
Err(PyTypeError::new_err(format!(
"The incorrect register was assigned. Bit type {}, Register type {}",
$pyname,
register.unwrap().type_identifier()
)))
}
}
}
};
}

// Create python instances
create_py_bit! {PyQubit, "Qubit", RegisterAsKey::Quantum(_), "qiskit._accelerate.bit"}
create_py_bit! {PyClbit, "Clbit", RegisterAsKey::Classical(_), "qiskit._accelerate.bit"}
use std::fmt::Debug;

/// Keeps information about where a qubit is located within the circuit.
#[derive(Debug, Clone)]
pub struct BitInfo<T: Register + Hash + Eq> {
register_idx: Interned<T>,
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct BitInfo {
register_idx: u32,
index: u32,
}

impl<T: Register + Hash + Eq> BitInfo<T> {
pub fn new(register_idx: Interned<T>, index: u32) -> Self {
impl BitInfo {
pub fn new(register_idx: u32, index: u32) -> Self {
Self {
register_idx,
index,
}
}

pub fn register_index(&self) -> Interned<T> {
pub fn register_index(&self) -> u32 {
self.register_idx
}

Expand Down
Loading