## `eigenkit.core.backends.qiskit_runtime_backend`

The Qiskit Runtime backend, for IBM Quantum hardware.

Qiskit and qiskit-ibm-runtime are optional dependencies (`pip install eigenkit[qiskit]`). They are imported only when they are needed, so the rest of the library works without them. If Qiskit is missing, `compile()` raises a clear `ImportError`. If qiskit-ibm-runtime is missing, the same kind of error comes when it is first needed: when `compile()` looks up a backend by name, or when the first job is submitted.

The backend runs on real IBM backends (Heron devices such as `ibm_fez`, `ibm_marrakesh` and `ibm_torino`), on the device that `service.least_busy()` chooses (`backend_name="least_busy"`), and, for local testing, on the fake backends with noise models from `qiskit_ibm_runtime.fake_provider` and on `qiskit_aer.AerSimulator`.

`QiskitRuntimeConfig(primitive=...)` chooses one of two primitives:

- `"estimator"`, the default, computes the expectation values of Pauli sums with `EstimatorV2`, which does the basis rotation and the averaging on the server. Each observable is one Primitive Unified Bloc (PUB) of a single job, and only the numbers come back.
- `"sampler"` computes the same expectation values from raw histograms of bitstrings with `SamplerV2`. The Pauli terms of the observables are sorted into qubit-wise commuting measurement groups, one circuit is run for each group, and the counts are reduced locally (see the `_sampling` module). There is one PUB per *group* instead of one per observable, and the shot budget is explicit. This is what you want when the shot cost of a result is itself what you measure.

`sample()` and `probabilities()` always use `SamplerV2`, whatever the configured primitive, because they are sampling operations and `EstimatorV2` returns no bitstrings. `primitive` only chooses how the expectation values are computed.

`submit()` runs `run`, `sample` or `probabilities` without blocking (see `QiskitRuntimeCompiled.submit_methods`), and it can tag the IBM job so that you can find it again. `attach()` rebuilds a handle from the id of a job submitted earlier, for example after the process that submitted it restarted. The `result()` of either handle returns what the blocking method of the same name returns.

`zero_state_probability()` and its batched form `zero_state_probabilities()` are used by quantum kernels. They run one `SamplerV2` job, measured in the `Z` basis, for the whole batch. They are not `submit()` methods: `submit_zero_state_probabilities()` submits the batch without blocking, and `retrieve_zero_state_probabilities()` attaches to it again by its job id.

The credentials are looked up in this order, and the most explicit one wins:

1. `QiskitRuntimeConfig(token=..., channel=..., instance=...)`.
1. The environment variable `QISKIT_IBM_TOKEN`.
1. The saved account (`~/.qiskit/qiskit-ibm.json`).

The channel defaults to `"ibm_quantum_platform"`. The legacy `"ibm_quantum"` channel was retired with the old IBM Quantum Platform, and `QiskitRuntimeService` no longer accepts it at all.

For testing, pass a `FakeBackendV2` instance directly as `backend_instance`. No token or service is needed.

By default, `gradient_method = "none"`, because runs on a quantum processing unit (QPU) are too expensive for parameter-shift gradients: one backward step costs at least `2 * n_weights` jobs, each with the full shot count. The PyTorch wrapper raises a clear error on `.backward()`. Train on a simulator first, then use the trained weights on the QPU. `enable_gradients=True` in the configuration turns on parameter-shift gradients on the device, and compiling for a paid device then gives a `CostWarning` that states the cost of one backward pass.

`compile()` runs `qiskit.transpile(circuit, backend=target, optimization_level=N)` once and caches the transpiled circuit. For the estimator, it also caches the `SparsePauliOp` operators, mapped to the layout of the transpiled circuit. The sampler transpiles each measured circuit on its first use and caches it too. Each `run()` or `submit()` then only binds the parameter values in the PUBs that it passes to the primitive.

Example

```python
from eigenkit import Circuit, Encoding, Variational, all_z, register
from eigenkit.configs import QiskitRuntimeConfig

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

# by a registered name (this backend is opt-in, so register it first)
register("qiskit-runtime", QiskitRuntimeConfig(backend_name="ibm_fez"))
circuit = Circuit(blocks=blocks, observables=all_z(4), provider="qiskit-runtime")

# or with the configuration, when a device setting matters
circuit = Circuit(
    blocks=blocks,
    observables=all_z(4),
    provider=QiskitRuntimeConfig(backend_name="ibm_fez"),
)
```

