## `eigenkit.core.backends.cudaquantum_backend`

The CUDA Quantum backend (the `cuda-quantum` package).

`cudaq` is an optional dependency (`pip install eigenkit[cudaquantum]`). The package is imported only when it is needed, so the rest of the library works without it, and `compile()` raises a clear `ImportError` if it is missing.

It declares `gradient_method = "parameter_shift"`. `cudaq` has its own parameter-shift tools, but this backend uses the fallback of the gradient code instead, for consistency across backends. This keeps Qiskit, Braket and `cudaq` on a single gradient code path.

`compile()` builds a parametric kernel with `cudaq.make_kernel` once. Each `run()` calls `cudaq.observe(kernel, hamiltonian, *params)` for each observable.

Limitation: only the parameter expressions `Constant`, `WeightRef`, `InputRef`, `Scale` and `Negate` are supported. `Sum` and `Multiply` expressions raise `NotImplementedError`, because the arithmetic of the `cudaq` `QuakeValue` is more restricted than that of the Qiskit `ParameterExpression`.

Example

```python
from eigenkit import Circuit, Encoding, Variational, all_z
from eigenkit import CudaQuantumBackend, register

blocks = [Encoding(in_features=4), Variational(depth=2)]

# by registered name, after registering it once
register("cudaq", CudaQuantumBackend())
circuit = Circuit(blocks=blocks, observables=all_z(4), provider="cudaq")

# or with the config, when a device setting matters
from eigenkit.configs import CudaQuantumConfig

circuit = Circuit(
    blocks=blocks,
    observables=all_z(4),
    provider=CudaQuantumConfig(target="nvidia"),
)
```

This backend is optional: register it once with `register("cudaq", CudaQuantumBackend())` before the name can be used.

### `CudaQuantumBackend`

The provider for NVIDIA CUDA Quantum, under the name `"cudaq"`.

It is not registered automatically. Register it with `register("cudaq", CudaQuantumBackend())` to select it with `provider="cudaq"`, or pass a CudaQuantumConfig as `provider=`.

#### `capabilities`

What this backend supports.

It runs every gate except the state preparation gates, the arbitrary unitaries, the generic multi-controlled gates and `CPHASE`. A CUDA Quantum kernel compiles to a hardware intermediate representation, so it cannot express the first three, and this backend does not translate `CPHASE`. It can sample a finite number of shots, evaluates a batch in one call through `cudaq.observe`, and has no limit on the number of qubits. See Capabilities.

#### `__init__(config=None, name='cudaq')`

Build the backend from a device configuration.

Parameters:

| Name     | Type                | Description                                                         | Default   |
| -------- | ------------------- | ------------------------------------------------------------------- | --------- |
| `config` | `CudaQuantumConfig` | The device settings. Default: None, which uses CudaQuantumConfig(). | `None`    |
| `name`   | `str`               | The registry name, used in error messages. Default: "cudaq".        | `'cudaq'` |

#### `compile(circuit, observables)`

Prepare `circuit` for repeated evaluation of `observables`.

A `Circuit` calls it once and reuses the result for every call, so the expensive work belongs here.

Parameters:

| Name          | Type                   | Description                 | Default    |
| ------------- | ---------------------- | --------------------------- | ---------- |
| `circuit`     | `CircuitSpec`          | The circuit to prepare.     | *required* |
| `observables` | `Sequence[Observable]` | The observables to measure. | *required* |

Returns:

| Type                  | Description                                            |
| --------------------- | ------------------------------------------------------ |
| `CudaQuantumCompiled` | The prepared circuit, as a CudaQuantumCompiled object. |

### `CudaQuantumCompiled`

Bases: `CompiledCircuit`

A circuit prepared for CUDA Quantum.

It is internal: CudaQuantumBackend.compile() builds it and returns it, and it is never built directly.

#### `__init__(circuit, observables, config)`

Prepare the circuit for repeated evaluation.

`CudaQuantumBackend.compile()` builds this object, so there is no reason to build one directly.

Parameters:

| Name          | Type                   | Description                 | Default    |
| ------------- | ---------------------- | --------------------------- | ---------- |
| `circuit`     | `CircuitSpec`          | The circuit to prepare.     | *required* |
| `observables` | `Sequence[Observable]` | The observables to measure. | *required* |
| `config`      | `CudaQuantumConfig`    | The device settings.        | *required* |

#### `run(weights, inputs)`

Evaluate the circuit and return one expectation value per observable.

It follows the `CompiledCircuit` contract: the result has shape `(n_obs,)` when `weights` and `inputs` are both 1-D, and `(B, n_obs)` otherwise.

Parameters:

| Name      | Type      | Description                                                                 | Default    |
| --------- | --------- | --------------------------------------------------------------------------- | ---------- |
| `weights` | `ndarray` | The parameter vector: 1-D for one sample, or 2-D with a leading batch axis. | *required* |
| `inputs`  | `ndarray` | The input features, with the same 1-D or 2-D shape convention as weights.   | *required* |

Returns:

| Type      | Description                                      |
| --------- | ------------------------------------------------ |
| `ndarray` | The expectation values, one for each observable. |

#### `zero_state_probability(weights, inputs)`

Return the probability of `|0…0⟩`, read from the statevector of `cudaq`.

Parameters:

| Name      | Type      | Description                             | Default    |
| --------- | --------- | --------------------------------------- | ---------- |
| `weights` | `ndarray` | The parameter vector (1-D).             | *required* |
| `inputs`  | `ndarray` | The input features of one sample (1-D). | *required* |

Returns:

| Type    | Description                         |
| ------- | ----------------------------------- |
| `float` | The probability, a float in [0, 1]. |

### `CudaQuantumConfig`

Device configuration for the CUDA Quantum backend.

Parameters:

| Name     | Type  | Description                                                                                                                                                                                                                                                                                                           | Default                                                                                               |
| -------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `target` | `str` | The cudaq target. Common values are "qpp-cpu", a statevector simulator on the central processing unit (CPU), which is the default; "nvidia", on one graphics processing unit (GPU); "nvidia-mgpu", on several GPUs; "nvidia-mqpu", with several quantum processing units (QPUs); and "tensornet". Default: "qpp-cpu". | `'qpp-cpu'`                                                                                           |
| `shots`  | \`int | None\`                                                                                                                                                                                                                                                                                                                | None for exact expectation values, or a positive integer for a finite number of shots. Default: None. |

#### `make_backend()`

Build the backend that this configuration describes.

The provider layer calls it when a configuration is passed as `provider=`. There is no reason to call it directly.

Returns:

| Type                   | Description                                    |
| ---------------------- | ---------------------------------------------- |
| `'CudaQuantumBackend'` | The CudaQuantumBackend for this configuration. |
