## `eigenkit.core.backends.qiskit_backend`

The Qiskit backend.

Qiskit is an optional dependency (`pip install eigenkit[qiskit]`). It 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.

The backend has `gradient_method = "parameter_shift"`. Qiskit has no automatic differentiation for statevector expectation values, so the dispatch layer computes the gradients with the parameter-shift rule.

`compile()` builds a single parametrised `QuantumCircuit` whose gates use `qiskit.circuit.Parameter` symbols. Each `run()` calls `assign_parameters` on this circuit, so the circuit is not rebuilt at each call. The `SparsePauliOp` operators are also built only once.

Example

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

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

# by its registered name
circuit = Circuit(blocks=blocks, observables=all_z(4), provider="qiskit")

# or with the configuration, when a device setting matters
from eigenkit.configs import QiskitConfig

circuit = Circuit(
    blocks=blocks,
    observables=all_z(4),
    provider=QiskitConfig(),
)
```

The name `"qiskit"` is registered when the `qiskit` extra is installed.

### `QiskitBackend`

The provider for Qiskit, registered as `"qiskit"`.

This class is internal. Select the backend with `provider="qiskit"` or by passing a QiskitConfig, instead of constructing this class.

#### `capabilities`

Return what this backend supports.

It supports every gate, but only exact expectation values, because finite-shot sampling is not supported yet. It does not batch, and it has no limit on the number of qubits. The adjoint of `AmplitudeEncoding` is excluded, because the Qiskit gate translation does not implement it. See Capabilities.

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

Build the backend from a device configuration.

Parameters:

| Name     | Type           | Description                                | Default                                        |
| -------- | -------------- | ------------------------------------------ | ---------------------------------------------- |
| `config` | \`QiskitConfig | None\`                                     | The device settings. None uses QiskitConfig(). |
| `name`   | `str`          | The registry name, used in error messages. | `'qiskit'`                                     |

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

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

It is called once per `Circuit`, and the handle is reused for every call, so the expensive work is done here.

Parameters:

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

Returns:

| Type             | Description              |
| ---------------- | ------------------------ |
| `QiskitCompiled` | A QiskitCompiled handle. |

### `QiskitCompiled`

Bases: `CompiledCircuit`

A circuit prepared for Qiskit.

This class is internal. It is built by QiskitBackend.compile() and obtained from it, and it is never constructed directly.

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

Prepare the circuit for repeated evaluation.

`QiskitBackend.compile()` builds it, and there is no reason to construct one directly.

Parameters:

| Name          | Type                   | Description                                | Default    |
| ------------- | ---------------------- | ------------------------------------------ | ---------- |
| `circuit`     | `CircuitSpec`          | The circuit to prepare.                    | *required* |
| `observables` | `Sequence[Observable]` | The observables that this handle measures. | *required* |
| `config`      | `QiskitConfig`         | 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: a 1-D array for one sample, or a 2-D array with a leading batch axis. | *required* |
| `inputs`  | `ndarray` | The input features, with the same 1-D or 2-D shapes as weights.                             | *required* |

Returns:

| Type      | Description                           |
| --------- | ------------------------------------- |
| `ndarray` | One expectation value per observable. |

#### `statevector(weights, inputs, initial_state=None)`

Return the full complex statevector after the circuit.

In the result, qubit 0 is the most significant bit. The amplitudes are reordered from the Qiskit convention, where qubit 0 is the least significant bit, so that they match the NumPy and PennyLane backends. `initial_state`, in the same order as the result, is evolved through the bound circuit, so the evolution starts from it instead of `|0…0⟩`. When `inputs` is 2-D, the method loops over its rows and returns an array of shape `(B, 2**n_qubits)`.

Parameters:

| Name            | Type      | Description                                                                               | Default                             |
| --------------- | --------- | ----------------------------------------------------------------------------------------- | ----------------------------------- |
| `weights`       | `ndarray` | The parameter vector, which must be 1-D.                                                  | *required*                          |
| `inputs`        | `ndarray` | The input features: a 1-D array for one sample, or a 2-D array with a leading batch axis. | *required*                          |
| `initial_state` | \`ndarray | None\`                                                                                    | The state to evolve from instead of |

Returns:

| Type      | Description                                                                    |
| --------- | ------------------------------------------------------------------------------ |
| `ndarray` | The statevector, of shape (2\*\*n_qubits,), or (B, 2\*\*n_qubits) for a batch. |

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

Return the probability of the all-zeros state for one sample.

It is the squared magnitude of the all-zeros amplitude of the simulated statevector.

Parameters:

| Name      | Type      | Description                                          | Default    |
| --------- | --------- | ---------------------------------------------------- | ---------- |
| `weights` | `ndarray` | The parameter vector, which must be 1-D.             | *required* |
| `inputs`  | `ndarray` | The input features of one sample, which must be 1-D. | *required* |

Returns:

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

### `QiskitConfig`

Device configuration for the Qiskit backend.

Pass it to `Circuit(provider=QiskitConfig(...))`, or register it under a name with `register()` to use it again.

Parameters:

| Name    | Type  | Description | Default                                                                                                                                                                                                                                                                                            |
| ------- | ----- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `shots` | \`int | None\`      | None computes exact expectation values with Statevector. Finite-shot sampling is not supported on this backend yet, and any other value makes the compilation raise NotImplementedError. For sampling, use the Qiskit Runtime backend, which can also run locally on a fake device. 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                               |
| ----------------- | ----------------------------------------- |
| `'QiskitBackend'` | The QiskitBackend for this configuration. |
