Skip to content

vttresearch/qc-parallelizer

Repository files navigation

Quantum Circuit Parallelizer

python PyPI version License: MIT

A Python module for optimally combining and distributing quantum circuits. See the included notebooks for examples and documentation.

For an operational overview, see the diagram below.

the parallelizer diagram

Why?

Motivation for this module comes from underutilization of increasingly large quantum processors in quantum computing tasks that only require relatively few qubits at a time. The module merges several independent circuits into a smaller set of wider circuits, which it then runs on available backends in parallel. All of this happens behind the scenes, so ideally, the user can treat the module's functionality as a parallelized drop-in replacement for Qiskit's backend.run().

As an example, consider a task that involves running a four-qubit circuit several times with different parameters. If each version of the circuit was naively submitted one by one to the 54-qubit VTT Q50, 54 - 4 = 50 qubits would remain unused in each job. This is very wasteful in terms of execution time, which then translates to unnecessary operational costs.

Instead, depending on the connectivity of the four-qubit circuit, at least nine such circuits can be packed into a single host circuit that covers as many of Q50's qubits as it can. Optionally, the parallelizer can also be instructed to leave "padding qubits" between packed circuits. This reduces crosstalk between circuits at the cost of lower packing density.

Installation

The package is on PyPI and can be installed with pip:

pip install qc_parallelizer

Usage example

Here is a brief and basic example:

# Define or load a number of circuits.
from qiskit import QuantumCircuit
circuits = [QuantumCircuit(...), QuantumCircuit(...), ...]

# Define backends for circuit execution. These can be any Qiskit-compatible backend objects,
# but here we define two simulators that mimic IQM's 5-qubit Adonis architecture.
import iqm.qiskit_iqm as iqm
backends = [iqm.IQMFakeAdonis(), iqm.IQMFakeAdonis()]

# Instantiate the parallelizer, define usable backends, and run the circuits.
from qc_parallelizer import Parallelizer
job = Parallelizer().across(backends).run(circuits)

# Fetch and handle results. This plots the first circuit's result histogram, for example.
results = job.result()
qiskit.visualization.plot_histogram(results.get_counts(0))
# Information about the execution is also available.
print("Job IDs:")
for job, id in job.remote_ids.items():
    print(f"- {id} (on '{job.remote_backend.name}')")

The parallelizer also supports emulation of a virtual parallelized backend that can be passed to other software. It functions as a regular backend, but automatically parallelizes any circuits that are submitted to it:

>>> backend = Parallelizer().across(backends).as_qiskit_backend
>>> isinstance(backend, BackendV2)
True
>>> backend.target
<qiskit.transpiler.target.Target object at 0x71f0deadbeef>
>>> job = backend.run(circuits)
>>> isinstance(job, JobV1)
True
>>> job.result()
Result(
  backend_name='ParallelizedQiskitBackendAdapter',
  backend_version='2',
  job_id='8b019556-bb08-40b5-93ff-788ff1f7fb89',
  results=[...]
)

Likewise, the parallelized backend can be supplied to PennyLane with .as_pennylane_device. See the PennyLane demo notebook for an example.

Development setup

For the following commands, a virtual environment or equivalent isolation is recommended. This can be done with Conda, for example, with

conda create --name parallelizer python=3.11 pip
conda activate parallelizer

The package can then be installed from a local copy of the directory by running

pip install -e .

from the repository root. If you additionally wish to run tests or the provided notebook(s), you can install dependencies for those with

pip install .[tests]
# and/or
pip install .[notebooks]

Logging

For debugging, it can be extremely useful to enable logging. The project uses an internal logging library with a global configurable log level. You can enable everything with

from qc_parallelizer.util import Log
Log.set_level("debug")

or use the other levels ("info", "warn", "fail") for less verbose logging. By default, it writes nicely formatted and coloured output to stderr, but you can configure it with these two class attributes:

Log.color: bool         # Enables color, True by default, but this can mess with some environments
Log.force_builtin: bool # Forwards everything to Python's logging module, False by default

The log lines are interpreted as follows:

2026-06-03 11:28:14.488510 | [T0]~~~> vf2.py:70               | DBUG | VF2++ generator created with `id_order` = False.
^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^ ^^^^ ^^^^^^ ^^                 ^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  `--> Timestamp               \    \      \   `-> Line number    `-> Log level      `-> Message
                                \    \      `-> Source file
                                 \    `-> Relative stack depth
                                  `-> Thread number (assigned T0, T1, T2, ... in order of appearance)

Testing

Running all tests is as simple as installing the required dependencies (see above) and running

pytest

from the repository root. Additionally, there is a benchmarking script in the tests/ directory.

Next steps

(In no particular order.)

  • Make layout/placement algorithms favour better-performing qubits, as specified by calibration data. This could potentially be read from the given backend objects, or the user could specify the data manually. This is of course possible with custom packers already.
  • Add more tests! Numerous configurations have been tested manually with notebooks but more should be covered with unit testing.
  • Batch jobs with identical measurements together. On backends with relatively long initialization times, batching can make a big difference.
  • Allow circuits to share physical qubits for temporally non-overlapping parts. This requires reset instructions and makes the problem computationally harder, so this a step for the distant future.

Authors

  • Henri Ahola <firstname.lastname@vtt.fi>

About

A Python module for optimally combining and distributing quantum circuits

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages