Easy Integration with the iqm-qdmi Python Package¶
To ease the distribution and integration of the IQM QDMI Device library, we have
packaged it as a Python module available on PyPI under the name iqm-qdmi. This
package provides a convenient way to discover installation paths and metadata
that are useful when integrating the IQM QDMI Device into downstream build
systems, such as CMake-based projects or Python workflows.
Install From PyPI¶
Use uv (or your Python package manager of choice) to install the package:
uv pip install iqm-qdmi
Quick Usage¶
The package itself makes the following variables available for import:
__version__: installed package version.IQM_QDMI_INCLUDE_DIR: include directory for C/C++ headers.IQM_QDMI_CMAKE_DIR: CMake package directory forfind_packageintegration.IQM_QDMI_LIBRARY_PATH: full path to the shared library.
1from iqm.qdmi import __version__, IQM_QDMI_INCLUDE_DIR, IQM_QDMI_CMAKE_DIR, IQM_QDMI_LIBRARY_PATH
2
3print(f"QDMI on IQM version: {__version__}")
4print(f"Include directory: {IQM_QDMI_INCLUDE_DIR}")
5print(f"CMake directory: {IQM_QDMI_CMAKE_DIR}")
6print(f"Library path: {IQM_QDMI_LIBRARY_PATH}")
QDMI on IQM version: 1.4.0
Include directory: /home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/include
CMake directory: /home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/share/cmake
Library path: /home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/lib/libiqm-qdmi-device.so
Command Line Interface¶
The above values can also be conveniently queried from the command line via the
iqm-qdmi entry point.
1!iqm-qdmi --help
usage: iqm-qdmi [-h] [--version | --include_dir | --cmake_dir | --lib_path]
Command line interface for the QDMI on IQM library.
options:
-h, --help show this help message and exit
--version show program's version number and exit
--include_dir Print the path to the iqm-qdmi C/C++ include directory
--cmake_dir Print the path to the iqm-qdmi CMake module directory
--lib_path Print the path to the iqm-qdmi shared library
1!iqm-qdmi --version
1.4.0
1!iqm-qdmi --include_dir
/home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/include
1!iqm-qdmi --cmake_dir
/home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/share/cmake
1!iqm-qdmi --lib_path
/home/runner/work/QDMI-on-IQM/QDMI-on-IQM/.nox/docs/lib/python3.14/site-packages/iqm/qdmi/data/lib/libiqm-qdmi-device.so
Sampler and Estimator CLI Utilities¶
If you install the package with the qiskit extra, the following additional
command-line scripts are exposed:
iqm-sampler(see thesamplerentry point module): Samples a serialized QPY circuit on the specified backend.iqm-estimator(see theestimatorentry point module): Variational Quantum Eigensolver (VQE) parameter estimation for a serialized ansatz and observable.
iqm-sampler Usage¶
For example, to execute a QPY circuit file (bell.qpy):
iqm-sampler bell.qpy --shots 128
iqm-estimator Usage¶
To run a parameter estimation job:
iqm-estimator ansatz.qpy observable.pkl --maxiter 10
The estimator CLI and offloader.estimate use Qiskit’s default precision of
1/64, corresponding to 4,096 shots per measurement circuit. See the
primitive options.
Programmatic Offloading with the offloader Module¶
For workflows running on a Slurm login node (such as Jupyter notebooks on a
gateway service), the package exposes the offloader module.
It allows you to programmatically submit quantum workloads to the Slurm quantum
queue.
The module provides two primary functions:
sample(): Serializes the given circuit to QPY, submits a Slurm job usingsrun iqm-sampler, and parses the base64-encoded pickled result back to a python dictionary of counts.estimate(): Serializes the ansatz and observable, submits a Slurm job usingsrun iqm-estimator, and parses the base64-encoded pickledVQEResultto return it, matching the semantics of runningVQEdirectly against the regular (non-offloaded) estimator.
Both functions support a local=True argument for running simulation/hardware
compilation locally (useful for debugging) and a simulator=True argument when
submitting Slurm jobs to target simulated devices instead of real QPU hardware.
Selecting the Slurm Partition¶
Both functions submit their srun jobs to the partition gating the nodes that
expose the quantum computer as a Slurm GRES resource. Its name is a per-site
choice, resolved in this order:
The
partitionkeyword argument.The
IQM_SLURM_PARTITIONenvironment variable, which lets an administrator set the site’s name once for every user. An empty value counts as unset.quantum, the name used throughout the SPANK plugin documentation and the Administrator Guide.
counts = sample(qc, shots=512, partition="qc-nodes")
Slurm’s own SLURM_PARTITION has no effect here, because the resolved name is
always passed as an explicit --partition, which takes precedence over it.
Important
Renaming the partition is not enough on its own. The SPANK plugin only runs on
the partitions its partitions= option lists, so that list has to carry the new
name too — see Configuration. Otherwise the
plugin silently skips the job and never injects IQM_BASE_URL, IQM_QC_ID, or
IQM_QC_ALIAS.
Sizing the Slurm Allocation¶
Both functions accept a nodes keyword argument, forwarded as --nodes and
defaulting to a single node. The worker itself always runs as one task
(--ntasks=1), so nodes only sizes the allocation for a site whose partition
demands more than one node; it does not distribute or parallelize the workload.
It has no environment fallback: the node count is a per-job resource request rather than a site-wide constant.
Selecting a Quantum Computer per Job¶
Both functions accept optional qc_id and qc_alias keyword arguments to pin a
specific quantum computer for a single job, without changing the process’s
default backend configuration. When set, they are passed as --iqm-qc-id and
--iqm-qc-alias options on the srun command itself, which the QDMI-on-IQM
SPANK plugin resolves into the job’s IQM_QC_ID and
IQM_QC_ALIAS environment variables. Only used when local=False.
Requesting a Slurm License¶
Both functions accept an optional licenses keyword argument, forwarded
verbatim as a --licenses option on the srun command (Slurm’s own
name[:count][,name[:count]...] syntax). This is unrelated to QC selection: a
site administrator can configure a Slurm license per QC to cap concurrent jobs
against it – see the SPANK plugin’s
Limiting Concurrent Access with Slurm Licenses
docs – and licenses is how a caller requests it. Only used when
local=False.
counts = sample(qc, shots=512, simulator=True, qc_alias="emerald", licenses="iqm_qc_emerald:1")
Programmatic Sampling Example¶
from iqm.qdmi.offloader import sample
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
# programmatically offload via Slurm
counts = sample(qc, shots=512, simulator=True)
print("Counts:", counts)
Querying the Device Directly¶
The Qiskit backend covers circuit execution, but a QDMI device also answers
questions about itself. Open a session with MQT Core’s driver to reach them.
Constructing an IQMBackend registers the device
under the stable ID IQM_QDMI_DEVICE_ID, after which
open_device resolves it:
from mqt.core.qdmi.driver import open_device
from iqm.qdmi import IQM_QDMI_DEVICE_ID
device = open_device(IQM_QDMI_DEVICE_ID, token="…", custom2="emerald")
print(device.status())
print(device.supported_program_formats())
Queue Length and Queue Position¶
The device reports how busy the quantum computer is, so a client can decide whether to submit now or wait:
waiting = device.queue_length() # jobs waiting, excluding those executing
queue_length() returns None when the IQM API does not supply a trustworthy
value. A queued job reports how many jobs are ahead of it; querying it refreshes
the job’s status first:
ahead = job.queue_position # None once the job is no longer queued
Retrieving an Existing Job¶
A job outlives the session that submitted it. Given its ID, a later session can pick it up again to poll, wait, cancel, or fetch results:
job = device.retrieve_job_by_id("d3416f0a-…")
print(job.check())
A retrieved job cannot be resubmitted, and its parameters cannot be changed.