It is opt-in, and it costs money. The first compile for a paid device gives a `CostWarning`, and `dry_run_info()` reports the shape of a run, including how many circuits a call runs, before you submit it.

### `QiskitRuntimeBackend`

The provider for IBM Quantum hardware through Qiskit Runtime.

It is opt-in: the name `"qiskit-runtime"` exists only after the caller registers it, for example with `register("qiskit-runtime", QiskitRuntimeConfig(...))`.

It costs money: the first compile for a paid device gives a CostWarning, and `dry_run_info()` reports the shape of a run beforehand. It does not estimate a price.

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

#### `capabilities`

Return what this backend supports.

It supports every gate except `AmplitudeEncoding` (state preparation), `QubitUnitary` and `ControlledQubitUnitary` (arbitrary unitaries) and `CPHASE`. It supports finite-shot sampling, which a quantum processing unit (QPU) always uses. It supports batching, because the primitives evaluate a batch of parameter values in one job when `weights` is 1-D and `inputs` is 2-D. It has no limit of its own on the number of qubits: the limit of the device applies. See Capabilities.

#### `gradient_method`

Return the gradient method, which depends on `enable_gradients`.

It is `"parameter_shift"` when the configuration sets `enable_gradients`, and `"none"` otherwise. A parameter-shift backward pass on a quantum processing unit (QPU) costs at least `2 * n_weights` jobs, each with the full shot count, so gradients are refused unless the caller opts in.

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

Build the backend from a device configuration.

Parameters:

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

#### `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                     |
| ----------------------- | ------------------------------- |
| `QiskitRuntimeCompiled` | A QiskitRuntimeCompiled handle. |

### `QiskitRuntimeCompiled`

Bases: `CompiledCircuit`

A circuit transpiled for an IBM Quantum backend.

This class is internal. It is built by QiskitRuntimeBackend.compile() and obtained from it, and it is never constructed directly. The circuit is transpiled once and cached (each measured circuit of the sampler on its first use), so `run()` and `submit()` only bind the parameter values. `submit()` returns a QiskitRuntimeJobHandle without blocking, and `attach()` rebuilds that handle from a job id.

#### `submit_methods = _SUBMIT_METHODS`

The methods `submit()` and `attach()` accept: `"run"`, `"sample"` and `"probabilities"`. `zero_state_probability` is not one of them: its batched async form is `submit_zero_state_probabilities()`. Any method added to this adapter's async path must also be added here, or callers that check this set will refuse it.

#### `__init__(circuit, observables, config, *, warn=True)`

Prepare the circuit for repeated evaluation.

`QiskitRuntimeBackend.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`      | `QiskitRuntimeConfig`  | The device settings.                                                                                                                     | *required* |
| `warn`        | `bool`                 | Whether to give the cost warnings for a paid device. It is False only for the shifted copies that compile_shifted builds. Default: True. | `True`     |

#### `attach(job_id, *, method='run')`

Rebuild the handle of a job submitted earlier from this circuit.

Use it to pick up a job from a process other than the one that submitted it, for example after a crash. The handle decodes results exactly as the handle that `submit()` returned would have, provided that the job was submitted from the same circuit, observables, primitive and `method`.

Parameters:

| Name     | Type  | Description                                                        | Default    |
| -------- | ----- | ------------------------------------------------------------------ | ---------- |
| `job_id` | `str` | The IBM job id, as returned by QiskitRuntimeJobHandle.job_id().    | *required* |
| `method` | `str` | The method that the job was submitted with, one of submit_methods. | `'run'`    |

Returns:

| Name     | Type        | Description                    |
| -------- | ----------- | ------------------------------ |
| `handle` | `JobHandle` | A handle for the existing job. |

Raises:

