cudaq.State.from_data silently misreads non-contiguous NumPy arrays (strides ignored on the host path)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
Research direction
Read python/runtime/cudaq/algorithms/py_state.cpp, focusing on getNumpyBufferInfo and createStateFromPyBuffer and how the host 1-D and 2-D paths handle strides. Reproduce with the issue's non-contiguous NumPy column view and compare it with np.ascontiguousarray(view). Done means State.from_data honors strides or rejects non-contiguous input instead of silently returning wrong amplitudes.
Written by the indexing model from the issue text.
Description
Describe the bug
cudaq.State.from_data(arr) with a non-contiguous NumPy array (for example a column view A[:, 0], or the ground-state column V[:, 0] returned by np.linalg.eigh for a complex Hermitian matrix) produces a state whose amplitudes are wrong, with no error or warning. The data are read from the underlying buffer as if they were contiguous.
In python/runtime/cudaq/algorithms/py_state.cpp, getNumpyBufferInfo records info.strides, but the host 1-D path in createStateFromPyBuffer then calls state::from_data(std::make_pair(ptr, info.size)), reading info.size consecutive elements from info.ptr. The contiguity helpers (isCContiguous / isFContiguous) are only consulted for CuPy input via shouldCanonicalizeCupyArray; NumPy input is never canonicalized. (The 2-D path only tests strides[1] == itemsize to pick row- vs column-major, so a sliced 2-D array is affected too.) The code is the same on current main.
Steps to reproduce
CUDA-Q 0.15.1 (pip), numpy 2.5.0, Python 3.12, target qpp-cpu:
import numpy as np, cudaq
cudaq.set_target("qpp-cpu")
rng = np.random.default_rng(2)
A = rng.normal(size=(4, 2)) + 1j * rng.normal(size=(4, 2))
A[:, 0] /= np.linalg.norm(A[:, 0])
view = A[:, 0] # complex128, view.flags["C_CONTIGUOUS"] is False
@cudaq.kernel
def load(s: cudaq.State):
q = cudaq.qvector(s)
for arr in (view, np.ascontiguousarray(view)):
out = np.array(cudaq.get_state(load, cudaq.State.from_data(arr)))
print(arr.flags["C_CONTIGUOUS"], np.max(np.abs(out - view)))
Output:
False 2.35e+00 <- wrong amplitudes, no error
True 0.00e+00
The common idiom w, V = np.linalg.eigh(H); cudaq.State.from_data(V[:, 0]) with a complex Hermitian H gives a max error of 1.06 in the same way. Real-valued input happens to be safe only because the required dtype cast to complex makes a contiguous copy.
Expected behavior
Either honor the strides (copy to a contiguous buffer, as np.ascontiguousarray does, mirroring what the CuPy path already does) or raise on non-contiguous input.
Impact
Any code that passes an eigenvector column or a slice of a larger array as an initial state gets a silently wrong simulation. Wrappers that use np.asarray(x, dtype=...) do not protect against it, because asarray returns the same strided buffer when the dtype already matches.
Environment
- CUDA-Q 0.15.1 (pip,
aca5853a), numpy 2.5.0, Python 3.12.3, Ubuntu (Linux 6.8), targetqpp-cpu - Source inspected at
main(549d6a0be):python/runtime/cudaq/algorithms/py_state.cpp,getNumpyBufferInfo/createStateFromPyBuffer/isCContiguous/shouldCanonicalizeCupyArray
- Dominant language
- C++
- Stars
- 1.2k
- Forks
- 490
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 191
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from NVIDIA/cuda-quantum
-
Ask the `ServerHelper` for fresh headers on every poll in `Future::get`, as is done for cookiesOpenenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
NVIDIA/cuda-quantum#5886 ·
Maintainers usually reply within 1 day
-
[docs] Shor's tutorial: test_order computes gcd(r ± 1, N) instead of gcd(a^(r/2) ± 1, N)Possibly taken @sylvesterkaczmarek claimed this 4 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
NVIDIA/cuda-quantum#5837 · 2 comments ·
Maintainers usually reply within 1 day
-
dfJump variable not initialized before first use in pass UnwindByDataFlowPossibly taken @totoschnell claimed this 35 days ago. Openstale-notified
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
NVIDIA/cuda-quantum#5539 · 2 comments ·
Maintainers usually reply within 1 day
-
Broadcast sample replaces a scalar argument with zeroPossibly taken @SashaMIT claimed this 41 days ago. Openstale-notified
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
NVIDIA/cuda-quantum#5518 · 1 comment ·
Maintainers usually reply within 1 day
-
[Docs] Fix typo in Sphinx extensions descriptionPossibly taken @reginaldalfret claimed this 35 days ago. Openstale-notified
Difficulty 1/5 Under an hour Newbie friendliness 95/100
NVIDIA/cuda-quantum#5492 · 2 comments ·
Maintainers usually reply within 1 day
All issues in NVIDIA/cuda-quantum
Similar issues
-
mlir
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
llvm/llvm-project#241070 · 1 comment ·
Maintainers usually reply within 1 day
-
backlog documentation
Difficulty 1/5 Under an hour Newbie friendliness 96/100
EchoTools/nevr-runtime#2354 ·
Maintainers usually reply within 1 day
-
help wanted new command
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
tldr-pages/tldr#25111 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day