Skip to content

qiskit_backend

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
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 property

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().

None
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 |0…0⟩. Default: None.

None

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 dataclass

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.

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.