Skip to content

pennylane_backend

eigenkit.core.backends.pennylane_backend

The PennyLane backend.

It declares gradient_method = "native": the PyTorch interface of PennyLane carries the gradients through the tape, so the parameter-shift rule is not needed here.

compile() builds the device, both qnodes (one for NumPy and one for PyTorch) and the Pauli operators once. Each run() only binds the parameters into the cached qnodes. A finite number of shots is set on each qnode with qml.set_shots, because passing shots= to qml.device was deprecated in PennyLane 0.43.

Example
from eigenkit import Circuit, Encoding, Variational, all_z

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

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

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

circuit = Circuit(
    blocks=blocks,
    observables=all_z(4),
    provider=PennyLaneConfig(device_name="lightning.qubit"),
)

This backend needs the pennylane extra.

PennyLaneBackend

The provider for PennyLane devices. It is registered as "pennylane".

It is internal: you select this backend with provider="pennylane" or by passing a PennyLaneConfig, not by building this class.

capabilities property

What this backend supports.

It runs every gate, evaluates a batch of inputs in one call, can sample a finite number of shots, and has no limit on the number of qubits. It also provides the two features that Iterative Quantum Amplitude Estimation (IQAE) needs: the dense unitary of a callable oracle, through qml.matrix, and sampling of the ancilla qubit by the provider, for shot_mode="provider". See Capabilities.

__init__(config=None, name='pennylane')

Build the backend from a device configuration.

Parameters:

Name Type Description Default
config PennyLaneConfig

The device settings. Default: None, which uses PennyLaneConfig().

None
name str

The registry name, used in error messages. Default: "pennylane".

'pennylane'

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
PennyLaneCompiled

The prepared circuit, as a PennyLaneCompiled object.

PennyLaneCompiled

Bases: CompiledCircuit

A circuit prepared for PennyLane.

It is internal: PennyLaneBackend.compile() builds it and returns it, and it is never built directly. It has a run_torch() method, so the PyTorch interface differentiates through PennyLane itself instead of falling back to the parameter-shift rule.

__init__(circuit, observables, config)

Prepare the circuit for repeated evaluation.

PennyLaneBackend.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 PennyLaneConfig

The device settings.

required

jacobian(weights, inputs, *, need_input_grad=False)

Compute the gradient with PennyLane, using the configured diff_method.

The gradient code of the core package looks for a jacobian method, and prefers it to its own parameter-shift rule, which works on any backend. Here PennyLane differentiates the gate angles with its own engine (adjoint, backpropagation or parameter shift, as diff_method selects). These gate-angle gradients are then mapped onto the weights and inputs with the shared symbolic chain-rule factors, so angles built with Scale, Multiply, Sum or Negate are handled. It takes a single sample (1-D) only, and the caller loops over a batch.

Parameters:

Name Type Description Default
weights ndarray

The parameter vector (1-D).

required
inputs ndarray

The input features of one sample (1-D).

required
need_input_grad bool

If True, also compute the jacobian with respect to the inputs. Default: False.

False

Returns:

Name Type Description
weight_jacobian ndarray

The jacobian with respect to the weights.

input_jacobian ndarray | None

The jacobian with respect to the inputs, or None when need_input_grad is False.

probabilities(weights, inputs)

Return the full measurement distribution over the 2**n_qubits basis states.

Qubit 0 is the most significant bit. The distribution comes from qml.probs, through a qnode that is built on first use and then cached.

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
ndarray

The probabilities, of shape (2**n_qubits,).

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.

run_torch(weights, inputs)

Evaluate the circuit on PyTorch tensors, keeping the result on the tape.

This is the path of native automatic differentiation: the gradients flow through the simulator itself instead of through the parameter-shift fallback.

Parameters:

Name Type Description Default
weights Tensor

The parameter vector, 1-D or batched.

required
inputs Tensor

The input features, 1-D or batched.

required

Returns:

Type Description
Tensor

A PyTorch tensor of expectation values, which can still be differentiated.

statevector(weights, inputs, initial_state=None)

Return the full complex statevector, computed with qml.state().

Qubit 0 is the most significant bit. initial_state is added at the start of the circuit as a qml.StatePrep, so the evolution starts from that state instead of |0…0⟩. A 2-D inputs batch returns an array of shape (B, 2**n_qubits). The batch is evaluated in a loop, because reading the state does not use the fast path of parameter broadcasting. This method needs exact mode, because qml.state is not defined with a finite number of shots.

Parameters:

Name Type Description Default
weights ndarray

The parameter vector (1-D).

required
inputs ndarray

The input features: 1-D for one sample, or 2-D with a leading batch axis.

required
initial_state ndarray | None

The state to start 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.

Raises:

Type Description
NotImplementedError

If the configuration sets a finite number of shots.

zero_state_probability(weights, inputs)

Return the probability of measuring |0…0⟩ after the circuit has run.

On first use, it builds a separate qnode that returns qml.probs(...), and the method returns entry 0 of that distribution. The qnode uses the same device as the expectation-value qnodes.

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].

PennyLaneConfig dataclass

Device settings, used for every qml.device() call.

Pass it directly to Circuit(provider=PennyLaneConfig(...)), or pass it to register() under a name to reuse it.

Parameters:

Name Type Description Default
device_name str

The identifier of the PennyLane simulator plugin: "default.qubit", "lightning.qubit", "lightning.gpu", or any other installed device. Default: "default.qubit".

'default.qubit'
shots int | None

None computes exact expectation values, and a positive integer samples that many shots for each expectation value. Default: None.

None
diff_method str

The PennyLane differentiation method. With "best", PennyLane chooses for each device, usually backpropagation on a simulator and the parameter-shift rule on hardware. Default: "best".

'best'

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
'PennyLaneBackend'

The PennyLaneBackend for this configuration.