| Type         | Description                                                                                                                                                                                                                                                     |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ValueError` | If job_id is not made of 1 to 64 letters, digits, _ or -, if method is not in submit_methods, or if the backend is not an IBM Runtime backend with a service to look the job up in (a fake backend has none). In all these cases, the service is not contacted. |

#### `compile_shifted(circuit)`

Compile a copy of this circuit with one gate angle shifted.

The chain-rule gradient compiles one copy per shifted gate. Each copy runs on the device of this handle, never on a new `"least_busy"` choice, and is transpiled with the seed of this handle, so every term of the gradient comes from the same qubits. The compile of this handle already gave the cost warnings, so the copy gives none.

Parameters:

| Name      | Type          | Description          | Default    |
| --------- | ------------- | -------------------- | ---------- |
| `circuit` | `CircuitSpec` | The shifted circuit. | *required* |

Returns:

| Type                      | Description                                 |
| ------------------------- | ------------------------------------------- |
| `'QiskitRuntimeCompiled'` | A QiskitRuntimeCompiled handle for circuit. |

#### `counts(weights, inputs)`

Return the histogram in the computational basis for one sample.

It is always a `SamplerV2` job, whatever `primitive` the configuration names, because `EstimatorV2` has no bitstrings to return. It is one job of `shots` shots.

Parameters:

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

Returns:

| Name     | Type             | Description                                                                                                                     |
| -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `counts` | `dict[str, int]` | The number of shots for each measured bitstring. The first character of each key is qubit 0, which is the most significant bit. |

#### `dry_run_info()`

Report the size of a run, before anything is submitted.

It reports the target backend and whether it is a fake one, the primitive in use, the number of shots, the optimisation level, the transpiler seed set in the configuration, the numbers of logical and physical qubits, the gate counts and the depth of the transpiled circuit, the numbers of observables and of measurement groups, and how many circuits one call runs: one per observable with the estimator, and one per measurement group with the sampler.

`transpiled_gate_counts` and `transpiled_depth` describe the circuit that is actually submitted. With the estimator, this is the circuit without measurements, which carries its observables separately, so both are single values. With the sampler, there is one circuit per measurement group, with the basis rotation and the measurements added *before* transpiling, so that the layout can place them on the qubits that the circuit ran on. Both are then dictionaries keyed by basis, as in the IQM backend. Reporting the circuit without measurements there would understate a routed circuit, because the transpiler sees a different input and chooses a different layout.

Returns:

| Name   | Type   | Description                      |
| ------ | ------ | -------------------------------- |
| `info` | `dict` | The fields above, keyed by name. |

#### `probabilities(weights, inputs)`

Return the measurement distribution over all `2**n_qubits` basis states.

It is the estimate from the shot frequencies, not the exact distribution: on hardware, the basis states that were never sampled come back as exact zeros. It is limited to circuits of at most `_sampling.MAX_DENSE_QUBITS` (`24`) qubits. For a wider circuit, read `sample()` directly.

Parameters:

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

Returns:

| Name            | Type      | Description                                                   |
| --------------- | --------- | ------------------------------------------------------------- |
| `probabilities` | `ndarray` | The distribution, of shape (2\*\*n_qubits,), which sums to 1. |

#### `resources(measured=True)`

Report the resources that the transpiled circuit uses on this device.

Parameters:

| Name       | Type   | Description                                                                                                                                                                             | Default |
| ---------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `measured` | `bool` | If True, the default, report the circuit measured in the Z basis, which is what kernels and sampling submit. If False, report the circuit without measurements that the estimator runs. | `True`  |

Returns:

| Type   | Description                                                                                                                                                                                                                                                                                                                                                                                               |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dict` | A dictionary with backend_name, is_fake, n_logical_qubits, optimization_level, seed_transpiler, gate_counts, n_2q_gates, two_qubit_gate_counts, depth, depth_2q, n_2q_gates_unrouted (the same circuit on the native gates with all-to-all connectivity), routing_overhead_2q, physical_qubits, n_physical_qubits_device, and estimated_success_probability, computed from the error rates of the target. |

#### `retrieve_zero_state_probabilities(job_id)`

Attach again to a job that `submit_zero_state_probabilities()` submitted.

The job may have been submitted from another session.

Parameters:

| Name     | Type  | Description             | Default    |
| -------- | ----- | ----------------------- | ---------- |
| `job_id` | `str` | The IBM Quantum job id. | *required* |

Returns:

| Type                   | Description                                       |
| ---------------------- | ------------------------------------------------- |
| `ProbabilityJobHandle` | A handle whose result() is the probability array. |

Raises:

| Type                  | Description                                                                                                      |
| --------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `ValueError`          | If job_id is not made of 1 to 64 letters, digits, _ or -.                                                        |
| `NotImplementedError` | For a backend without a service to look the job up in, such as a fake backend or Aer, which keep no job history. |

#### `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. |

#### `sample(weights, inputs)`

Return the same histogram as `counts()`.

This is an alias of counts, under the name that the `Circuit.sample()` dispatch looks for.

