Backends
The divi.backends module provides interfaces for running quantum circuits on different backends, from local simulators to cloud-based quantum hardware.
Backend Architecture
All backends implement the CircuitRunner interface, providing a consistent API for circuit execution. This abstraction allows switching between different execution environments without changing quantum program code.
- class CircuitRunner(shots)[source]
Bases:
ABCA generic interface for anything that can “run” quantum circuits.
- property shots
Get the number of measurement shots for circuit execution.
- Returns:
Number of shots configured for this runner.
- Return type:
- abstract property supports_expval: bool
Whether the backend supports expectation value measurements.
- abstract property is_async: bool
Whether the backend executes circuits asynchronously.
- Returns:
- True if the backend returns a job ID and requires polling
for results (e.g., QoroService). False if the backend returns results immediately (e.g., ParallelSimulator).
- Return type:
- abstract submit_circuits(circuits, **kwargs)[source]
Submit quantum circuits for execution.
This abstract method must be implemented by subclasses to define how circuits are executed on their respective backends (simulator, hardware, etc.).
- Parameters:
- Returns:
- For synchronous backends, contains results directly.
For asynchronous backends, contains a job_id that can be used to fetch results later.
- Return type:
ExecutionResult
Execution Results
All CircuitRunner.submit_circuits() methods return an ExecutionResult object, which provides a unified interface for handling both synchronous and asynchronous backend responses.
- class ExecutionResult(results=None, job_id=None)[source]
Bases:
objectResult container for circuit execution.
This class provides a unified return type for all CircuitRunner.submit_circuits() methods. For synchronous backends, it contains the results directly. For asynchronous backends, it contains the job_id that can be used to fetch results later.
The class is frozen (immutable) to ensure data integrity. Use the with_results() method to create a new instance with results populated from an async ExecutionResult.
- results
For sync backends or after fetching: List of result dictionaries, each containing ‘label’ and ‘results’ keys. Format: [{“label”: str, “results”: dict}, …]
- job_id
For async backends: Job identifier that can be used to poll and retrieve results from the backend.
- Type:
str | None
Examples
>>> # Synchronous backend >>> result = ExecutionResult(results=[{"label": "circuit_0", "results": {"00": 100}}]) >>> result.is_async() False
>>> # Asynchronous backend >>> result = ExecutionResult(job_id="job-12345") >>> result.is_async() True >>> # After fetching results >>> result = backend.get_job_results(result) >>> result.results is not None True
-
results:
list[dict] |None= None str, “results”: dict}, …]
- Type:
Results for synchronous backends
- Type:
[{“label”
- __init__(results=None, job_id=None)
- is_async()[source]
Check if this result represents an async job.
- Returns:
- True if job_id is not None and results are None (async backend),
False otherwise (sync backend or results already fetched).
- Return type:
- with_results(results)[source]
Create a new ExecutionResult with results populated.
This method creates a new instance with results set, effectively converting an async ExecutionResult to a completed one.
Core Backend Classes
- class ParallelSimulator(n_processes=None, shots=5000, simulation_seed=None, qiskit_backend=None, noise_model=None, _deterministic_execution=False)[source]
Bases:
CircuitRunnerA parallel wrapper around Qiskit’s AerSimulator using Qiskit’s built-in parallelism.
- Parameters:
n_processes (int | None, optional) – Number of parallel processes to use for transpilation and simulation. If None, defaults to half the available CPU cores (min 2, max 8). Controls both transpilation parallelism and execution parallelism. The execution parallelism mode (circuit or shot) is automatically selected based on workload characteristics.
shots (int, optional) – Number of shots to perform. Defaults to 5000.
simulation_seed (int, optional) – Seed for the random number generator to ensure reproducibility. Defaults to None.
qiskit_backend (Backend | Literal["auto"] | None, optional) – A Qiskit backend to initiate the simulator from.
passed (If "auto" is)
circuit. (the best-fit most recent fake backend will be chosen for the given)
None (Defaults to)
simulation. (resulting in noiseless)
noise_model (NoiseModel, optional) – Qiskit noise model to use in simulation. Defaults to None.
- __init__(n_processes=None, shots=5000, simulation_seed=None, qiskit_backend=None, noise_model=None, _deterministic_execution=False)[source]
A parallel wrapper around Qiskit’s AerSimulator using Qiskit’s built-in parallelism.
- Parameters:
n_processes (int | None, optional) – Number of parallel processes to use for transpilation and simulation. If None, defaults to half the available CPU cores (min 2, max 8). Controls both transpilation parallelism and execution parallelism. The execution parallelism mode (circuit or shot) is automatically selected based on workload characteristics.
shots (int, optional) – Number of shots to perform. Defaults to 5000.
simulation_seed (int, optional) – Seed for the random number generator to ensure reproducibility. Defaults to None.
qiskit_backend (Backend | Literal["auto"] | None, optional) – A Qiskit backend to initiate the simulator from.
passed (If "auto" is)
circuit. (the best-fit most recent fake backend will be chosen for the given)
None (Defaults to)
simulation. (resulting in noiseless)
noise_model (NoiseModel, optional) – Qiskit noise model to use in simulation. Defaults to None.
- set_seed(seed)[source]
Set the random seed for circuit simulation.
- Parameters:
seed (int) – Seed value for the random number generator used in simulation.
- property n_processes: int
Get the current number of parallel processes.
- Returns:
Number of parallel processes configured.
- Return type:
- submit_circuits(circuits)[source]
Submit multiple circuits for parallel simulation using Qiskit’s built-in parallelism.
Uses Qiskit’s native batch transpilation and execution, which handles parallelism internally.
- static estimate_run_time_single_circuit(circuit, qiskit_backend, **transpilation_kwargs)[source]
Estimate the execution time of a quantum circuit on a given backend, accounting for parallel gate execution.
- class QoroService(auth_token=None, config=None, polling_interval=3.0, max_retries=5000)[source]
Bases:
CircuitRunnerA client for interacting with the Qoro Quantum Service API.
This class provides methods to submit circuits, check job status, and retrieve results from the Qoro platform.
Initializes the QoroService client.
- Parameters:
auth_token (str | None, optional) – The authentication token for the Qoro API. If not provided, it will be read from the QORO_API_KEY in a .env file.
config (JobConfig | None, optional) – A JobConfig object containing default job settings. If not provided, a default configuration will be created.
polling_interval (float, optional) – The interval in seconds for polling job status. Defaults to 3.0.
max_retries (int, optional) – The maximum number of retries for polling. Defaults to 5000.
- __init__(auth_token=None, config=None, polling_interval=3.0, max_retries=5000)[source]
Initializes the QoroService client.
- Parameters:
auth_token (str | None, optional) – The authentication token for the Qoro API. If not provided, it will be read from the QORO_API_KEY in a .env file.
config (JobConfig | None, optional) – A JobConfig object containing default job settings. If not provided, a default configuration will be created.
polling_interval (float, optional) – The interval in seconds for polling job status. Defaults to 3.0.
max_retries (int, optional) – The maximum number of retries for polling. Defaults to 5000.
- test_connection()[source]
Test the connection to the Qoro API.
Sends a simple GET request to verify that the API is reachable and the authentication token is valid.
- Returns:
The response from the API ping endpoint.
- Return type:
requests.Response
- Raises:
requests.exceptions.HTTPError – If the connection fails or authentication is invalid.
- fetch_qpu_systems()[source]
Get the list of available QPU systems from the Qoro API.
- Return type:
list[QPUSystem]- Returns:
List of QPUSystem objects.
- submit_circuits(circuits, ham_ops=None, job_type=None, override_config=None)[source]
Submit quantum circuits to the Qoro API for execution.
This method first initializes a job and then sends the circuits in one or more chunks, associating them all with a single job ID.
- Parameters:
circuits (dict[str, str]) – Dictionary mapping unique circuit IDs to QASM circuit strings.
ham_ops (str | None, optional) – String representing the Hamiltonian operators to measure, semicolon-separated. Each term is a combination of Pauli operators, e.g. “XYZ;XXZ;ZIZ”. If None, no Hamiltonian operators will be measured.
job_type (JobType | None, optional) – Type of job to execute (e.g., SIMULATE, EXECUTE, EXPECTATION, CIRCUIT_CUT). If not provided, the job type will be determined from the service configuration.
override_config (JobConfig | None, optional) – Configuration object to override the service’s default settings. If not provided, default values are used.
- Raises:
ValueError – If more than one circuit is submitted for a CIRCUIT_CUT job, or if any circuit is not valid QASM.
requests.exceptions.HTTPError – If any API request fails.
- Returns:
- Contains job_id for asynchronous execution. Use the job_id
to poll for results using backend.poll_job_status() and get_job_results().
- Return type:
ExecutionResult
- delete_job(execution_result)[source]
Delete a job from the Qoro Database.
- Parameters:
execution_result (
ExecutionResult) – An ExecutionResult instance with a job_id to delete.- Returns:
The response from the API.
- Return type:
requests.Response
- Raises:
ValueError – If the ExecutionResult does not have a job_id.
- cancel_job(execution_result)[source]
Cancel a job on the Qoro Service.
- Parameters:
execution_result (
ExecutionResult) – An ExecutionResult instance with a job_id to cancel.- Returns:
- The response from the API. Use response.json() to get
the cancellation details (status, job_id, circuits_cancelled).
- Return type:
requests.Response
- Raises:
ValueError – If the ExecutionResult does not have a job_id.
requests.exceptions.HTTPError – If the cancellation fails (e.g., 403 Forbidden, or 409 Conflict if job is not in a cancellable state).
- get_job_results(execution_result)[source]
Get the results of a job from the Qoro Database.
- Parameters:
execution_result (
ExecutionResult) – An ExecutionResult instance with a job_id to fetch results for.- Returns:
A new ExecutionResult instance with results populated.
- Return type:
ExecutionResult
- Raises:
ValueError – If the ExecutionResult does not have a job_id.
requests.exceptions.HTTPError – If the job results are not available (e.g., job is still running) or if the request fails.
- poll_job_status(execution_result, loop_until_complete=False, on_complete=None, verbose=True, progress_callback=None)[source]
Get the status of a job and optionally execute a function on completion.
- Parameters:
execution_result (
ExecutionResult) – An ExecutionResult instance with a job_id to check.loop_until_complete (bool) – If True, polls until the job is complete or failed.
on_complete (Callable, optional) – A function to call with the final response object when the job finishes.
verbose (bool, optional) – If True, prints polling status to the logger.
progress_callback (Callable, optional) – A function for updating progress bars. Takes (retry_count, status).
- Returns:
The current job status.
- Return type:
- Raises:
ValueError – If the ExecutionResult does not have a job_id.
Job Management
- class JobConfig(shots=None, qpu_system=None, use_circuit_packing=None, tag='default', force_sampling=False)[source]
Bases:
objectConfiguration for a Qoro Service job.
-
qpu_system:
QPUSystem|str|None= None The QPU system to use, can be a string or a QPUSystem object.
-
tag:
str= 'default' Tag to associate with the job for identification.
-
force_sampling:
bool= False Whether to force sampling instead of expectation value measurements.
- override(other)[source]
Creates a new config by overriding attributes with non-None values.
This method ensures immutability by always returning a new JobConfig object and leaving the original instance unmodified.
- Parameters:
other (
JobConfig) – Another JobConfig instance to take values from. Only non-None attributes from this instance will be used for the override.- Return type:
JobConfig- Returns:
A new JobConfig instance with the merged configurations.
- __post_init__()[source]
Sanitizes and validates the configuration.
- __init__(shots=None, qpu_system=None, use_circuit_packing=None, tag='default', force_sampling=False)
-
qpu_system:
- class JobStatus[source]
Status of a job on the Qoro Service.
- PENDING = 'PENDING'
Job is queued and waiting to be processed.
- RUNNING = 'RUNNING'
Job is currently being executed.
- COMPLETED = 'COMPLETED'
Job has finished successfully.
- FAILED = 'FAILED'
Job execution encountered an error.
- CANCELLED = 'CANCELLED'
Job was cancelled before completion.
- class JobType[source]
Type of job to execute on the Qoro Service.
- EXECUTE = 'EXECUTE'
Execute circuits on real quantum hardware (sampling mode only).
- SIMULATE = 'SIMULATE'
Simulate circuits using cloud-based simulation services (sampling mode).
- EXPECTATION = 'EXPECTATION'
Compute expectation values for Hamiltonian operators (simulation only).
- CIRCUIT_CUT = 'CIRCUIT_CUT'
Automatically decompose large circuits that wouldn’t fit on a QPU.