Skip to content

✨ Build target environments from QDMI payloads - #2227

Open
burgholzer wants to merge 2 commits into
codex/qdmi-v14-payload-contractfrom
codex/qdmi-target-environment-adapter
Open

✨ Build target environments from QDMI payloads#2227
burgholzer wants to merge 2 commits into
codex/qdmi-v14-payload-contractfrom
codex/qdmi-target-environment-adapter

Conversation

@burgholzer

@burgholzer burgholzer commented Aug 24, 2026

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Description

Build one owning compiler TargetEnvironment from an exact payload accepted by a QDMI device.

This pull request:

  • verifies that the selected descriptor is advertised by the device;
  • snapshots the device target and payload specification into a context-free value;
  • groups optional QDMI feature records and preserves their typed constraints;
  • adds the normative QIR Adaptive baseline without conflating it with optional metadata completeness;
  • exposes C++ factories for an open device and a registered device ID; and
  • exposes matching TargetEnvironment.from_device and from_device_id Python factories.

This PR is stacked on #2226, which supplies the low-level QDMI 1.4 payload contract. Together they complete the QDMI integration requested during review of #2219.

Validation on the complete stack:

  • full release build: passed;
  • all configured CTest cases: 4,073/4,073 passed, with one expected SC job-ID skip;
  • focused TargetEnvironment adapter tests: 10/10 passed;
  • Python factory tests: 2/2 passed;
  • stub generation: passed;
  • documentation build: passed; and
  • full lint: passed.

AI assistance: OpenAI Codex assisted with implementation, review, testing, and this description.

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:

  • Any agent that created, edited, or submitted GitHub content was explicitly authorized for that scope, as required by our AI Usage Guidelines.
  • Every agent-authored or agent-edited public text body begins with the visible disclosure 🤖 *AI text below* 🤖 (titles are exempt).
  • I have disclosed AI assistance in the PR description.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

@burgholzer burgholzer added feature New feature or request c++ Anything related to C++ code python Anything related to Python code MLIR Anything related to MLIR QDMI Anything related to QDMI labels Aug 24, 2026
@burgholzer burgholzer self-assigned this Aug 24, 2026
@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch from 000f1a7 to 119e8dd Compare August 24, 2026 14:55
@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch from 119e8dd to 5aefae1 Compare August 24, 2026 15:00
@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch from 5aefae1 to f6ccb12 Compare August 24, 2026 15:35
@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch 2 times, most recently from c463a53 to 4289979 Compare August 24, 2026 16:22
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.70330% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mlir/lib/Compiler/QDMIAdapter.cpp 96.7% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch 3 times, most recently from fcf7027 to 0c598df Compare August 24, 2026 20:10
Snapshot one exact device-supported descriptor, its grouped optional features, and its normative baseline into an owning TargetEnvironment. Expose matching C++ and Python factories.

Assisted-by: GPT-5.6 Sol via Codex
Exercise constrained and malformed feature groups, invalid descriptors, snapshot propagation, and exception containment through the public adapter entry points.

Remove duplicate validation branches that cannot run after the QDMI C++ client validates provider records and encodings.

Assisted-by: GPT-5.6 Sol via Codex
@burgholzer
burgholzer force-pushed the codex/qdmi-target-environment-adapter branch from 0c598df to 6d85e61 Compare August 24, 2026 23:47
@burgholzer burgholzer added this to the MLIR Support milestone Aug 25, 2026

@burgholzer burgholzer left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This largely looks good to me. I one simplification request, one lifted constraint and likely some better bindings. I have the feeling that changes in the lower layers of the PR stack will trigger a few more changes here.

I am also wondering whether there is a bit too much overlap/duplication between the MLIR and the QDMI concepts and whether some of that could be simplified while still maintaining the proper separation between the two.

@denialhaag @simon1hofmann same question here as in the other PRs: Do you also see some things that need changes?

Comment on lines +49 to +70
/**
* @brief Snapshot a QDMI device and one accepted payload as a target
* environment.
*
* @details The adapter preserves the exact program format, groups feature
* records with the same ID and value, and adds the normative baseline of a
* standard payload. Unknown optional feature metadata remains unknown.
*/
[[nodiscard]] llvm::Expected<TargetEnvironment>
targetEnvironmentFromDevice(const qdmi::Device& device,
const QDMI_Program_Format& format);

/**
* @brief Open a registered QDMI device and snapshot one accepted payload.
*
* @details This adapter contains exceptions from the QDMI C++ API and returns
* them as LLVM errors. The returned environment owns all queried metadata.
*/
[[nodiscard]] llvm::Expected<TargetEnvironment>
targetEnvironmentFromDeviceId(std::string_view deviceId,
const QDMI_Program_Format& format);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is just me trying to be pragmatic: Most devices will expose a single payload format that they support. In these cases, it would be quite convenient to define a shortcut that either just uses the device or the ID without an explicit program format in the call.
The only thing to choose would be what to do with devices that offer multiple formats. One plausible option would be to default to the first supported format, which, by definition, is the preferred format by the device.
It should likely be pointed out explicitly that there is an overload for the convenience shortcut that allows specifying an explicit format.
As a follow-up, all code that does not explicitly need it otherwise and all docs may be moved to the convenience function.

Comment on lines +452 to +455
if (format.id != "qir" || format.version != "2.1.0" ||
format.profile != "adaptive") {
return {};
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The 2.1.0 feels a bit more restrictive than this likely needs to be.

Comment thread python/mqt/core/mlir.pyi

import qiskit.circuit

import mqt.core.qdmi

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This line feels odd and I am pretty sure that we can get rid of that by better writing the bindings.

@burgholzer
burgholzer marked this pull request as ready for review August 25, 2026 12:40

@simon1hofmann simon1hofmann 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.

Only have a couple of comments about the docs, but besides that this PR also looks really good!

return copyValue(DEVICE_NAME.data(), DEVICE_NAME.size() + 1U, size, value,
sizeRet);
}
case QDMI_DEVICE_PROPERTY_QUBITSNUM: {

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.

Was this the reason for calling it qubits_num in the other PR?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah. Mainly. But we use the other wording practically everywhere else. So I would be fine with the syntactic break going from C to C++.

metadata are unknown unless the caller states them:

```python
target = CompilerTarget(

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.

CompilerTarget is not imported anymore (deleted in line 18).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah. We need to be careful here while the docs in CI are failing. They should still all pass locally for all of the changes here and produce correct output.

environment = TargetEnvironment(target, payload)
environment = TargetEnvironment.from_device_id(
"mqt.sc.iqm.garnet",
ProgramFormat.QIR21_BASE_BINARY,

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.

The SC provider does not advertise any program formats right?
Same for the example in lines 111-112.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It does not. But maybe it should.
Maybe the configuration for the device should include which formats the device claims to accept/support. Would allow a more faithful model of an IQM machine.

@denialhaag denialhaag left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This also LGTM! 🙂 I just have one nitpick and a comment on the documentation:

#include <nanobind/stl/string_view.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/variant.h> // NOLINT(misc-include-cleaner)
#include <nanobind/stl/vector.h> // NOLINT(misc-include-cleaner)
#include <qdmi/constants.h>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We still need to streamline our includes when we have fewer PRs open, but this would comply with the current style:

Suggested change
#include <qdmi/constants.h>
#include "qdmi/constants.h"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah. You are right. Still have this wired wrongly in my brain. We did device at some point to only treat stdlib includes with angle brackets, right?
Because this is still an external header pulled in as a dependency.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, but then we changed our minds again, following the discussion in FullStaQD/qcc#37. I still have it on my list to apply this across the MQT. Maybe just before the v4 release is a good time, since we hopefully won't have too many open PRs at that point. 🤔

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah. Before the release makes sense.
We may even want to consider that as a point where we may use an "mqt" namespace for our code to differentiate it a tad bit more from plain mlir. Similar to how this is done in FullStaQD with qcc. I was initially opposed to that but I am starting to see the potential benefits.

Comment on lines -35 to +38
The payload specification identifies the exact representation selected for the
device. MQT Core derives the compiler output from that specification and uses
The QDMI adapter checks that the device accepts the exact program format. It
groups program-feature records by ID and value, adds the selected format's
normative baseline, and preserves whether the optional feature list is known.
MQT Core derives the compiler output from this payload specification and uses
the canonical QCO pipeline. The targeted overload therefore accepts one
`TargetEnvironment` and no independent output or custom pipeline. MQT Core's
QDMI adapter does not yet translate QDMI program-format and feature metadata, so
callers must construct the payload specification from the device documentation.

The example has no reported execution capabilities. A producer must add every
effective capability, including the selected format's baseline. Set
`optional_capabilities_known=True` only when the producer also knows that the
list contains every optional device capability.
`TargetEnvironment` and no independent output or custom pipeline.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This might just be me, but this feels overly technical and not user-facing. Again, this might just be me, but my brain switched off while I was reading. 🤠

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This entire page needs a revamp once the implementation is consolidated.
And some of the terminology might still need bike shedding. As pointed out in several of my own review comments, I am not quite happy yet with how some of the things are framed.

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 feature New feature or request MLIR Anything related to MLIR python Anything related to Python code QDMI Anything related to QDMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants