Using QDMI drivers¶
The source-installed C++ QDMI library (MQT::CoreQDMI) provides owning wrappers
for the standard QDMI Client Interface. Applications can replace the driver
without rebuilding. The library calls every driver through that interface. Each
driver handles its own device implementations, configuration, and authorization.
The builtin MQT Core QDMI driver (MQT::CoreQDMIDriver, exposed in Python as
builtin_driver) loads devices such as the SC device and
the DDSIM device.
Driver selection¶
Each session selects a driver in this order:
qdmi::SessionConfig::driverPathor Pythondriver_path;the
MQT_CORE_QDMI_DRIVERenvironment variable;the builtin MQT Core QDMI driver.
MQT Core validates the required functions and ABI major/minor versions before allocating a session. Patch differences are compatible. Applications may use different drivers in the same process. Devices and jobs keep their originating session alive, so opening another driver does not invalidate them. Validated driver libraries remain loaded for the process lifetime, including calls from global destructors.
The builtin MQT Core QDMI driver shares device libraries across path aliases with the same symbol prefix. Independent sessions keep their own parameters. Initializing one device does not block initialization of unrelated devices.
Any compatible driver can be selected through the standard opening API:
from mqt.core.qdmi import open_device
device = open_device("example.device", driver_path="/path/to/libdriver.so", token="...")
The driver defines how it uses the token and which devices it exposes. Only the builtin driver accepts per-device session overrides from manifests.
Opening configured devices¶
The following discovery and configuration conveniences are specific to the MQT
Core driver. Use mqt.core.qdmi.builtin_driver.open_device() or
qdmi::builtin_driver::openDevice to open one configured device
with the builtin MQT Core QDMI driver. These calls create independent device
sessions and accept per-call overrides of the session settings in its manifest.
They do not initialize unrelated devices.
from mqt.core.qdmi import builtin_driver
device = builtin_driver.open_device("mqt.ddsim.default")
Use mqt.core.qdmi.builtin_driver.registered_device_ids() to list
enabled configured IDs without loading device libraries or contacting devices.
Register manifests before the first enumeration or device opening.
The Qiskit QDMIBackend.from_device_id factory and PennyLane’s
qml.device("mqt.ddsim.default", wires=4) use this opening API. Python
mqt.core.typing.QDMISessionParameters describes the supported
overrides for device session parameters. To use another driver with these SDKs,
pass an already-open Device to the backend constructor.
The builtin MQT Core QDMI driver provides optional private functions for
manifest registration, metadata-only ID enumeration, and targeted session
allocation. Standard-interface drivers need none of them. The generic Session
and open_device APIs use only the standard Client Interface. The driver’s C++
implementation is internal; only the Client Interface and these three C
extensions are exported from its shared library.
Multi-program jobs¶
Device.submit_job accepts one program or an ordered program list with one
format and common job parameters. num_shots applies to each program. Text
programs carry one terminating null byte; binary programs retain their exact
bytes. try_submit_job returns None only when the device reports that it
cannot accept the format or program count before submission. Device
unavailability and submission errors propagate, since retrying an uncertain
submission could duplicate execution.
Use job.num_programs and the optional program_index argument on result
methods to retrieve results in input order. Use job.get_program(index) for
text or job.get_program(bytes, index) for exact bytes; a retrieved historical
job may not expose it. job.get_program_status(index) reports one outcome when
supported, or None otherwise. A successful program’s results remain available
if another program fails or is cancelled. Cancelling uses the shared native job
handle.
Building the Bundled Devices¶
Standalone MQT Core builds include the DDSIM and superconducting QDMI device
libraries by default. When MQT Core is embedded in another CMake project using
FetchContent or add_subdirectory, these device libraries are
disabled by default so the consumer does not build implementations it may not
use. They can be selected independently before making MQT Core available:
BUILD_MQT_CORE_QDMI_DDSIM_DEVICEBUILD_MQT_CORE_QDMI_SC_DEVICE
All source builds require LLVM/MLIR. The DDSIM device uses the compiler for both OpenQASM and QIR programs.
For example, an embedded simulator consumer can enable only the DDSIM device, while CUDA-Q can enable the DDSIM and superconducting devices used by its integration tests.
The driver is a shared library. The C++ QDMI library follows the project’s
static/shared build setting and is shared in Python wheels. Device-free builds
can use another QDMI driver through driver_path or MQT_CORE_QDMI_DRIVER. The
builtin MQT Core QDMI driver can load external device libraries through
QDMI device configuration. C++ test builds require both
bundled devices.
Python Bindings¶
The C++ QDMI library adds owning wrappers for driver sessions, devices, sites,
operations, and jobs. Each wrapper retains the driver session that owns its raw
handle. The Python module exposes the same entities through
mqt.core.qdmi.
Native device opening, property queries, job calls, and compiler-target snapshots release Python’s GIL. Other Python threads can run while a device waits for a remote response. Python argument and result conversion still holds the GIL. Concurrent calls into a shared device or job must satisfy the device implementation’s thread safety contract; releasing the GIL does not serialize device access.
Custom job parameter types¶
The custom1 through custom5 arguments of
mqt.core.qdmi.Device.submit_job() and
mqt.core.mlir.submit_program() use the device’s documented types.
Strings include a null terminator; bool, int, and float use C++ bool,
int, and double. For a device-defined binary payload, pass nonempty bytes:
job = device.submit_job(program, program_format, custom1=b"\x01\x00\xff")
QDMI copies raw bytes without a terminator; empty payloads raise ValueError.
The device defines their meaning and size. In C++, pass a
std::span<const std::byte> whose buffer stays valid until submission returns.
The bytes describe a local QDMI ABI value, not a network encoding.
Usage¶
Use device_ids() to list the stable IDs visible with default session
parameters. open_device starts a fresh session and finds the requested ID in
its device list. Use Session when authentication or other session parameters
are needed.
1from mqt.core.qdmi import device_ids, open_device
2
3for device_id in device_ids():
4 device = open_device(device_id)
5 print(device.name())
MQT Core DDSIM QDMI Device
All session keywords map to standard QDMI parameters. They are token,
auth_file, auth_url, username, password, project_id, and custom1
through custom5. The selected driver defines validation, precedence, and the
meaning of these values.