Usage Guide¶
This guide introduces the core workflow of QC Executor — building a backend agnostic circuit and observable, creating an executor through the factory, and evaluating it — followed by a basic, runnable example for each backend.
Backend examples
Core building blocks¶
Every workflow uses three backend-independent objects from the package root:
QuantumCircuitA backend-agnostic circuit, constructed with a Qiskit-like gate API (
h(),cx(),ryy(), …). Gate angles may be plain numbers or symbolic parameter expressions.QuantumOperatorAn observable expressed as a weighted sum of Pauli strings, e.g.
QuantumOperator(["ZI", "IZ"], [1.0, 1.0]). Coefficients may also be symbolic.ParametersA named, indexable vector of free parameters used to build symbolic gate angles and observable coefficients.
Parameters("x", 2)createsx[0]andx[1].
from qc_executor import QuantumCircuit, QuantumOperator, Parameters
x = Parameters("x", 1)
p = Parameters("p", 2)
qc = QuantumCircuit(2)
qc.h(0)
qc.ryy(0, 1, p[0] * x[0]) # symbolic gate angle
observable = QuantumOperator(["ZI", "IZ"], [1.0, 1.0])
The factory: Executor¶
Executor is a factory, not something you
instantiate. Calling Executor() raises TypeError. Instead, you create a
concrete backend executor with Executor.create:
from qc_executor import Executor
# Which backends are installed in this environment?
print(Executor.available_backends())
# e.g. ['pauli_propagation', 'pennylane', 'qiskit', 'qulacs']
# Create an executor by backend name
executor = Executor.create("qiskit", shots=1024, seed=42)
The first positional argument (target) is usually a backend name, but it can
also be a backend object — for example a Qiskit BackendV2 instance — in
which case the matching plugin is auto-detected:
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
executor = Executor.create(FakeManilaV2(), shots=2048) # -> QiskitExecutor
All remaining keyword arguments are forwarded to the backend constructor. The
options shared by every backend (defined on
ExecutorBase) are:
Parameter |
Description |
|---|---|
|
Number of measurement shots. |
|
Random seed for reproducible sampling. |
|
Path to a log file. |
|
|
|
Enable in-memory caching of results. |
|
Directory used for caching. Defaults to |
|
Maximum number of cached entries ( |
Backend-specific options (such as the Qiskit execution_mode or the
PennyLane device backend name) are documented on each backend’s page and in
the API Reference.
Switching backends¶
An executor’s configuration can be transferred to another backend with
switch_backend, optionally
overriding individual settings:
qiskit_executor = Executor.create("qiskit", shots=1024, seed=42)
# Same shots/seed, different backend
pennylane_executor = qiskit_executor.switch_backend("pennylane")
# Switch and override
qulacs_executor = qiskit_executor.switch_backend("qulacs", shots=2048)
Common operations¶
Every executor exposes the same evaluation interface, regardless of backend.
Free parameters are supplied as keyword arguments, either in vector form
(x=[0.1, 0.2]) or indexed form (x[0]=0.1, x[1]=0.2).
Method |
Returns |
|---|---|
Expectation value(s) of the observable for the circuit. |
|
|
Gradient(s) of the expectation value w.r.t. the requested parameters. |
Measurement sample counts (requires |
|
Statevector of the circuit. |
|
Convert a generic circuit/operator into the backend-native form. |
executor = Executor.create("qiskit", seed=0, shots=10000)
value = executor.expectation_value(qc, observable, x=[0.1], p=[0.3])
grads = executor.expectation_value_derivatives(
qc, observable, "x", "p", x=[0.1], p=[0.3]
)
The pages that follow show a complete basic-usage example for each backend.
They mirror the runnable notebooks in the examples/ directory of the
repository.