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 33 commits into
base: main
Choose a base branch
from

Conversation

raynelfss
Copy link
Contributor

@raynelfss raynelfss commented Jan 17, 2025

Summary

The following commits add native bits and register usage to CircuitData. This is the first public attempt at implementing these structures and is open to feedback.

Details and comments

Tasks:

  • Implement a new BitData struct to store registers.
  • Implement the new BitData in CircuitData.
  • Fix all the broken tests.
  • Implement rust-native tests to check if this is working properly.
  • Implement python cross testing.

@raynelfss raynelfss linked an issue Jan 17, 2025 that may be closed by this pull request
raynelfss and others added 6 commits January 21, 2025 15:21
- Some functions in `CircuitData` had become mutable unnecessarily due to erroneous assumptions on the `BitData` `OnceCell` usage.
- Fix incorrect serialization to now include registers in `CircuitData::__reduce__`.
- Also add `CircuitData::__setstate__` to deal with the new register state.
- Fix bug with `BlueprintCircuit` that discarded most instances of `QuantumRegister`.
- Rename `RegisterAsKey::index()` to size, since it was erroneously named.
Copy link
Contributor

@to24toro to24toro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for sharing this pull request. I understand that this is currently marked as a WIP and a draft, so I was initially hesitant to leave comments. However, I do have a few questions and suggestions that I hope will be helpful as the work progresses.

crates/circuit/src/bit.rs Outdated Show resolved Hide resolved
Comment on lines +8 to +11
pub struct BitInfo {
added_by_reg: bool,
registers: Vec<BitLocation>,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BitInfo struct and its registers field may be somewhat ambiguous in conveying their true purpose.It appears that BitInfo primarily tracks how bits are associated with registers.

You might consider renaming this BitInfo to something more indicative of its focus on bit-register relationships or placements.

However, if you assume how to use it in another way, it is not necessary to rename this field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You got the intended use correctly. I'm open to renaming this, since it is WiP you can leave any suggestions.

@@ -230,3 +235,602 @@ where
self.bits.clear();
}
}

#[derive(Clone, Debug)]
pub struct NewBitData<T: From<BitType>, R: Register + Hash + Eq> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Q] Both BitData<T> and NewBitData<T, R>, which both manage and track bit-related information. However, it’s not entirely clear how they are intended to coexist. Are they meant to be used in parallel for different scenarios(is BitData<T> for dag-circuit?), or is there a plan to eventually replace BitData<T> with NewBitData<T, R>? Any clarification on whether BitData<T> is deprecated or if both are needed for distinct reasons would be greatly appreciated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewBitData here is meant to replace BitData, the only reason why I'm keeping the old one around still is because the new replacement methods will need a bigger rewrite of DAGCircuit's methods. Which I plan on doing on a separate PR due to how big it is.

let res = py_reg.unwrap().bind(py).get_item(bit_info.index())?;
self.bits[index_as_usize]
.set(res.into())
.map_err(|_| PyRuntimeError::new_err("Could not set the OnceCell correctly"))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of simply saying "Could not set the OnceCell correctly", you might include any relevant internal state or the specific condition that led to the failure. This added detail will greatly aid in diagnosing issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this.

raynelfss and others added 7 commits January 27, 2025 15:32
- Fix `BitLocation` updates when a bit or a register is added to use data directly from `CircuitData`.
- Fix incorrect register re-assignment in `QuantumCircuit._from_circuit_data`.
- Re-organize `BitData::py_get_bit_location` to behave more closely to python.
Co-authored-by: Kento Ueda <[email protected]>
- Add additional checks to `find_bit()`, to make sure bit exists in the `CircuitData` instance.
- Separate python `add_register` from native method due to conflicting implementation.
- Fix register setter in `NewBitData` to discard old `BitLocations`.
- Update `BitLocations` when setting a new register in `QuantumCircuit`.
- Modify test to include registers when comparing to an equivalency from the `EquivalenceLibrary`.
- Add one test case to test initialization.
- Modify the getter methods for the cached lists to correct the cache if it becomes necessary. This to avoid the uninitialization of bits when rust bits are added after requesting access from Python. These methods are now fallible, so a PyResult will always be returned.
- Adapt `CircuitData` and `DAGCircuit` to these changes.
@coveralls
Copy link

coveralls commented Jan 29, 2025

Pull Request Test Coverage Report for Build 13145399793

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 563 of 946 (59.51%) changed or added relevant lines in 10 files are covered.
  • 142 unchanged lines in 12 files lost coverage.
  • Overall coverage decreased (-0.3%) to 88.52%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/circuit/quantumcircuit.py 33 34 97.06%
crates/circuit/src/lib.rs 3 6 50.0%
crates/circuit/src/register.rs 33 98 33.67%
crates/circuit/src/circuit_data.rs 135 244 55.33%
crates/circuit/src/bit_data.rs 299 504 59.33%
Files with Coverage Reduction New Missed Lines %
crates/circuit/src/circuit_data.rs 1 86.34%
qiskit/providers/basic_provider/basic_provider_tools.py 1 83.33%
crates/circuit/src/operations.rs 1 89.61%
qiskit/result/result.py 3 83.74%
qiskit/providers/models/backendconfiguration.py 3 85.76%
crates/qasm2/src/lex.rs 4 92.73%
qiskit/circuit/library/blueprintcircuit.py 6 94.31%
crates/qasm2/src/parse.rs 6 97.61%
qiskit/providers/basic_provider/basic_simulator.py 7 97.37%
crates/circuit/src/bit_data.rs 8 65.3%
Totals Coverage Status
Change from base Build 13118695608: -0.3%
Covered Lines: 80202
Relevant Lines: 90603

💛 - Coveralls

raynelfss and others added 8 commits January 30, 2025 11:59
- Remove stale methods `contains` and `get_interned` from `Interner` in favor of the changes introduced by Qiskit#13752.
- Temporarily fix incorrect null assignment of `Bit` object to indices. A different solution can be achieved if more time is spent.
- Incorrect python circuit creation in Python due to misusage of the bit's `BitInfo` property inside of `BitData`.
- Fix incorrect register and bit creation from `CircuitData::new()`
- Add provisional `qubits_mut()` and `clbits_mut()` methods while we address the issue with `indices`.
- Fix error where rust bits wouldn't be initialized in the cache.
- Provisionally fix error in which rust bits wouldn't have valid mapping to python bits. Bits need to be generated before being able to map them to a rust native index. The current solution implements said changes during the `find_bit` function, in which there is an extra validation step. However, this is certain to consume more resources. The ideal solution would be to generate said mapping when obtaining the Python bit with something similar to a `RefCell`. However, `RefCells` are not thread safe and could cause several mutable references to coexist.
- Re-purpose `NewBitData.indices` to be modifiable even when if a mutable references is not granted by using `RWLock`. This is done to stay consistent with the behavior of `OnceLock` which allows us to initialize bits upon request. We need to make sure to map a bit once it has been initialized. Otherwise, the circuit will have to regenerate this mapping multiple times during runtime.
- Optimize pre-caching of Python bits and registers by using the cache size. Bits and registers are guaranteed to be initialized in ther order they were added/last accessed, so in the case a cache is initialized prematurely, add the missing bits or registers to the back of the cache while following the same index order.
…es of the inner `CircuitData`.

- Fix docstrings in `CircuitData` and `BitData`.
- Remove unnecessary mutable reference in `find_bit()`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make rust Qubit and Clbit the source of truth in a circuit
3 participants