Qdislib.core.backend package¶
The pluggable execution layer. Every target – a CPU simulator (Qibo / Qiskit /
CUDA-Q), a GPU, or a real QPU – is a BaseBackend;
the cutting algorithms never branch on the backend, they hand each subcircuit to
the object that build_execution_backend()
selects from the software / gpu / qpu arguments.
Submodules¶
Qdislib.core.backend.base_backend module¶
Backend abstraction for Qdislib.
The cutting algorithms are backend-agnostic: they produce subcircuits and ask a
backend to sample them (counts) or estimate an observable (expectation
value). A backend is anything implementing BaseBackend – a simulator
(Aer, Qibo, CUDA-Q) or real hardware (IQM, IBM, a BSC QPU). New backends are
registered in registry and can be added by users
without touching the algorithms.
- class Qdislib.core.backend.base_backend.BackendConfig(num_qubits, extra=<factory>)[source]¶
Bases:
objectStatic configuration for a backend (its size and any extra options).
- class Qdislib.core.backend.base_backend.BaseBackend(name, config)[source]¶
Bases:
ABCCommon interface for all Qdislib backends.
FIFO queue management is centralised here via the Template Method pattern: subclasses implement
_execute_samples/_execute_estimator/transpile(the hooks), whilerun_samples/run_estimatororchestrate the full enqueue -> execute -> dequeue lifecycle. The queue length is whatQdBackEnduses to load-balance.- evaluate_expectation(dag, num_qubits, prep_qubits=(), shots=1024, method='automatic')[source]¶
Evaluate the expectation of a Qdislib subcircuit DAG on this backend.
This is the seam the cutting algorithms delegate to instead of branching on the backend name: they hand over the backend-neutral DAG (its Pauli observable rides along as
Observable Imarkers) and the set ofprep_qubits(cut qubits measured for the decomposition, whose sign is recovered from the backend’s own mid-circuit outcome). The backend builds its native circuit, executes it, and reconstructs the value. Backends that only supportrun_samples()/run_estimator()may leave this unimplemented.- Parameters:
- Return type:
- Returns:
The subcircuit’s expectation value.
- evaluate_joint_counts(dag, num_qubits, cut_point_qubits=(), shots=1024, seed=None)[source]¶
Sample a gate-cut subcircuit, capturing the JOINT final/cut-point outcomes.
The seam the sampling reconstruction delegates to – the distribution counterpart of
evaluate_expectation(). Gate-cut sampling needs, per shot, the final measurement and the mid-circuit cut-point outcomes ofcut_point_qubitskept correlated, so a cut qubit that keeps evolving after the cut still reconstructs correctly (its final bit no longer equals its cut-point bit). Returns{(final_bits, cut_point_bits): count}withfinal_bitsqubit-0-first over the component andcut_point_bitsovercut_point_qubitsin order.Backends whose execution yields only aggregated final counts (most real QPUs) cannot report the mid-circuit outcome and leave this unimplemented.
- Parameters:
- Return type:
- Returns:
{(final_bits, cut_point_bits): count}.
- evaluate_samples(dag, num_qubits, shots=1024, seed=None)[source]¶
Sample a Qdislib subcircuit DAG and return counts in a standard convention.
Used by the sampling reconstruction of gate cutting. Every backend returns keys as qubit-0-first bitstrings (
key[i]is qubiti), regardless of the SDK’s native endianness, so the reconstruction combines components uniformly.
- property queue_snapshot: list[Job]¶
Return an immutable copy of the current queue (useful for logging / monitoring).
- run_estimator(circuit, transpile, observable, shots)[source]¶
Compute the expectation value of an observable, updating the FIFO queue.
- Return type:
- class Qdislib.core.backend.base_backend.ExpectationJobResult(expectation_value, shots, backend_name, job_id, obs='', metadata=<factory>)[source]¶
Bases:
objectResult of an estimator run: an expectation value plus provenance metadata.
- class Qdislib.core.backend.base_backend.Job(job_id, kind, n_qubits, shots, submitted_at=<factory>)[source]¶
Bases:
objectA unit of work tracked in a backend’s FIFO queue.
- class Qdislib.core.backend.base_backend.SampleJobResult(counts, backend_name, shots, job_id, metadata=<factory>)[source]¶
Bases:
objectResult of a sampling run: measurement counts plus provenance metadata.
- Qdislib.core.backend.base_backend.SupportedCircuit¶
A circuit in any of the supported source formats (Qiskit / Qibo / a CUDA-Q kernel or its
(dag, num_qubits)payload). Annotated asAnyso importing the backend layer never pulls in a specific SDK –import Qdislibmust work with only one backend installed (Qibo-only / Qiskit-only / CUDA-Q-only).
Qdislib.core.backend.registry module¶
Lazy, user-extensible registry of Qdislib backends.
Backends are registered by name -> (module path, class name) and imported only on first use, so a backend’s optional third-party dependencies (qiskit-aer, iqm, …) are not required until that backend is actually built.
- Qdislib.core.backend.registry.available_backends()[source]¶
Return the names of all registered backends.
- Qdislib.core.backend.registry.build_backend(name, config)[source]¶
Lazily import and instantiate a registered backend.
The backend module – and its third-party dependencies – are imported only at this point, not at registry import time.
- Return type:
- Qdislib.core.backend.registry.build_execution_backend(software=None, num_qubits=1, *, gpu=False, gpu_min_qubits=None, qpu=False, qpu_dict=None, max_qubit=None, batch=None, ibm_backend=None, **extra)[source]¶
Select and build the backend that evaluates a cut subcircuit.
The single place that turns the cutting algorithms’ execution knobs (
software,gpu,qpu/qpu_dict) into a concrete backend, so the algorithms never branch on the backend/device. Selection order: a large-enough configured QPU (BSCMN_Ona->BSC_QPU_BACKEND,IBM_Quantum->IBM_BACKEND), then GPU-eligible Aer, then thesoftwarebackend (qibo/qiskit/cudaqor the name of any registered backend). Extra keyword arguments (e.g.platformfor Qibo) flow into theBackendConfig.- Return type:
Qdislib.core.backend.unified module¶
The unified backend: one object the algorithms ask to sample / estimate.
QdBackEnd holds one or more BaseBackend
instances and routes each job to the most suitable one – shortest queue first,
qubit-count compatible, with fallback to the next candidate on failure. This is
what decouples the cutting algorithms from any specific SDK or device.
- class Qdislib.core.backend.unified.QdBackEnd(qpu_dict=None)[source]¶
Bases:
objectUnified, load-balancing backend for Qdislib.
- Parameters:
qpu_dict –
Maps backend names to their config, e.g.:
QdBackEnd({ "AER_BACKEND": {"num_qubits": 30}, "IQM_BACKEND": {"num_qubits": 20, "url": "...", "tokens_path": "..."}, })
With no argument, a single default Aer backend is used.
- property backends: list[BaseBackend]¶
- get_expectation_value(circuit, observable, shots=1024, transpile=True, backend_name=None)¶
Estimate
<observable>; falls back past backends without estimator support.- Return type:
- sample_circuit(circuit, shots=1024, transpile=True, backend_name=None)¶
Sample the circuit on the most suitable backend (or a named one).
- Return type:
Qdislib.core.backend.circuit_converter module¶
Convert circuits between the supported source formats (Qiskit / Qibo).
Qiskit and Qibo interconvert cleanly through OpenQASM 2.0. CUDA-Q kernels have
no stable QASM round-trip, so Qdislib feeds CUDA-Q via its backend-neutral DAG
instead; CircuitConverter.num_qubits() still understands a CUDA-Q kernel
and the (dag, num_qubits) payload the cutting code uses for it.
- class Qdislib.core.backend.circuit_converter.CircuitConverter[source]¶
Bases:
objectConverts circuits between the supported formats and reports their size.
- static num_qubits(circuit)[source]¶
Qubit count for any supported circuit, including CUDA-Q payloads.
- Return type:
- static to_qiskit_pauli(observable)[source]¶
Reorder a qubit-0-first Pauli string to Qiskit’s little-endian labels.
Qdislib observable strings are qubit-0-first (char
iacts on qubiti), matching the Qibo/CUDA-Q backends; a QiskitPauli/SparsePauliOplabel is little-endian (char 0 = highest qubit). Reversing keeps the convention consistent across backends – centralised here so the Qiskit-family backends (Aer, IQM) cannot drift apart.- Return type:
Module contents¶
Pluggable, user-swappable execution backends for Qdislib.
Public surface:
from Qdislib import QdBackEnd, register_backend
be = QdBackEnd({"AER_BACKEND": {"num_qubits": 30}})
result = be.sample_circuit(circuit, shots=4096) # -> SampleJobResult
result = be.get_expectation_value(circuit, "ZZI") # -> ExpectationJobResult
Add your own backend by subclassing BaseBackend and registering it:
register_backend("MY_BACKEND", "my_pkg.my_backend", "MyBackend")
Concrete backend modules import their SDKs lazily, so only the extras you use are required.
- class Qdislib.core.backend.BackendConfig(num_qubits, extra=<factory>)[source]¶
Bases:
objectStatic configuration for a backend (its size and any extra options).
- class Qdislib.core.backend.BaseBackend(name, config)[source]¶
Bases:
ABCCommon interface for all Qdislib backends.
FIFO queue management is centralised here via the Template Method pattern: subclasses implement
_execute_samples/_execute_estimator/transpile(the hooks), whilerun_samples/run_estimatororchestrate the full enqueue -> execute -> dequeue lifecycle. The queue length is whatQdBackEnduses to load-balance.- evaluate_expectation(dag, num_qubits, prep_qubits=(), shots=1024, method='automatic')[source]¶
Evaluate the expectation of a Qdislib subcircuit DAG on this backend.
This is the seam the cutting algorithms delegate to instead of branching on the backend name: they hand over the backend-neutral DAG (its Pauli observable rides along as
Observable Imarkers) and the set ofprep_qubits(cut qubits measured for the decomposition, whose sign is recovered from the backend’s own mid-circuit outcome). The backend builds its native circuit, executes it, and reconstructs the value. Backends that only supportrun_samples()/run_estimator()may leave this unimplemented.- Parameters:
- Return type:
- Returns:
The subcircuit’s expectation value.
- evaluate_joint_counts(dag, num_qubits, cut_point_qubits=(), shots=1024, seed=None)[source]¶
Sample a gate-cut subcircuit, capturing the JOINT final/cut-point outcomes.
The seam the sampling reconstruction delegates to – the distribution counterpart of
evaluate_expectation(). Gate-cut sampling needs, per shot, the final measurement and the mid-circuit cut-point outcomes ofcut_point_qubitskept correlated, so a cut qubit that keeps evolving after the cut still reconstructs correctly (its final bit no longer equals its cut-point bit). Returns{(final_bits, cut_point_bits): count}withfinal_bitsqubit-0-first over the component andcut_point_bitsovercut_point_qubitsin order.Backends whose execution yields only aggregated final counts (most real QPUs) cannot report the mid-circuit outcome and leave this unimplemented.
- Parameters:
- Return type:
- Returns:
{(final_bits, cut_point_bits): count}.
- evaluate_samples(dag, num_qubits, shots=1024, seed=None)[source]¶
Sample a Qdislib subcircuit DAG and return counts in a standard convention.
Used by the sampling reconstruction of gate cutting. Every backend returns keys as qubit-0-first bitstrings (
key[i]is qubiti), regardless of the SDK’s native endianness, so the reconstruction combines components uniformly.
- property queue_snapshot: list[Job]¶
Return an immutable copy of the current queue (useful for logging / monitoring).
- run_estimator(circuit, transpile, observable, shots)[source]¶
Compute the expectation value of an observable, updating the FIFO queue.
- Return type:
- class Qdislib.core.backend.CircuitConverter[source]¶
Bases:
objectConverts circuits between the supported formats and reports their size.
- static num_qubits(circuit)[source]¶
Qubit count for any supported circuit, including CUDA-Q payloads.
- Return type:
- static to_qiskit_pauli(observable)[source]¶
Reorder a qubit-0-first Pauli string to Qiskit’s little-endian labels.
Qdislib observable strings are qubit-0-first (char
iacts on qubiti), matching the Qibo/CUDA-Q backends; a QiskitPauli/SparsePauliOplabel is little-endian (char 0 = highest qubit). Reversing keeps the convention consistent across backends – centralised here so the Qiskit-family backends (Aer, IQM) cannot drift apart.- Return type:
- class Qdislib.core.backend.ExpectationJobResult(expectation_value, shots, backend_name, job_id, obs='', metadata=<factory>)[source]¶
Bases:
objectResult of an estimator run: an expectation value plus provenance metadata.
- class Qdislib.core.backend.Job(job_id, kind, n_qubits, shots, submitted_at=<factory>)[source]¶
Bases:
objectA unit of work tracked in a backend’s FIFO queue.
- class Qdislib.core.backend.QdBackEnd(qpu_dict=None)[source]¶
Bases:
objectUnified, load-balancing backend for Qdislib.
- Parameters:
qpu_dict –
Maps backend names to their config, e.g.:
QdBackEnd({ "AER_BACKEND": {"num_qubits": 30}, "IQM_BACKEND": {"num_qubits": 20, "url": "...", "tokens_path": "..."}, })
With no argument, a single default Aer backend is used.
- property backends: list[BaseBackend]¶
- get_expectation_value(circuit, observable, shots=1024, transpile=True, backend_name=None)¶
Estimate
<observable>; falls back past backends without estimator support.- Return type:
- sample_circuit(circuit, shots=1024, transpile=True, backend_name=None)¶
Sample the circuit on the most suitable backend (or a named one).
- Return type:
- class Qdislib.core.backend.SampleJobResult(counts, backend_name, shots, job_id, metadata=<factory>)[source]¶
Bases:
objectResult of a sampling run: measurement counts plus provenance metadata.
- Qdislib.core.backend.build_backend(name, config)[source]¶
Lazily import and instantiate a registered backend.
The backend module – and its third-party dependencies – are imported only at this point, not at registry import time.
- Return type:
- Qdislib.core.backend.build_execution_backend(software=None, num_qubits=1, *, gpu=False, gpu_min_qubits=None, qpu=False, qpu_dict=None, max_qubit=None, batch=None, ibm_backend=None, **extra)[source]¶
Select and build the backend that evaluates a cut subcircuit.
The single place that turns the cutting algorithms’ execution knobs (
software,gpu,qpu/qpu_dict) into a concrete backend, so the algorithms never branch on the backend/device. Selection order: a large-enough configured QPU (BSCMN_Ona->BSC_QPU_BACKEND,IBM_Quantum->IBM_BACKEND), then GPU-eligible Aer, then thesoftwarebackend (qibo/qiskit/cudaqor the name of any registered backend). Extra keyword arguments (e.g.platformfor Qibo) flow into theBackendConfig.- Return type: