API Reference

This reference documents the public API: the Executor factory, the shared executor interface, the backend-agnostic building blocks, and each backend plugin.

The Executor factory

Executor is the entry point for creating backend executors. It is a factory and cannot be instantiated directly — use create().

class qc_executor.factory.Executor[source]

Bases: object

Factory class for creating executor instances based on backend name.

This class provides a plugin-based architecture for executor backends. Backends can be registered using the @Executor.register() decorator or discovered automatically via entry points.

Example

>>> executor = Executor.create("qiskit", shots=1024)
>>> backends = Executor.available_backends()
>>> print(backends)  # ['qiskit', 'pennylane', 'qulacs']
classmethod register(name)[source]

Decorator to register a backend implementation.

Parameters:

name (str) – The name of the backend (e.g., “qiskit”, “pennylane”, “qulacs”)

Return type:

Callable[[Type[ExecutorBase]], Type[ExecutorBase]]

Returns:

Decorator function that registers the backend class

Raises:

TypeError – If the decorated class does not inherit from ExecutorBase

Example

>>> @Executor.register("qiskit")
... class QiskitExecutor(ExecutorBase):
...     pass
classmethod create(target, **kwargs)[source]

Create an executor instance for the specified backend.

Parameters:
  • target (str | Any) – Name of the backend (e.g., “qiskit”, “pennylane”, “qulacs”). May also be a Qiskit Backend / BackendV2 instance, in which case the "qiskit" executor is used automatically and the object is forwarded as backend=<instance>. An already constructed ExecutorBase instance is returned unchanged (no **kwargs allowed in that case).

  • **kwargs – Configuration parameters passed to the backend constructor

Return type:

ExecutorBase

Returns:

An instance of the requested backend executor

Raises:

ValueError – If the backend is not found or not installed

Example

>>> executor = Executor.create("qiskit", shots=1024, seed=42)
>>> executor = Executor.create("pennylane", shots=1000)
classmethod available_backends()[source]

Get a list of available (installed) backends.

Return type:

list[str]

Returns:

List of backend names that can be used with create()

Example

>>> backends = Executor.available_backends()
>>> print(backends)  # ['qiskit', 'pennylane', 'qulacs']
classmethod switch_backend(executor, backend, **overrides)[source]

Switch an executor to a different backend while preserving its configuration.

Creates a new executor instance with the specified backend, copying the current configuration and applying any overrides.

Parameters:
  • executor (ExecutorBase) – The existing executor whose configuration should be copied.

  • backend (str | Any) – Name of the backend to switch to (e.g., "qiskit", "pennylane", "qulacs"). May also be a Qiskit Backend / BackendV2 instance, in which case the "qiskit" executor is used automatically.

  • **overrides – Configuration parameters to override (e.g., shots=2048)

Returns:

New executor instance with the specified backend

Return type:

ExecutorBase

Example

>>> executor = Executor.create("qiskit", shots=1024, seed=42)
>>> pennylane_executor = Executor.switch_backend(executor, "pennylane")
>>> # pennylane_executor has shots=1024, seed=42
>>>
>>> # Override specific parameters
>>> qulacs_executor = Executor.switch_backend(executor, "qulacs", shots=2048)
>>> # qulacs_executor has shots=2048, seed=42
>>>
>>> # Switch to a real IBM Quantum backend
>>> from qiskit_ibm_runtime import QiskitRuntimeService
>>> service = QiskitRuntimeService()
>>> ibm_backend = service.least_busy(operational=True, simulator=False)
>>> ibm_executor = Executor.switch_backend(executor, ibm_backend)

Shared executor interface

All backend executors inherit from ExecutorBase, which defines the common configuration options (passed through Executor.create) and the evaluation interface shared by every backend.

class qc_executor.base.executor_base.ExecutorBase(backend=None, shots=None, seed=None, log_file=None, log_level='WARNING', caching=None, cache_dir='cache', max_cache_size=4096)[source]

Bases: ABC

Base class for quantum circuit executors.

Parameters:
  • shots (int | None, optional) – Number of shots for sampling.

  • seed (int | None, optional) – Random seed for reproducibility.

  • log_file (str | None, optional) – Path to the log file.

  • log_level (str, optional) – Logging level (for example "DEBUG", "INFO", "WARNING", "ERROR").

  • caching (bool | None, optional) – Whether to cache computation results in memory.

  • cache_dir (str, optional) – Directory for caching.

  • max_cache_size (int | None, optional) – Maximum number of entries kept in each in-memory cache; None makes them unbounded.

  • backend (Any)

property shots: int | None

Return the number of shots.

property remote: bool

Return True if the execution access a remote backend.

get_config()[source]

Get the current executor configuration.

Returns:

Dictionary containing the executor configuration parameters

(shots, seed, log_file, log_level, caching, cache_dir, max_cache_size)

Return type:

dict

Example

>>> executor = Executor.create("qiskit", shots=1024, seed=42)
>>> config = executor.get_config()
>>> print(config)  # {'shots': 1024, 'seed': 42, ...}
switch_backend(backend, **overrides)[source]

Switch to a different backend while preserving configuration.

Delegates to Executor.switch_backend.

Parameters:
  • backend (Any) – Name of the backend (e.g., "qiskit", "pennylane") or a backend instance for auto-detection.

  • **overrides – Configuration parameters to override (e.g., shots=2048)

Returns:

New executor instance with the specified backend

Return type:

ExecutorBase

expectation_value(circuit, observable, **parameters)[source]

Calculate the expectation value of the observable with respect to the circuit.

Parameters:
  • circuit (QuantumCircuitBase | List[QuantumCircuitBase]) – The quantum circuit or a list of circuits.

  • observable (QuantumOperatorBase | List[QuantumOperatorBase]) – The quantum observable or a list of observables.

  • parameters – Additional values for the free parameters of the circuit(s) and the observable(s) given as keyword arguments. Both vector-style keys (e.g., x=[0.1, 0.2]) and indexed keys (e.g., x[0]=0.1, x[1]=0.2) are accepted and normalized.

Returns:

The expectation value either as a single float or as a

numpy array if multiple circuits/observables are provided.

Return type:

float | np.array

expectation_value_derivatives(circuit, observable, *derivative, **parameters)[source]

Calculate the derivatives of the expectation value with respect to the parameters of the circuit.

The return format and the ordering below are part of the public API; downstream consumers rely on both. The full gradient of a circuit is obtained by supplying all of its parameter-vector names (see QuantumCircuitBase.parameter_vector_names) as derivative arguments.

Parameters:
  • circuit (QuantumCircuitBase | List[QuantumCircuitBase]) – The quantum circuit or a list of circuits.

  • observable (QuantumOperatorBase | List[QuantumOperatorBase]) – The quantum observable or a list of observables. Lists of circuits and observables are evaluated combinatorially: every circuit is paired with every observable. Observable lists are handled natively by each backend; a circuit list is expanded here.

  • derivative – The parameter(s) with respect to which the derivative is calculated.

  • parameters – Additional values for the free parameters of the circuit(s) and the observable(s) given as keyword arguments. Both vector-style keys (e.g., x=[0.1, 0.2]) and indexed keys (e.g., x[0]=0.1, x[1]=0.2) are accepted and normalized.

Returns:

The derivative of the expectation value:
  • single float/array if one derivative parameter is requested

  • dictionary mapping parameter names to gradient arrays if multiple parameters are requested

A list input adds a leading axis per list: (n_circuits, ...) for a circuit list, (n_observables, ...) for an observable list, and (n_circuits, n_observables, ...) for both.

Entries within each parameter vector are ordered by numeric element index, i.e. theta[2] precedes theta[10].

Return type:

float | np.array | dict

sample(circuit, **parameters)[source]

Computes samples of the quantumstate of the given circuit.

Bitstring keys use the big-endian convention q[0]q[1]...q[n-1] (qubit 0 is the leftmost character).

