Skip to content

Use Rust generator function for QuantumVolume class#13283

Merged
Cryoris merged 4 commits intoQiskit:mainfrom
mtreinish:use-qv-rs-for-py-class
Oct 16, 2024
Merged

Use Rust generator function for QuantumVolume class#13283
Cryoris merged 4 commits intoQiskit:mainfrom
mtreinish:use-qv-rs-for-py-class

Conversation

@mtreinish
Copy link
Copy Markdown
Member

Summary

In #13238 we added a new function quantum_volume for generating a quantum volume model circuit with the eventual goal of replacing the existing QuantumVolume class. This new function is ~10x faster to generate the circuit than the existing python class. This commit builds off of that to internally call the new function for generating the circuit from the class. While the plan is to deprecate and remove the class for Qiskit 2.0 until that time we can give a performance boost to users of it for the lifespan of the 1.x release series.

Details and comments

In Qiskit#13238 we added a new function quantum_volume for generating a
quantum volume model circuit with the eventual goal of replacing the
existing QuantumVolume class. This new function is ~10x faster to
generate the circuit than the existing python class. This commit builds
off of that to internally call the new function for generating the
circuit from the class. While the plan is to deprecate and remove the
class for Qiskit 2.0 until that time we can give a performance boost to
users of it for the lifespan of the 1.x release series.
@mtreinish mtreinish added performance Changelog: Added Add an "Added" entry in the GitHub Release changelog. Changelog: Changed Add a "Changed" entry in the GitHub Release changelog. mod: circuit Related to the core of the `QuantumCircuit` class or the circuit library labels Oct 4, 2024
@mtreinish mtreinish added this to the 1.3.0 milestone Oct 4, 2024
@mtreinish mtreinish requested a review from a team as a code owner October 4, 2024 22:11
@qiskit-bot
Copy link
Copy Markdown
Collaborator

One or more of the following people are relevant to this code:

  • @Cryoris
  • @Qiskit/terra-core
  • @ajavadia

Copy link
Copy Markdown
Contributor

@kevinhartman kevinhartman left a comment

Choose a reason for hiding this comment

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

Looks mostly good, other than the test failure regarding seeding.

width = num_qubits // 2 # how many SU(4)s fit in each layer
rng = seed if isinstance(seed, np.random.Generator) else np.random.default_rng(seed)
seed_name = seed
if seed is None:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IMO it would be clearer to check if seed_name is None instead, since the purpose of this branch is to make sure it has a value.

if flatten:
self.compose(qv_circ, inplace=True)
else:
self._append(CircuitInstruction(qv_circ.to_instruction(), tuple(self.qubits)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we instead just early-return here instead of having the else on line 107? That way, it's a bit clearer that the handling of classical permutations is treated specially and forwarded to the Rust quantum_volume.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I didn't return because __init__ normally doesn't have a return; that's an implicit None but there is a pylint rule that doesn't like an explicit return in one path and not another.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think pylint is fine with bare return for early return, it's return None it has a problem with (unless it's changed).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah, that's probably it, I normally would do return None in this case. I can change it to a bare return if there is a strong preference here.

@mtreinish
Copy link
Copy Markdown
Member Author

I did a quick speed test of a 100q qv model circuit, with QuantumVolume(100, 100, seed=42) with this PR it takes 0.06909546643420132 sec and with 1.2.4 it took: 0.08987236272822026 sec (averaged over 50 runs). Most of the time is spent in to_instruction() for _append

@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 11243570672

Details

  • 20 of 21 (95.24%) changed or added relevant lines in 1 file are covered.
  • 19 unchanged lines in 4 files lost coverage.
  • Overall coverage increased (+0.009%) to 88.884%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/circuit/library/quantum_volume.py 20 21 95.24%
Files with Coverage Reduction New Missed Lines %
qiskit/transpiler/passes/synthesis/unitary_synthesis.py 2 88.26%
crates/qasm2/src/lex.rs 4 92.98%
crates/qasm2/src/parse.rs 6 97.61%
qiskit/synthesis/two_qubit/xx_decompose/decomposer.py 7 90.91%
Totals Coverage Status
Change from base Build 11241264267: 0.009%
Covered Lines: 74763
Relevant Lines: 84113

💛 - Coveralls

CircuitInstruction(gate, (qubits[perm[qubit]], qubits[perm[qubit + 1]]))
)
if classical_permutation:
if seed is not None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I might be slower than usual as I'm reviewing this before my first coffee, but should this be the following?

Suggested change
if seed is not None:
if seed is None:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is actually correct. This code path is to normalize the seeds we pass to rust so it will fit in a uint64 (although I realized I used int64 by mistake, I'll fix that). The typing on the python class was a python int which was doesn't have an upper bound and it was possible to pass in an value greater than 18446744073709551615 which would cause an error when one didn't happen before. To solve that I used a numpy rng to select a random int from the provided seed value that we then pass to rust as a seed for it's internal rng.

When seed is None we can just pass that to rust because it will use system entropy to initialize the rust rng.

Comment thread qiskit/circuit/library/quantum_volume.py
@Cryoris Cryoris added this pull request to the merge queue Oct 16, 2024
Merged via the queue into Qiskit:main with commit 50f2965 Oct 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: Added Add an "Added" entry in the GitHub Release changelog. Changelog: Changed Add a "Changed" entry in the GitHub Release changelog. mod: circuit Related to the core of the `QuantumCircuit` class or the circuit library performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants