CUDA Backend

The CUDA backend leverages NVIDIA GPUs via the cuda-quantum framework. When no compatible GPU is detected it transparently falls back to a CPU target, so the same code prototyped on a laptop will also run on an accelerated machine.

Installation

pip install qilisdk[cuda12]   # or [cuda13]

Quick start

import numpy as np
from qilisdk.digital import Circuit, H, RX, CNOT
from qilisdk.backends import CudaBackend, CudaSamplingMethod
from qilisdk.functionals import DigitalPropagation
from qilisdk.readout import Readout

circuit = Circuit(2)
circuit.add(RX(0, theta=np.pi / 4))
circuit.add(H(0))
circuit.add(CNOT(0, 1))

backend = CudaBackend(sampling_method=CudaSamplingMethod.STATE_VECTOR)
result = backend.execute(DigitalPropagation(circuit), Readout().with_sampling(nshots=500))
print(result.get_samples())

Functional support

Functional

Support

Notes

DigitalPropagation

Native CUDA-Q kernel. Sampling method selected via CudaSamplingMethod. Intermediate measurements raise NotImplementedError.

AnalogEvolution

Driven by cudaq.evolve on the dynamics target (always GPU-accelerated when available, independent of the digital sampling method).

QuantumReservoir

🟡

The CudaBackend does not natively implement Backend._execute_quantum_reservoir. Circuit steps inside the reservoir layer fall back to dense QTensor unitary multiplication on CPU; Schedule steps still use CUDA-Q’s evolve. Any attached noise model is ignored.

VariationalProgram

Reuses the digital/analog handlers above for each optimization step.

Configuration

The CUDA backend exposes a single configuration parameter — CudaSamplingMethod — that selects the underlying CUDA-Q target used for digital circuits. Analog evolution always runs on the dynamics target and ignores this setting.

Method

CUDA-Q target (and fallback)

Default

STATE_VECTOR

nvidia (GPU) when a GPU is available, otherwise qpp-cpu. Precision matches Precision.

TENSOR_NETWORK

tensornet. Good for shallow, wide circuits.

MATRIX_PRODUCT_STATE

tensornet-mps. Good for low-entanglement, long circuits.

Set the method at construction time:

from qilisdk.backends import CudaBackend, CudaSamplingMethod

backend = CudaBackend(sampling_method=CudaSamplingMethod.MATRIX_PRODUCT_STATE)

Noise model support

A NoiseModel can be passed to CudaBackend(noise_model=…):

  • For DigitalPropagation, qilisdk noise channels are translated into a cudaq.NoiseModel (Kraus channels for static / time-derived noise, parameter perturbations applied to the circuit). With noise enabled, only a single SamplingReadout is supported.

  • For AnalogEvolution, Lindblad-compatible noise channels become CUDA-Q jump operators and Hamiltonian deltas fed to cudaq.evolve.

  • For QuantumReservoir, the fallback implementation drops the noise model (a warning is logged).

Example: a depolarising channel applied to every gate of a digital circuit:

from qilisdk.backends import CudaBackend, CudaSamplingMethod
from qilisdk.noise import NoiseModel, Depolarizing

nm = NoiseModel()
nm.add(Depolarizing(probability=1e-3))

backend = CudaBackend(
    sampling_method=CudaSamplingMethod.STATE_VECTOR,
    noise_model=nm,
)