Skip to content

Add zero-copy GPU state vector access (#836) - #1100

Open
Jonathan-tWang wants to merge 2 commits into
quantumlib:mainfrom
Jonathan-tWang:issue-836-device-state
Open

Add zero-copy GPU state vector access (#836)#1100
Jonathan-tWang wants to merge 2 commits into
quantumlib:mainfrom
Jonathan-tWang:issue-836-device-state

Conversation

@Jonathan-tWang

Copy link
Copy Markdown

This PR adds an opt-in zero-copy API, QSimSimulator.simulate_into_device_array(...), to extract the final state vector from GPU simulation without copying data from GPU to host memory (issue #836).

The returned DeviceStateVector object owns the GPU allocation and exposes it through the CUDA Array Interface (__cuda_array_interface__, v3), allowing downstream GPU frameworks (CuPy, PyTorch, Numba) to consume the device buffer directly without a device -> host -> device round trip.

This PR adds an opt-in zero-copy API, `QSimSimulator.simulate_into_device_array(...)`, to extract the final state vector from GPU simulation without copying data from GPU to host memory (issue quantumlib#836).

The returned `DeviceStateVector` object owns the GPU allocation and exposes it through the CUDA Array Interface (`__cuda_array_interface__`, v3), allowing downstream GPU frameworks (CuPy, PyTorch, Numba) to consume the device buffer directly without a device -> host -> device round trip.
@google-cla

google-cla Bot commented Aug 4, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added the size: L 250< lines changed <1000 label Aug 4, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request implements zero-copy device state-vector bindings, allowing GPU-based simulations to retain their final state in device memory and expose it via the CUDA Array Interface for direct consumption by libraries like CuPy. Feedback on these changes highlights a potential out-of-bounds read vulnerability when passing non-contiguous NumPy arrays as initial states, which can be resolved by ensuring C-contiguity. Additionally, it is recommended to use std::make_unique instead of direct new expressions when instantiating std::unique_ptrs to comply with the Google C++ Style Guide.

Comment on lines +636 to +639
if isinstance(initial_state, np.ndarray):
if initial_state.dtype != np.complex64:
raise TypeError("initial_state vector must have dtype np.complex64.")
input_vector = initial_state.view(np.float32)

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.

high

When initial_state is a non-contiguous NumPy array (e.g., created via slicing or striding), initial_state.view(np.float32) will also be non-contiguous. Passing this to the C++ extension and accessing its raw data pointer via input_vector.data() will result in sequential out-of-bounds reads, leading to silent data corruption or segmentation faults.

To prevent this, ensure the array is C-contiguous by calling np.ascontiguousarray before creating the view.

        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError("initial_state vector must have dtype np.complex64.")
            initial_state = np.ascontiguousarray(initial_state)
            input_vector = initial_state.view(np.float32)

Comment thread pybind_interface/pybind_main.cpp Outdated
Comment on lines +850 to +851
return std::unique_ptr<DeviceStateVector>(
new DeviceStateVector(std::move(helper)));

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.

high

According to the Google C++ Style Guide (referenced in the repository style guide), you should prefer using std::make_unique over direct new expressions when creating std::unique_ptrs. This avoids explicit type repetition and is safer.

    return std::make_unique<DeviceStateVector>(std::move(helper));
References
  1. Use std::make_unique instead of bare new when creating std::unique_ptr, as recommended by the Google C++ Style Guide. (link)

- Ensure initial_state NumPy array is C-contiguous (via np.ascontiguousarray) before creating float32 view to prevent out-of-bounds reads on non-contiguous array slices.
- Use std::make_unique<DeviceStateVector> instead of bare new expression per Google C++ Style Guide.
- Add test_cirq_qsim_gpu_simulate_into_device_array_with_non_contiguous_input_state test case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: L 250< lines changed <1000

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant