Skip to content

✨ Integrate QDMI Devices#1687

Open
MatthiasReumann wants to merge 37 commits into
mainfrom
feat/arch-option-and-qdmi
Open

✨ Integrate QDMI Devices#1687
MatthiasReumann wants to merge 37 commits into
mainfrom
feat/arch-option-and-qdmi

Conversation

@MatthiasReumann

@MatthiasReumann MatthiasReumann commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Description

This pull request integrates QDMI into the MLIR Compiler Collection (mqt-cc).

Overview

  • Adds SuperconductingDevice class that acts as an adapter for QDMI.
  • The CLI is defined as follows (prefix: qdmi)
--qdmi-list-devices         // List all available QDMI devices. 
--qdmi-device=iqm-radiance  // Specify the device used for hardware-specific passes. 
--qdmi-config=./qdmi.json   // Specify session config, additional devices and their respective configs. 
  • The specified device is loaded and stored in the QuantumCompilerConfig. The QDMI device is then used in the hardware-specific phase to construct the SuperconductingDevice. I assume superconducting devices only. Future work might implement a "dispatcher" to create the correct pass pipeline for the respective device's constraints.

CLI Example

matthias:~$ cat ~/Downloads/qdmi.json
{
    "devices": [
        {
            "libName": "/Users/matthias/Documents/projects/core/build/src/qdmi/devices/sc/libmqt-core-qdmi-sc-device.dylib",
            "prefix": "MQT_SC",
            "deviceConfig": {
                "baseUrl": "...",
                "token": "...",
                "authFile": "...",
                "authUrl": "...",
                "username": "...",
                "password": "...",
                "custom1": "...",
                "custom2": "...",
                "custom3": "...",
                "custom4": "...",
                "custom5": "..."
            }
        }
    ]
}
matthias:~$ mqt-cc --qdmi-list-devices --qdmi-config ~/Downloads/qdmi.json
[2026-07-09 14:03:58.473] [info] [Driver.cpp:193] Device session parameter BASE URL not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter TOKEN not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter AUTH FILE not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter AUTH URL not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter USERNAME not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter PASSWORD not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM1 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM2 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM3 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM4 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM5 not supported by device (skipped)
Available QDMI devices:
	MQT NA Default QDMI Device // Statically loaded.
	MQT SC Default QDMI Device // Statically loaded.
	MQT Core DDSIM QDMI Device // Statically loaded.
	MQT SC Default QDMI Device // Dynamically loaded.

Resolves #1082.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • AI-assisted commits include an Assisted-by: [Model Name] via [Tool Name] footer.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

@MatthiasReumann MatthiasReumann self-assigned this May 6, 2026
@MatthiasReumann MatthiasReumann added c++ Anything related to C++ code MLIR Anything related to MLIR labels May 6, 2026
@codecov

codecov Bot commented May 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 22.30216% with 108 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mlir/lib/Support/Qdmi.cpp 0.0% 72 Missing ⚠️
mlir/lib/Compiler/CompilerPipeline.cpp 15.0% 17 Missing ⚠️
mlir/lib/Support/SuperconductingDevice.cpp 46.6% 16 Missing ⚠️
mlir/include/mlir/Support/SuperconductingDevice.h 50.0% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@MatthiasReumann MatthiasReumann changed the title 🚧 Specify QPU Architecture via arch option 🚧 Integrate QDMI Devices via arch Option Jun 15, 2026
@mergify mergify Bot added the conflict label Jun 18, 2026
@mergify mergify Bot removed the conflict label Jul 1, 2026
@MatthiasReumann MatthiasReumann changed the title 🚧 Integrate QDMI Devices via arch Option 🚧 Integrate QDMI Devices Jul 1, 2026
@MatthiasReumann

MatthiasReumann commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

@burgholzer (cc: @ystade)

This pull request now implements a very basic QDMI V1 integration into our compiler collection. Before continuing, I want to discuss the following issues.

Optionally enable QDMI

As of now, the current implementation tightly couples the mqt-cc with QDMI. Wouldn't it be nice to have QDMI as a compile-option in CMake? Something like ENABLE_QDMI_INTEGRATION (analogous to LLVM's ENABLE_ASSERTIONS) which adds the CLI Options, and generally the QDMI logic via preprocessor definitions? If so, we could still compile the mqt-cc without QDMI.

Extract Nested Classes

In order to augment the FoMaC device classes, I think it would be nice to extract them outside the Session class. Any opinions on that? It is kind of awkward to always write out fomac::Session::Device. Especially if we ever want to have specializations such as SuperconductingDevice, etc.

Trailing Return Types (Nitpick, sorry!)

I am really not that sure if the FoMaC classes benefit from the benefits of trailing return types. The auto in the following examples just feels somewhat wrong. Modern & fancy but wrong.

// fomac/FoMaC.cpp
auto getParametersNum(const std::vector<Site>& sites = {},
                       const std::vector<double>& params = {}) const -> size_t;
// qdmi/sc/Device.hpp
auto sessionFree(MQT_SC_QDMI_Device_Session session) -> void;

I've taken the liberty to implement some of the above FoMaC changes this morning (+ some improvements using modern C++ concepts) in FoMaC.hpp and FoMaC.cpp for you to better understand what I meant.


Any comments appreciated! Many thanks 🙏

@burgholzer

Copy link
Copy Markdown
Member

@burgholzer (cc: @ystade)

This pull request now implements a very basic QDMI V1 integration into our compiler collection. Before continuing, I want to discuss the following issues.

Optionally enable QDMI

As of now, the current implementation tightly couples the mqt-cc with QDMI. Wouldn't it be nice to have QDMI as a compile-option in CMake? Something like ENABLE_QDMI_INTEGRATION (analogous to LLVM's ENABLE_ASSERTIONS) which adds the CLI Options, and generally the QDMI logic via preprocessor definitions? If so, we could still compile the mqt-cc without QDMI.

Hm. I'd argue that if we view QDMI as the primary way to add architecture information to mqt-cc, it should be(come) an essential part of it. Would we ever compile mqt-cc without QDMI support? In what kind of circumstances would that yield a benefit?

Extract Nested Classes

In order to augment the FoMaC device classes, I think it would be nice to extract them outside the Session class. Any opinions on that? It is kind of awkward to always write out fomac::Session::Device. Especially if we ever want to have specializations such as SuperconductingDevice, etc.

We have an open tracking issue going in that direction #1358. See also #1363 (comment)
Your proposed refactoring sounds fine as a start.

Trailing Return Types (Nitpick, sorry!)

I am really not that sure if the FoMaC classes benefit from the benefits of trailing return types. The auto in the following examples just feels somewhat wrong. Modern & fancy but wrong.

// fomac/FoMaC.cpp
auto getParametersNum(const std::vector<Site>& sites = {},
                       const std::vector<double>& params = {}) const -> size_t;
// qdmi/sc/Device.hpp
auto sessionFree(MQT_SC_QDMI_Device_Session session) -> void;

Feel free to get rid of them. I am personally not the biggest fan of these either way.

I've taken the liberty to implement some of the above FoMaC changes this morning (+ some improvements using modern C++ concepts) in FoMaC.hpp and FoMaC.cpp for you to better understand what I meant.

Thanks, I'll take a look! 👍🏼

Any comments appreciated! Many thanks 🙏

@MatthiasReumann

MatthiasReumann commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator Author

In what kind of circumstances would that yield a benefit?

I was kind of thinking about IBM Benchpress. Not sure if we could still use QDMI here that easily.

We have an open tracking issue going in that direction #1358. See also #1363 (comment)

Oh. Great! I'll have a look at these and try to incorporate them in the refactoring.

Thanks, I'll take a look!

I've also opened #1849 to ease the comparison to the old implementation.

@burgholzer

Copy link
Copy Markdown
Member

In what kind of circumstances would that yield a benefit?

I was kind of thinking about IBM Benchpress. Not sure if we could still use QDMI here that easily.

I was hoping that we could take the input from benchpress and wrap it in QDMI at runtime.
Somewhat relates to #1226 but on a broader scale

We have an open tracking issue going in that direction #1358. See also #1363 (comment)

Oh. Great! I'll have a look at these and try to incorporate them in the refactoring.

Take those with a grain of salt though. It's been a while that they have been written and some circumstances might have changed since then. Still good to have a look though.

@ystade

ystade commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

A little late, but since I was tagged, I also wanted to comment:

Trailing return types

I guess I am responsible for them. I love them because when you read auto as func or so, the function signature becomes very similar to other languages. For me, it feels natural to have the return type at the end of the function. Anyway, I agree that this depends very much on taste, and I will go along with the majority.

FoMaC Concept

I guess everything has already been said here. I can just repeat here that in the future we want to directly build on QDMI and want to get rid of FoMaC or rather replace that by a C++ abstraction of QDMI.

@mergify mergify Bot added the conflict label Jul 8, 2026
@MatthiasReumann
MatthiasReumann marked this pull request as ready for review July 9, 2026 12:11
@MatthiasReumann

MatthiasReumann commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

@burgholzer @ystade

I think this one is ready to discuss.

  • I've added a SuperconductingDevice1 class that acts as an adapter for QDMI, coupling maps, and whatever is to follow (V2 at some point, I guess).
  • The CLI is defined as follows (prefix: qdmi)
--qdmi-list-devices         // List all available QDMI devices. 
--qdmi-device=iqm-radiance  // Specify the device used for hardware-specific passes. 
--qdmi-config=./qdmi.json   // Specify session config, additional devices and their respective configs. 
  • The specified device is loaded and stored in the QuantumCompilerConfig. The QDMI device is then used in the hardware-specific phase to construct the SuperconductingDevice. I assume superconducting devices only. Future work might implement a "dispatcher" to create the correct pass pipeline for the respective device's constraints.

CLI Example

matthias:~$ cat ~/Downloads/qdmi.json
{
    "devices": [
        {
            "libName": "/Users/matthias/Documents/projects/core/build/src/qdmi/devices/sc/libmqt-core-qdmi-sc-device.dylib",
            "prefix": "MQT_SC",
            "deviceConfig": {
                "baseUrl": "...",
                "token": "...",
                "authFile": "...",
                "authUrl": "...",
                "username": "...",
                "password": "...",
                "custom1": "...",
                "custom2": "...",
                "custom3": "...",
                "custom4": "...",
                "custom5": "..."
            }
        }
    ]
}
matthias:~$ mqt-cc --qdmi-list-devices --qdmi-config ~/Downloads/qdmi.json
[2026-07-09 14:03:58.473] [info] [Driver.cpp:193] Device session parameter BASE URL not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter TOKEN not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter AUTH FILE not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter AUTH URL not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter USERNAME not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter PASSWORD not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM1 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM2 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM3 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM4 not supported by device (skipped)
[2026-07-09 14:03:58.474] [info] [Driver.cpp:193] Device session parameter CUSTOM5 not supported by device (skipped)
Available QDMI devices:
	MQT NA Default QDMI Device // Statically loaded.
	MQT SC Default QDMI Device // Statically loaded.
	MQT Core DDSIM QDMI Device // Statically loaded.
	MQT SC Default QDMI Device // Dynamically loaded.

Footnotes

  1. I consciously avoided SCDevice because of "super-computing"; and generally to avoid acronyms as much as possible :)

@burgholzer

Copy link
Copy Markdown
Member

I have not yet had the chance to look through everything in detail here yet, but I have one general high-level observation already:

A lot of the QDMI-related functionality is built "outside" of QDMI here (building on top of FoMaC; relying on addDevice..).
I would argue that we need to take this one step further. These enhancements should directly go into the QDMI Driver so that the driver itself reads the config file and uses that to make its devices available.
The build should likely write a config file as part of the build, where one needs to be a bit careful about the library paths being embedded in the config because one needs to ensure that the config file also works in an install tree of MQT Core (such as in the Python bindings). We already perform some kind of shenanigans around that with the builtin devices and how they are hardcoded in the driver. The config file should replace the existing approach.
More generally, I believe that quite some of the functionality in the QDMI.h header should likely be functionality that is added to the FoMaC and/or Driver classes directly.

@MatthiasReumann does that make sense? Can you work with that?

@MatthiasReumann

MatthiasReumann commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

@burgholzer: I would argue that we need to take this one step further.

I'll try to summarize my thoughts on this. Let me know, if the following is valid.

These enhancements should directly go into the QDMI Driver so that the driver itself reads the config file and uses that to make its devices available.

Generally understood.

The build should likely write a config file as part of the build, where one needs to be a bit careful about the library paths being embedded in the config because one needs to ensure that the config file also works in an install tree of MQT Core (such as in the Python bindings). We already perform some kind of shenanigans around that with the builtin devices and how they are hardcoded in the driver. The config file should replace the existing approach.

I wonder: Is there any valid reason to link devices statically in the mqt-core driver? Wouldn't it be quite elegant if the mqt-core driver takes a config file at runtime (via function call or CLI) and loads the specified devices at boot-time?1 I guess this would avoid any of the build shenanigans described by you. However, we could still supply a builtin-devices.json (maybe even auto-generate it) to the QDMI devices generated by the generator:

<cmake world>
generateIQMSpark()
generateIQMRadiance()
generateIBMHeron()

generateJSONConfig()

<c++ world>
Driver::get().init("config.json");

Because isn't the purpose of the mqt-core driver to be "plug-and-play"?

More generally, I believe that quite some of the functionality in the QDMI.h header should likely be functionality that is added to the FoMaC and/or Driver classes directly.

Understood.


Currently, what really confuses me - and I just realized - is that the Driver.cpp implements the QDMI client functions. So the driver is in fact the client in mqt-core.

Footnotes

  1. which is actually already happening (just via CMake magic).

@mergify mergify Bot added the conflict label Jul 10, 2026
@burgholzer

Copy link
Copy Markdown
Member

The build should likely write a config file as part of the build, where one needs to be a bit careful about the library paths being embedded in the config because one needs to ensure that the config file also works in an install tree of MQT Core (such as in the Python bindings). We already perform some kind of shenanigans around that with the builtin devices and how they are hardcoded in the driver. The config file should replace the existing approach.

I wonder: Is there any valid reason to link devices statically in the mqt-core driver? Wouldn't it be quite elegant if the mqt-core driver takes a config file at runtime (via function call or CLI) and loads the specified devices at boot-time?1 I guess this would avoid any of the build shenanigans described by you. However, we could still supply a builtin-devices.json (maybe even auto-generate it) to the QDMI devices generated by the generator:

<cmake world>
generateIQMSpark()
generateIQMRadiance()
generateIBMHeron()

generateJSONConfig()

<c++ world>
Driver::get().init("config.json");

Because isn't the purpose of the mqt-core driver to be "plug-and-play"?

IIRC we no longer statically link the QDMI devices that come with MQT Core.
As you point out in the footnote above, we do some CMake magic to populate the devices at driver bootup.
My recommendation from above was precisely to replace that magic with configuration file logic.
The example driver in the main QDMI repository already has some boilerplate code for this https://github.com/Munich-Quantum-Software-Stack/QDMI/blob/cc94309662a8cdc265821f642707d44e34378274/examples/driver/qdmi_example_driver.cpp#L233-L311
This includes default search locations as well as the option to provide the config path via an environment variable.

I would argue that the following things should be possible:

  • a default config file should be (auto-)generated at build/install time that contains all the devices built into MQT Core. This should be placed somewhere where the driver looks for it (in the build folder or the install tree; it should not be written to the source tree as it is a generated artifact)
  • providing an additional configuration file to be considered. This can happen either through an environment variable, or potentially through a parameter of the driver constructor (does that make sense?). Both of these options allow configuration at boot time. Additionally, we likely want configurability at runtime (similar to addDynamicDeviceLibrary) either programmatically or through the CLI.
  • We could potentially use a MQT Core QDMI CLI that provides prefixes and library paths for the builtin devices so that other libraries that, e.g., want to use the DDSIM device could programmatically get that information. Ideally that CLI would be in C++ and somewhat exposed to Python so that it can be used with and without Python.

More generally, I believe that quite some of the functionality in the QDMI.h header should likely be functionality that is added to the FoMaC and/or Driver classes directly.

Understood.

Currently, what really confuses me - and I just realized - is that the Driver.cpp implements the QDMI client functions. So the driver is in fact the client in mqt-core.

I believe I get where your confusion is coming from. This is a consequence of the initial design of QDMI v1. QDMI v1 defines the device and the client interface. HW Providers implement the (prefixed) device interface; clients can use the (non-prefixed) client interface with all the devices they have access to. The driver mediates between both interfaces.
The FoMaC library builds on top of the client interface that is exposed by the driver; except for the addDynamicDeviceLibrary method of the driver, which is not officially part of the QDMI client interface.

We have a rather lengthy exposition of that topic here: Munich-Quantum-Software-Stack/QDMI#215 that was written almost a year ago. So far, no one dared to make the move and eliminate the client interface in MQT Core to combine the FoMaC and Driver libraries (also getting rid of the FoMaC name 😅)
Maybe you can give that issue a read and make up your mind based on that and the discussion here.

@MatthiasReumann

Copy link
Copy Markdown
Collaborator Author

@burgholzer Okay, I think I got a plan.

Step 0: Device Generation

  1. Create a few more sc device JSON files. Maybe real-hardware architectures such as those from IQM.
  2. Setup CMake to create .dylibs for each of those JSON files.
  3. Setup CMake to create a builtin-devices.json somewhere in the build folder, referencing those .dylibs. Store the path to this JSON as a CMake variable.

Step 1: Driver Boot-up

  1. Keep the current CMake magic; but parse the builtin-devices.json in the driver's constructor and load the devices described in it.
  2. Add a CMake Configuration Variable, explicitly stating a list of additional device JSON files. Parse and load these in the same step as 1.1.

Step 2: Driver Runtime

  1. The interface that parses and loads the devices used in Step 1, should also be usable for the MLIR CLI. Essentially something like Driver::get().load(<json_file>).

Essentially, the JSON config files will be the canonical way to load devices into mqt-core QDMI driver.

┌──────────────────────────────────────────────────┐                                                       
│  CMake                                           │                                                       
│                                                  │                                                       
│      ┌───────────┐     ┌─────────┐               │                                                       
│      │ Generator │    ┌│         │               │                                                       
│      └───┬─┬─┬───┘  ┌─││.dylib   │               │                                                       
│          │ │ └──────│ ││         │               │  ┌──────────────────┐                                 
│          │ └────────│ │└───┬─────┘               │  │ Outside World    │                                 
│          └──────────│ └─┬──┼───┘                 │  │                  │                                 
│                     └─┬─┼──┼─┘                   │  │┌────────────────┐│                                 
│                       │ │  │                     │  ││lrz-devices.json││                                 
│                    ┌──▼─▼──▼──────────────┐      │  │└────────────────┘│                                 
│                    │ builtin-devices.json │      │  │┌────────────────┐│                                 
│                    └──────────────────────┘      │  ││aws-devices.json││                                 
└───────────────────────────────────┬──────────────┘  │└────────────────┘│                                 
                                    │                 └──────┬───────────┘                                 
┌───────────────────────────────────┼──────────────┐         │                                             
│ CPP                               │                        │                                             
│              ┌────────────────────▼──────┐       │         │                                             
│              │Driver::Driver()           │       │         │                                             
│              │  for each: load(...)      ◄───────┼─────────┘                                             
│              └───────────────────────────┘       │  -DQDMI_DEVICE_PATHS=lrz-devices.json;aws-devices.json
│                                                  │                                                       
│              ┌───────────────────────────┐       │                                                       
│              │Driver::get().load(...)    │       │                                                       
│              └────────────▲──────────────┘       │                                                       
│                           │                      │                                                       
└───────────────────────────┼──────────────────────┘                                                       
                            │     --qdmi-configs=iqm-devices.json                                                          
                         ┌──┴──┐                                                                           
                         │MLIR │                                                                           
                         └─────┘                                                                           

I'll leave it at that for now for this pull request.

Any objections? @ystade Any opinions?

@burgholzer

Copy link
Copy Markdown
Member

@burgholzer Okay, I think I got a plan.

Step 0: Device Generation

  1. Create a few more sc device JSON files. Maybe real-hardware architectures such as those from IQM.

  2. Setup CMake to create .dylibs for each of those JSON files.

  3. Setup CMake to create a builtin-devices.json somewhere in the build folder, referencing those .dylibs. Store the path to this JSON as a CMake variable.

Step 1: Driver Boot-up

  1. Keep the current CMake magic; but parse the builtin-devices.json in the driver's constructor and load the devices described in it.

  2. Add a CMake Configuration Variable, explicitly stating a list of additional device JSON files. Parse and load these in the same step as 1.1.

Step 2: Driver Runtime

  1. The interface that parses and loads the devices used in Step 1, should also be usable for the MLIR CLI. Essentially something like Driver::get().load(<json_file>).

Essentially, the JSON config files will be the canonical way to load devices into mqt-core QDMI driver.


┌──────────────────────────────────────────────────┐                                                       

│  CMake                                           │                                                       

│                                                  │                                                       

│      ┌───────────┐     ┌─────────┐               │                                                       

│      │ Generator │    ┌│         │               │                                                       

│      └───┬─┬─┬───┘  ┌─││.dylib   │               │                                                       

│          │ │ └──────│ ││         │               │  ┌──────────────────┐                                 

│          │ └────────│ │└───┬─────┘               │  │ Outside World    │                                 

│          └──────────│ └─┬──┼───┘                 │  │                  │                                 

│                     └─┬─┼──┼─┘                   │  │┌────────────────┐│                                 

│                       │ │  │                     │  ││lrz-devices.json││                                 

│                    ┌──▼─▼──▼──────────────┐      │  │└────────────────┘│                                 

│                    │ builtin-devices.json │      │  │┌────────────────┐│                                 

│                    └──────────────────────┘      │  ││aws-devices.json││                                 

└───────────────────────────────────┬──────────────┘  │└────────────────┘│                                 

                                    │                 └──────┬───────────┘                                 

┌───────────────────────────────────┼──────────────┐         │                                             

│ CPP                               │                        │                                             

│              ┌────────────────────▼──────┐       │         │                                             

│              │Driver::Driver()           │       │         │                                             

│              │  for each: load(...)      ◄───────┼─────────┘                                             

│              └───────────────────────────┘       │  -DQDMI_DEVICE_PATHS=lrz-devices.json;aws-devices.json

│                                                  │                                                       

│              ┌───────────────────────────┐       │                                                       

│              │Driver::get().load(...)    │       │                                                       

│              └────────────▲──────────────┘       │                                                       

│                           │                      │                                                       

└───────────────────────────┼──────────────────────┘                                                       

                            │     --qdmi-configs=iqm-devices.json                                                          

                         ┌──┴──┐                                                                           

                         │MLIR │                                                                           

                         └─────┘                                                                           

I'll leave it at that for now for this pull request.

Any objections? @ystade Any opinions?

In principle, this plan sounds solid.
Let me try to collect my thoughts a little bit:

  • I'd like to avoid creating too many shared libraries that are bundled with MQT Core because each one increases our binary sizes. Especially in case of the SC device, these will just be repetitive and produce artificial bloat. Instead, I'd look into making the SC device configurable at session initialization time. We could use a Custom Session parameter to describe the path to a SC JSON config file describing the architecture. If this parameter is not set, the default one that comes with MQT Core is chosen. But this also allows to create generic backends on demand by providing different config files. I am kind of looking for the equivalent of Qiskit's GenericBackendV2, but through QDMI. In QDMI v2 this would be a provider that takes a single config file with multiple architecture and makes all of them available through a single shared library. In v1, we need to hack this together a little bit.

  • I think it would be really beneficial to not only allow a configure-time CMake option but some kind of search mechanism for config files. Quite a bit of tooling out there has good precedents for this kind of logic (consider uv, ruff, or ty as state of the art here). Can't we add config file detection and precedence rules based on these tools? The respective logic is not really special for those tools; nor does it need to be special for our purposes. This also includes defining a proper schema for these config files.

  • I believe the proposal from above does not yet address the problem that we also need to provide a config file in the install tree that needs to resolve to the right paths and not to the build dir. Not rocket science, but needs to be taken care of.

  • I really like the idea of using the config file as the single source of truth for QDMI device registration/loading. Exposing this at various levels makes a lot of sense to me.

Overall, this is definitely the right direction. Happy to discuss further 🙂

@mergify mergify Bot removed the conflict label Jul 14, 2026
@MatthiasReumann

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
mlir/include/mlir/Support/SuperconductingDevice.h (1)

45-46: 📐 Maintainability & Code Quality | 🟡 Minor | 💤 Low value

Document distanceBetween behavior for edge cases.

The Doxygen comment doesn't specify what distanceBetween returns when u == v or when qubits are unreachable. Since the implementation returns 0 for u == v and throws a fatal error for unreachable qubits, documenting this explicitly helps prevent misuse (e.g., unsigned underflow if callers subtract 1 from the distance).

📝 Suggested documentation update
-  /// Return the length of the shortest path between two qubits.
+  /// Return the length of the shortest path between two qubits.
+  ///
+  /// \param u The source qubit index.
+  /// \param v The target qubit index.
+  /// \return The shortest-path distance. The distance from a qubit to itself is 0.
+  /// \note Throws a fatal error if \p u and \p v are unreachable. Callers
+  ///       that subtract 1 for swap counts must guard against a 0 return value.
   [[nodiscard]] size_t distanceBetween(size_t u, size_t v) const;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mlir/include/mlir/Support/SuperconductingDevice.h` around lines 45 - 46,
Update the Doxygen comment for SuperconductingDevice::distanceBetween to
document that it returns 0 when u == v and triggers a fatal error when the
qubits are unreachable, while retaining the existing shortest-path description.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp`:
- Around line 1218-1227: Update createMappingPass to validate that the supplied
SuperconductingDevice has symmetric couplings before constructing MappingPass,
rejecting asymmetric coupling maps; alternatively normalize the map to an
undirected form first. Preserve the existing behavior for valid symmetric
devices and ensure invalid input cannot reach FGraph or the routing heuristic.

In `@mlir/lib/Support/CMakeLists.txt`:
- Around line 9-13: Replace the SUPPORT_CPP file(GLOB_RECURSE) collection with
an explicit list of the directory’s .cpp sources, then pass that list to
MLIRSupportMQT. If retaining globbing is necessary, add CONFIGURE_DEPENDS to
ensure source additions and removals trigger CMake reconfiguration.

In `@mlir/lib/Support/Qdmi.cpp`:
- Around line 63-78: Guard every nlohmann::json::contains call with an is_object
check: update getJsonStringIfExists for jsonObj, the root j checks around
session and devices, and the deviceJson check around libName. Apply these
changes at mlir/lib/Support/Qdmi.cpp lines 28-34, 63-78, and 80-84 respectively,
preserving the existing parsing behavior for valid JSON objects.

In `@mlir/lib/Support/SuperconductingDevice.cpp`:
- Around line 70-81: Replace the aborting mapping.at lookups in the siteCoupling
endpoint transformation with explicit checked lookups for both s0 and s1. If
either endpoint is absent from mapping, report a clear error through the
surrounding SuperconductingDevice validation path instead of crashing; otherwise
preserve insertion of the mapped index pair.

---

Duplicate comments:
In `@mlir/include/mlir/Support/SuperconductingDevice.h`:
- Around line 45-46: Update the Doxygen comment for
SuperconductingDevice::distanceBetween to document that it returns 0 when u == v
and triggers a fatal error when the qubits are unreachable, while retaining the
existing shortest-path description.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 649709e5-d37a-4bf9-b3e6-c81204bdbf1b

📥 Commits

Reviewing files that changed from the base of the PR and between e78c99a and 18423a5.

📒 Files selected for processing (16)
  • CHANGELOG.md
  • mlir/include/mlir/Compiler/CompilerPipeline.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h
  • mlir/include/mlir/Support/Graph.h
  • mlir/include/mlir/Support/Qdmi.h
  • mlir/include/mlir/Support/SuperconductingDevice.h
  • mlir/lib/Compiler/CompilerPipeline.cpp
  • mlir/lib/Dialect/QCO/Transforms/CMakeLists.txt
  • mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
  • mlir/lib/Dialect/QCO/Utils/Graph.cpp
  • mlir/lib/Support/CMakeLists.txt
  • mlir/lib/Support/Qdmi.cpp
  • mlir/lib/Support/SuperconductingDevice.cpp
  • mlir/tools/mqt-cc/mqt-cc.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp
  • src/fomac/FoMaC.cpp

Comment thread mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Comment thread mlir/lib/Support/CMakeLists.txt Outdated
Comment on lines +9 to +13
file(GLOB_RECURSE SUPPORT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")

add_mlir_library(
MLIRSupportMQT
IRVerification.cpp
Passes.cpp
PrettyPrinting.cpp
${SUPPORT_CPP}

@coderabbitai coderabbitai Bot Jul 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid using GLOB to collect source files.

Using file(GLOB_RECURSE) without CONFIGURE_DEPENDS is a well-known CMake anti-pattern. If a developer adds or removes a .cpp file in this directory, the build system will not automatically reconfigure, leading to confusing build failures. It is generally safer to explicitly list the source files.

If you prefer to keep the globbing, consider adding the CONFIGURE_DEPENDS flag (requires CMake 3.12+).

♻️ Proposed fix
-file(GLOB_RECURSE SUPPORT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+file(GLOB_RECURSE SUPPORT_CPP CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
 
 add_mlir_library(
   MLIRSupportMQT
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
file(GLOB_RECURSE SUPPORT_CPP "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_mlir_library(
MLIRSupportMQT
IRVerification.cpp
Passes.cpp
PrettyPrinting.cpp
${SUPPORT_CPP}
file(GLOB_RECURSE SUPPORT_CPP CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_mlir_library(
MLIRSupportMQT
${SUPPORT_CPP}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mlir/lib/Support/CMakeLists.txt` around lines 9 - 13, Replace the SUPPORT_CPP
file(GLOB_RECURSE) collection with an explicit list of the directory’s .cpp
sources, then pass that list to MLIRSupportMQT. If retaining globbing is
necessary, add CONFIGURE_DEPENDS to ensure source additions and removals trigger
CMake reconfiguration.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@burgholzer If this works as described, we might want to add this everywhere.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MatthiasReumann Sounds good — happy to help apply CONFIGURE_DEPENDS more broadly once burgholzer confirms this pattern works well here. Just flagging that CONFIGURE_DEPENDS (CMake ≥ 3.12) still only re-runs the glob at configure time triggered by a build, not automatically on every file save, so it won't fully eliminate the need to re-run CMake in all IDE/workflow setups — but it's a solid middle ground between fully explicit source lists and unguarded globbing. Let me know if you'd like me to scan for other file(GLOB / file(GLOB_RECURSE) usages across the repo so you can decide where else to apply it.

Comment thread mlir/lib/Support/Qdmi.cpp Outdated
Comment thread mlir/lib/Support/SuperconductingDevice.cpp
@mergify mergify Bot added the conflict label Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code conflict MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ MLIR - Feeding Architecture Information into MLIR Mapping Conversion

3 participants