Parameters:

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

Returns:

| Name     | Type             | Description                                      |
| -------- | ---------------- | ------------------------------------------------ |
| `counts` | `dict[str, int]` | The number of shots for each measured bitstring. |

#### `submit(weights, inputs, *, method='run', tags=None)`

Submit the circuit without blocking, and return a job handle.

Nothing blocks: `handle.result()` waits for the job and decodes it in the same way as the blocking method of the same name. For `"run"`, the handle returns expectation values with either primitive: the counts of the sampler are reduced when the result is collected, so the two paths look the same to the caller. `"sample"` and `"probabilities"` are always one `SamplerV2` job measured in the `Z` basis, whatever the configured primitive.

Parameters:

| Name      | Type                | Description                                                                                                                                                                                                                                               | Default                                                                                                                                                                                                                                                                                            |
| --------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `weights` | `ndarray`           | The parameter vector for one sample (1-D).                                                                                                                                                                                                                | *required*                                                                                                                                                                                                                                                                                         |
| `inputs`  | `ndarray`           | The input features for one sample (1-D).                                                                                                                                                                                                                  | *required*                                                                                                                                                                                                                                                                                         |
| `method`  | `str`               | What the job computes, one of submit_methods. "run", the default, measures the observables, like run(). "sample" returns the measurement histogram, like sample(). "probabilities" returns the distribution over every basis state, like probabilities(). | `'run'`                                                                                                                                                                                                                                                                                            |
| `tags`    | \`Mapping[str, str] | None\`                                                                                                                                                                                                                                                    | Tags to put on the IBM job, so that you can find it again later with QiskitRuntimeService.jobs(job_tags=[...]). Each one becomes the job tag "key=value", sorted by key. IBM allows at most 8 tags of at most 86 characters each. Keys and values must not be empty, and a key must not contain =. |

Returns:

| Name     | Type        | Description                     |
| -------- | ----------- | ------------------------------- |
| `handle` | `JobHandle` | A handle for the submitted job. |

Raises:

| Type         | Description                                                                                                                                                                        |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ValueError` | If method is not in submit_methods, if weights or inputs is not 1-D, or if tags breaks the IBM job tag limits. In all these cases, no primitive is built and nothing is submitted. |

#### `submit_zero_state_probabilities(weights, inputs)`

Submit the all-zeros probability of every row of `inputs` as one job.

It submits one `SamplerV2` job and returns without waiting. The circuit is transpiled once and measured in the `Z` basis, and every row binds one set of parameter values of the same Primitive Unified Bloc (PUB), so `B` kernel entries cost one job of `B * shots` shots. It works whatever `primitive` the configuration names.

Parameters:

| Name      | Type      | Description                              | Default    |
| --------- | --------- | ---------------------------------------- | ---------- |
| `weights` | `ndarray` | The parameter vector, which must be 1-D. | *required* |
| `inputs`  | `ndarray` | A batch, of shape (B, n_inputs).         | *required* |

Returns:

| Type                   | Description                                                      |
| ---------------------- | ---------------------------------------------------------------- |
| `ProbabilityJobHandle` | A handle whose result() is the probability array, of shape (B,). |

#### `transpiled_circuit(measured=True)`

Return the Qiskit circuit that this backend submits, to draw or inspect it.

Parameters:

| Name       | Type   | Description                                                                                                                                                                                                    | Default |
| ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `measured` | `bool` | If True, the default, return the circuit measured in the Z basis that sample(), probabilities() and the kernel path run. If False, return the transpiled circuit without measurements that the estimator runs. | `True`  |

Returns:

| Type               | Description                         |
| ------------------ | ----------------------------------- |
| `'QuantumCircuit'` | A transpiled qiskit.QuantumCircuit. |

#### `zero_state_probabilities(weights, inputs)`

Return the all-zeros probability of every row of `inputs`, from one job.

Parameters:

| Name      | Type      | Description                              | Default    |
| --------- | --------- | ---------------------------------------- | ---------- |
| `weights` | `ndarray` | The parameter vector, which must be 1-D. | *required* |
| `inputs`  | `ndarray` | A batch, of shape (B, n_inputs).         | *required* |

Returns:

| Type      | Description                                  |
| --------- | -------------------------------------------- |
| `ndarray` | The estimates from the shots, of shape (B,). |

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

Return the all-zeros probability for one sample, estimated from shots.

Parameters:

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

Returns:

| Type    | Description      |
| ------- | ---------------- |
| `float` | The probability. |

### `QiskitRuntimeConfig`

Bases: `SecretFieldsMixin`

Device configuration for the Qiskit Runtime backend.

There are two ways to choose the target backend:

- `backend_name` is looked up with `QiskitRuntimeService`. It needs credentials: a token, an environment variable or a saved account.
- `backend_instance` is a `BackendV2` that is used directly. It is useful for tests with a fake backend, or to pass any backend that is already configured.

Parameters:

| Name                   | Type        | Description                                                                                                                                                                                                                                                                                                                                                    | Default                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `backend_name`         | \`str       | None\`                                                                                                                                                                                                                                                                                                                                                         | The IBM backend name, for example "ibm_fez", or "least_busy" for the least busy operational device that the account can use, chosen once per compiled circuit. It is required unless backend_instance is set, and it is ignored when it is. Default: None.                                                                                                                                                                                                                                                                                                                                              |
| `backend_instance`     | `Any`       | A backend that is already configured. It takes precedence over backend_name. Default: None.                                                                                                                                                                                                                                                                    | `None`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `shots`                | `int`       | The number of shots per circuit run. Default: 1024.                                                                                                                                                                                                                                                                                                            | `1024`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `optimization_level`   | `int`       | The optimisation level passed to qiskit.transpile, from 0 to 3. Default: 1.                                                                                                                                                                                                                                                                                    | `1`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `seed_transpiler`      | \`int       | None\`                                                                                                                                                                                                                                                                                                                                                         | The seed of the random passes of the transpiler, mainly the SabreLayout and SabreSwap passes, which choose the layout and the routing. None, the default, draws a new seed for every compile, so a circuit that needs routing compiles to a different number of gates on every run. Within one compile, all the transpilations share the seed, including the shifted copies that a gradient on hardware compiles. Set it whenever two compilations must be comparable. Since compiling submits nothing, trying a few seeds and keeping the cheapest circuit is a cheap and fair way to choose a layout. |
| `primitive`            | `Primitive` | The Runtime primitive that computes the expectation values. "estimator", the default, uses EstimatorV2, with one Primitive Unified Bloc (PUB) per observable in each job. "sampler" uses SamplerV2, with one PUB per qubit-wise commuting measurement group, and reduces the raw counts locally. sample() and probabilities() use SamplerV2 with either value. | `'estimator'`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `group_commuting`      | `bool`      | Whether the sampler puts qubit-wise commuting Pauli terms into shared measurement circuits. False runs one circuit per term, which runs more circuits but keeps the shot budget of each term independent. The estimator ignores it. Default: True.                                                                                                             | `True`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `token`                | \`str       | None\`                                                                                                                                                                                                                                                                                                                                                         | The token passed to QiskitRuntimeService when backend_instance is None. With None, the backend uses QISKIT_IBM_TOKEN, then the saved account file. It is secret: it is never shown by repr(), and it is never saved in .eigenkit bundles, pickles or joblib checkpoints. After a load it is None, so set QISKIT_IBM_TOKEN.                                                                                                                                                                                                                                                                              |
| `channel`              | `str`       | The service channel: "ibm_quantum_platform" (the default), "ibm_cloud" or "local". The legacy "ibm_quantum" channel was retired, and QiskitRuntimeService no longer accepts it.                                                                                                                                                                                | `'ibm_quantum_platform'`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `instance`             | \`str       | None\`                                                                                                                                                                                                                                                                                                                                                         | The service instance, as a Cloud Resource Name (CRN) or a name, when one applies. Default: None.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `service_kwargs`       | `dict`      | Extra keyword arguments passed to QiskitRuntimeService, such as region, url or proxies.                                                                                                                                                                                                                                                                        | `dict()`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `poll_timeout_seconds` | `int`       | How long result() waits before it gives up, in seconds. Default: 3600.                                                                                                                                                                                                                                                                                         | `3600`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `enable_gradients`     | `bool`      | Whether to allow parameter-shift gradients on the device: PyTorch .backward(), jacobian() and gradient-based optimisers. It is off by default, because one backward pass costs at least 2 * n_weights times the jobs of a forward call. When it is on, compiling for a paid device gives a CostWarning that states this cost.                                  | `False`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

#### `__post_init__()`

Reject an unknown primitive when the configuration is built.

If the check waited for the first submission, the error would come as a confusing failure on a paid backend, after the transpilation and the cost warning.

#### `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                                      |
| ------------------------ | ------------------------------------------------ |
| `'QiskitRuntimeBackend'` | The QiskitRuntimeBackend for this configuration. |

### `QiskitRuntimeJobHandle`

A handle to a Qiskit Runtime job, whose `result()` blocks and decodes it.

`compiled.submit(weights, inputs)` and `compiled.attach(job_id)` return one of these. What `result()` returns depends on the `method` of the handle.

#### `method`

Return the method of the compiled circuit that this job runs.

It is `"run"`, `"sample"` or `"probabilities"`.

#### `__init__(job, n_observables, poll_timeout_seconds, reduce=None, counts=None, method='run', *, n_qubits=None)`

Wrap a submitted Runtime job as a job handle.

`QiskitRuntimeCompiled.submit()` and `QiskitRuntimeCompiled.attach()` build it, and it is not constructed directly.

Parameters:

| Name                   | Type         | Description                                                                                                                                 | Default                                                                                                                                                                                                                                                                  |
| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `job`                  | `RuntimeJob` | The IBM Runtime job returned by the primitive.                                                                                              | *required*                                                                                                                                                                                                                                                               |
| `n_observables`        | `int`        | The number of expectation values to expect back, which sets the shape of the result array.                                                  | *required*                                                                                                                                                                                                                                                               |
| `poll_timeout_seconds` | `int`        | How long result() waits before it gives up, in seconds.                                                                                     | *required*                                                                                                                                                                                                                                                               |
| `reduce`               | \`Callable   | None\`                                                                                                                                      | The function that turns the result of the primitive into the vector of expectation values. None reads the EstimatorV2 result of each Primitive Unified Bloc (PUB) directly, which is what the estimator submits. The sampler passes its reduction of the counts instead. |
| `counts`               | \`Callable   | None\`                                                                                                                                      | The function that takes the histograms out of the result of the primitive, one per submitted circuit. Only sampler jobs have histograms, because the estimator returns expectation values and never sees a bitstring. With None, counts() raises NotImplementedError.    |
| `method`               | `str`        | The method of the compiled circuit that the job runs, one of QiskitRuntimeCompiled.submit_methods. It decides how result() decodes the job. | `'run'`                                                                                                                                                                                                                                                                  |
| `n_qubits`             | \`int        | None\`                                                                                                                                      | The number of qubits of the circuit, which sets the size of the "probabilities" distribution.                                                                                                                                                                            |

Raises:

| Type         | Description                                                                                                                                                          |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ValueError` | If method is not in QiskitRuntimeCompiled.submit_methods, if method is "sample" or "probabilities" without counts, or if method is "probabilities" without n_qubits. |

#### `cancel()`

Ask IBM Quantum to cancel the job, without blocking.

#### `counts()`

Block until the job finishes, then return the raw histograms.

There is one histogram per measurement group. In each key, qubit 0 is the leftmost character, which is the most significant bit. A `"sample"` or `"probabilities"` job measured one circuit, so it has one histogram.

These are the numbers that the device returned, and result is these numbers reduced against the observables. Because both come from a single job, a run can be scored again offline, against different observables or with a different metric, without paying for it twice.

Raises:

| Type                  | Description                                                                                                                           |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `NotImplementedError` | For a "run" job on the estimator, which returns expectation values and never sees a bitstring. Set primitive="sampler" to get counts. |

#### `job_id()`

Return the IBM Quantum job id.

Use it to look the job up in the console or in `qiskit-ibm-runtime`.

#### `result()`

Block until the job finishes, then decode it by the `method` of the handle.

A handle from `attach()` decodes a job exactly as the handle that `submit()` returned would have.

Returns:

| Type      | Description      |
| --------- | ---------------- |
| \`ndarray | dict[str, int]\` |

Raises:

| Type         | Description                                                                                                                                                                                                                                                                 |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ValueError` | If the results of the job do not have the shape that the method and the circuit of this handle produce, for example because the handle was attached with the wrong method. Also, for "probabilities", if the circuit has more than \_sampling.MAX_DENSE_QUBITS (24) qubits. |

#### `status()`

Return the state of the job as IBM Quantum reports it, without blocking.

Examples of states are `"QUEUED"`, `"RUNNING"`, `"DONE"`, `"CANCELLED"` and `"ERROR"`.
