New StateVector simulator backend based on cuQuantum for Graphix - #1
Conversation
|
Thanks, I'll look into it in the coming days. Don't worry about the typecheck failure in the CI, it's a known issue with mypy and qiskit. I thought I had fixed the dependency, but maybe qiskit 2.4 version is leaking from the mqt-bench plugin, I'll try to fix it. |
|
Looking nice! I managed to run your bash script and tests are passing. I'll review your code shortly. |
matulni
left a comment
There was a problem hiding this comment.
Thanks for your work, it looks very nice!
Here are some comments from my first pass
|
hi @matulni I'm working on all your suggestions, I'll get back to you as soon as it is all done. |
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
Co-authored-by: matulni <m.uldemolins@gmail.com>
|
hi @matulni except for the comment I left above the tests and lints are now passing for all the repo and the code suggestions applied, there is another new helper script run_validations that runs the previous mentioned commands but for all repo which ease the testing in local environments. Nonetheless, I will dig deeper in the Tuple v. tuple issue later today. |
|
Hi @ljcamargo, we decided to award you the bounty for your contribution, congratulations! |
Co-authored-by: matulni <m.uldemolins@gmail.com> Co-authored-by: thierry-martinez <thierry.martinez@inria.fr>
|
Hi @matulni and @thierry-martinez thanks a lot for choosing me! I'm working on solving all the comments, they remain a few, nonetheless in the last batch of suggestion of yours I've applied, they raised many new lint and runtime errors, as they were many this time, I used ai analysis this time to asses which suggestion lead to which errors and got the following, I suggest reverting this to keep the tests running and tackle other fixes while you check this comments:
- branch = t[tuple(idx)].ravel()
+ branch = t[idx].ravel()Cupy does not accept a plain list as an advanced index — it needs tuple(...). This caused every remove_qubit call
- branch_nrm2 = float(cp.sum(cp.abs(branch) ** 2))
+ branch_nrm2 = cp.sum(cp.abs(branch) ** 2)cp.sum() returns a cupy scalar, not a Python float. math.isclose() downstream expects a Python float. The float()
- backend = cls(**kwargs)
- object.__setattr__(backend, "state", state_init)
- return backend
+ return cls(state_init, **kwargs)state has init=False on the frozen dataclass, so calling cls(state_init, ...) passes state_init (a Statevec) to the (THIS ONE IS A CONCERN, WHICH AI ADVERTS OF POSSIBLE UNWANTED SIDE FX) - ip = float(cp.dot(a.conj(), b))
- return ip.real**2 + ip.imag**2
+ ip: float = cp.dot(a.conj(), b) # cp.dot returns complex, not float
+ return ip # now returns complex, not |<ψ1|ψ2>|²cp.dot() on complex arrays returns a complex value. The annotation ip: float is misleading — the value is complex. |
Co-authored-by: matulni <m.uldemolins@gmail.com>
thierry-martinez
left a comment
There was a problem hiding this comment.
You've my approval! Thank for your contribution.
|
Hi @ljcamargo, thanks for your contribution and apologies for the misleading comments. We'll merge the PR! |
3e11b3c
into
matulni:cuquantum-backend-ljcamargo
Closes TeamGraphix/graphix#496 for UnitaryHack 2026
Hello @matulni here is the PR for the cuQuantum StateVector backend.
Some comments:
Copy of the backend README:
graphix-statevec-cuquantum
GPU-accelerated statevector backend for Graphix pattern simulation, built on NVIDIA cuQuantum (cuStateVec) and CuPy.
Requirements
cuquantum-python-cu12(≥ 24.03) — pre-built wheels, no CUDA toolkit needed at build timecupy-cuda12x(≥ 13.0)Installation
Usage
Design
State representation
The quantum state is stored as a flat CuPy array of shape
(2**max_space,)with dtypecomplex128. Only the first2**nqubitentries are meaningful; the tail is padding to avoid GPU reallocation as qubits come and go during MBQC pattern simulation.Qubit ordering
Graphix uses MSB convention (qubit 0 = most significant bit = axis 0 of the tensor). cuQuantum uses LSB convention (qubit 0 = least significant bit). All calls to cuQuantum APIs convert indices via
_msb_to_lsb().cuQuantum API used
custatevec.apply_matrixapply_matrix_get_workspace_sizecustatevec.compute_expectationcomplexcp.swapaxes(CuPy)swap_index_bitsavailable but CuPy tensor axis swap is simpler and equally GPU-acceleratedcustatevec.apply_matrixwith 4×4 CZ matrixBuffer growth
When
tensor()needs more space thanmax_space, the buffer is reallocated to exactly the needed size. No doubling strategy is used, since MBQC pattern qubit counts fluctuate and doubling can overshoot GPU memory.Project structure
CI notes
Tests and benchmarks are decorated with
@pytest.mark.skipif(not _gpu_available(), reason="GPU not available"). On CI runners without GPU they will be skipped. Formatting, linting, and type-checking still run normally.Benchmark results (Tesla T4)
Approximate per-operation latency (lower is better):
evolve_single(H gate)entangle(CZ)expectation_single(Z)add_nodesremove_qubitGate application times are near-constant across qubit counts due to cuQuantum's optimized GPU kernels. Structural operations (
add_nodes,remove_qubit) scale with state size as they involve GPU memory transfers.Caveats
cuquantum.bindings.custatevec). Earlier versions (24.x) withcuquantum.custatevecandapply_gateare not compatible.compute_expectation: cuQuantum's own API writes the scalar result to a host-side (CPU) buffer. The computation is fully GPU-accelerated; only the final 16-byte complex value is transferred to CPU.tensor()growth triggers a new GPU allocation. For patterns with predictablemax_space, initializingStatevecwith the correctmax_spaceavoids this.apply_noise.StatevecandStatevectorBackendfollow the template's convention. The import path (graphix_statevec_cuquantum) disambiguates from the NumPy CPU backend (graphix.sim.statevec) and the template (graphix_statevec_template). Subject to change based on Graphix maintainer guidelines.test_output_20260606_211025.log