Parameters:
  • circuit (QuantumCircuitBase | List[QuantumCircuitBase]) – The quantum circuit or a list of circuits.

  • parameters – Additional values for the free parameters of the circuit(s) given as keyword arguments. Both vector-style keys (e.g., x=[0.1, 0.2]) and indexed keys (e.g., x[0]=0.1, x[1]=0.2) are accepted and normalized.

Returns:

The sampled results either as a single dictionary or a

list of dictionaries if multiple circuits are provided.

Return type:

dict | List[dict]

statevector(circuit, **parameters)[source]

Computes the statevector of the quantum circuit.

Amplitudes use the big-endian basis ordering: index i encodes qubit 0 as the most significant bit.

Parameters:
  • circuit (QuantumCircuitBase | List[QuantumCircuitBase]) – The quantum circuit or a list of circuits.

  • parameters – Additional values for the free parameters of the circuit(s) given as keyword arguments. Both vector-style keys (e.g., x=[0.1, 0.2]) and indexed keys (e.g., x[0]=0.1, x[1]=0.2) are accepted and normalized.

Returns:

The statevector of the circuit(s).

Return type:

np.ndarray

probabilities(circuit, *, cutoff=0.0, **parameters)[source]

Compute the measurement probabilities of a circuit.

With shots=None the probabilities are exact (derived from the statevector); otherwise they are estimated from sampled counts.

Parameters:
  • circuit (QuantumCircuitBase) – A single quantum circuit.

  • cutoff (float, optional) – Only probabilities strictly greater than this threshold are returned. The default of 0.0 omits exact zeros only, matching what the backends report natively; pass a larger value to keep the result sparse for many qubits.

  • parameters – Values for the free parameters of the circuit given as keyword arguments. Passing more than one parameter set (the same batching convention as expectation_value()) is supported on backends whose statevector()/sample() support it.

Returns:

Mapping of basis-state index (big-endian ordering, qubit 0 = most significant bit) to probability - one mapping for a single parameter set, or a list of mappings, one per set, for a batch of parameter sets.

Return type:

Dict[int, float] | List[Dict[int, float]]

Raises:

ValueError – If a list of circuits is passed.

transpile_circuit(circuit)[source]

Transpile the circuit for execution on this executor’s backend.

Subclasses may override _transpile_circuit() to apply backend-specific optimisations (e.g. gate decomposition, qubit routing). When a list of circuits is provided, each circuit is transpiled and cached individually.

Parameters:

circuit (QuantumCircuitBase | List[QuantumCircuitBase]) – The quantum circuit or a list of circuits to transpile.

Returns:

The transpiled

circuit(s).

Return type:

QuantumCircuitBase | List[QuantumCircuitBase]

transpile_operator(operator, **options)[source]
Overloads:
  • self, operator (QuantumOperatorBase), options (Any) → QuantumOperatorBase

  • self, operator (List[QuantumOperatorBase]), options (Any) → List[QuantumOperatorBase]

Parameters:
  • operator (QuantumOperatorBase | List[QuantumOperatorBase])

  • options (Any)

Return type:

QuantumOperatorBase | List[QuantumOperatorBase]

Transpile the operator for execution on this executor’s backend.

Subclasses may override _transpile_operator() to apply backend-specific conversions (e.g., to wrapper types). When a list of operators is provided, each operator is transpiled and cached individually.

Parameters:
  • operator (QuantumOperatorBase | List[QuantumOperatorBase]) – The quantum operator or a list of operators to transpile.

  • **options – Backend-specific transpilation options, forwarded to _transpile_operator(). The Pauli-propagation backend uses this for symmetry_strategy.

Returns:

The transpiled

operator(s).

Return type:

QuantumOperatorBase | List[QuantumOperatorBase]

abstractmethod classmethod get_accepted_backend_types()[source]

Return a list of backend object types accepted by this executor.

This is used for auto-detection when a non-string backend is passed to Executor.create(). If the backend object is an instance of any of the returned types, this executor will be selected automatically.

Returns:

List of accepted backend types

(e.g., Qiskit Backend / BackendV2 classes)

Return type:

List[type]

classmethod get_accepted_backend_aliases()[source]

Return string aliases accepted by this executor.

This optional list is used by Executor.create() when a string target is not a registered backend name. The factory resolves aliases to the owning plugin and forwards the original string via backend=<target>.

Returns:

String aliases accepted by the executor.

Return type:

List[str]

Core building blocks

Backend-agnostic circuit, observable, and parameter types from the package root.

class qc_executor.quantum_circuit.QuantumCircuit(num_qubits, num_clbits=0, *, _ir=None)[source]

Bases: QuantumCircuitBase

A quantum circuit that is not tied to any quantum framework.

Parameters:
  • num_qubits (int) – Number of qubits in the circuit.

  • num_clbits (int) – Number of classical bits for mid-circuit measurement.

  • _ir (CircuitIR | None)

property qiskit_circuit: Any

The circuit compiled to Qiskit.

Provided so backends that still consume Qiskit objects keep working while they are migrated onto the IR. Requires the qiskit extra.

Returns:

The equivalent qiskit.QuantumCircuit.

classmethod from_qiskit(qiskit_circuit)[source]

Import a Qiskit circuit into the framework-independent IR.

The circuit’s instructions are translated into the instruction store, so the result runs on every backend – unlike QiskitCircuit.from_qiskit, which only carries a pre-built circuit for the Qiskit backend and is the right tool for ISA-transpiled circuits. Requires the qiskit extra.

Parameters:

qiskit_circuit (Any) – The qiskit.QuantumCircuit to import.

Return type:

QuantumCircuit

Returns:

A new circuit holding the translated instructions.

Raises:

UnsupportedGateError – If the circuit is transpiled or contains an instruction the IR cannot express; see qiskit_to_ir().

class qc_executor.quantum_operator.QuantumOperator(paulis=None, coeffs=None, num_qubits=None, *, _ir=None)[source]

Bases: QuantumOperatorBase

A weighted sum of Pauli strings, not tied to any quantum framework.

Qubit q is character q of the label, so QuantumOperator(["ZI"], [1.0]) measures Z on qubit 0.

Parameters:
  • paulis (Optional[Sequence[str]]) – Pauli labels making up the operator.

  • coeffs (Optional[Sequence[Any]]) – One coefficient per label; numbers or SymPy expressions.

  • num_qubits (int | None) – Width, required only when no labels are given.

  • _ir (PauliIR | None)

property qiskit_operator: Any

The operator translated to Qiskit.

Provided so backends that still consume Qiskit objects keep working while they are migrated onto the shared representation. Requires the qiskit extra.

Returns:

The equivalent qiskit.quantum_info.SparsePauliOp.

class qc_executor.parameters.Parameters(name, length=0)[source]

Bases: Sequence[Parameter]

An ordered collection of Parameter elements sharing a name.

Behaves like a sequence, so len(), indexing, slicing and iteration all work:

x = Parameters("x", 3)
angle = x[0] * 2 + x[1]
Parameters:
  • name (str) – Name shared by all elements, e.g. "theta".

  • length (int) – Initial number of elements.

property name: str

The name shared by every element.

property params: List[Parameter]

The contained elements. Treat as read-only.

index(value, start=0, stop=None)[source]

Return the position of value within the vector.

Return type:

int

Parameters:
  • value (Any)

  • start (int)

  • stop (int | None)

resize(length)[source]

Grow or shrink the vector to length elements.

Growing preserves existing element identities, so expressions already built from this vector stay valid.

Parameters:

length (int) – The new number of elements.

Return type:

None

Backend plugins

Each plugin provides an executor plus native circuit/operator wrappers. You normally obtain an executor through Executor.create("<name>") rather than instantiating these classes directly, but their public classes are documented on the per-plugin pages below.

qc_executor.qiskit

Qiskit backend for the executor framework.

qc_executor.pennylane

PennyLane backend for Executor.

qc_executor.qulacs

Qulacs backend for Executor.

qc_executor.pauli_propagation

Pauli Propagation Package for Quantum Computing.