PennyLane backend¶
The PennyLane backend
(PennyLaneExecutor) runs
circuits on any PennyLane device and supports automatic differentiation.
pip install "qc-executor[pennylane]"
Basic usage¶
from qc_executor import Executor, QuantumCircuit, QuantumOperator, Parameters
# 1. Build a parametrized circuit
x = Parameters("x", 1)
p = Parameters("p", 2)
qc = QuantumCircuit(2)
qc.h(0)
qc.ryy(0, 1, p[0] * x[0])
# 2. Build a parametrized observable
p_obs = Parameters("p_obs", 2)
observable = QuantumOperator(["ZI", "IZ"], [p_obs[0], p_obs[1]])
# 3. Create the executor
executor = Executor.create("pennylane", seed=0, shots=10000)
pennylane_circuit = executor.transpile_circuit(qc)
# 4. Expectation value (the generic observable can be passed directly)
result = executor.expectation_value(
pennylane_circuit,
observable,
x=[0.1],
p=[0.3],
p_obs=[0.5, 0.6],
)
print("Expectation value:", result)
# 5. Gradients
grads = executor.expectation_value_derivatives(
pennylane_circuit,
observable,
"x",
"p",
"p_obs",
x=[0.1],
p=[0.3],
p_obs=[0.5, 0.6],
)
print(grads)
# 6. Statevector (analytic) and samples
Executor.create("pennylane").statevector(pennylane_circuit, x=[0.8], p=[0.5])
executor.sample(pennylane_circuit, x=[0.8], p=[0.5])
Selecting a device¶
The backend argument is the PennyLane device name (default
"default.qubit") or an already-instantiated
qml.devices.Device. Additional positional/keyword arguments are forwarded to
qml.device:
# By device name
executor = Executor.create("pennylane", backend="default.mixed", shots=1000, seed=42)
# From a pre-built device instance
import pennylane as qml
dev = qml.device("lightning.qubit", wires=2)
executor = Executor.create("pennylane", backend=dev)
Note
The device is created once at construction time and is never recreated, so it
must provide enough wires for every circuit you execute. When passing a device
instance, executor-level shots/seed overrides are rejected — configure
them on the device instead.