Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
520 changes: 520 additions & 0 deletions .agent/plans/1687-int-final-qdmi-bridge.md

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ build:
- asdf install uv latest
- asdf global uv latest
# Install MLIR
- curl -LsSf https://github.com/munich-quantum-software/setup-mlir/releases/latest/download/setup-mlir.sh | bash -s -- -v 22.1.7 -p $HOME/mlir
- curl -LsSf https://github.com/munich-quantum-software/setup-mlir/releases/download/v1.4.1/setup-mlir.sh | bash -s -- -v 22.1.7 -p $HOME/mlir
build:
html:
- MLIR_DIR=$HOME/mlir/lib/cmake/mlir uvx nox --non-interactive -s docs
- mkdir -p $READTHEDOCS_OUTPUT/html && cp -R docs/_build/html/. $READTHEDOCS_OUTPUT/html
htmlzip:
- MLIR_DIR=$HOME/mlir/lib/cmake/mlir uvx nox --non-interactive -s docs -- -b dirhtml
- mkdir -p $READTHEDOCS_OUTPUT/htmlzip
- zip -r $READTHEDOCS_OUTPUT/htmlzip/html.zip docs/_build/dirhtml/*
- |
mkdir -p $READTHEDOCS_OUTPUT/htmlzip
archive=$(realpath $READTHEDOCS_OUTPUT/htmlzip/html.zip)
(cd docs/_build/html && zip -r $archive .)
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ releases may include breaking changes.

### Added

- ✨ Integrate QDMI devices as MLIR compiler targets across C++, Python, and
`mqt-cc` ([#1687]) ([**@MatthiasReumann**], [**@burgholzer**])
- ✨ Add immutable MLIR compiler targets and a canonical target compilation
pipeline for decomposition, optimization, mapping, native synthesis, and
conformance ([#1993], [#1999]) ([**@simon1hofmann**], [**@burgholzer**])
Expand Down Expand Up @@ -819,6 +821,7 @@ for previous changelogs._
[#1702]: https://github.com/munich-quantum-toolkit/core/pull/1702
[#1700]: https://github.com/munich-quantum-toolkit/core/pull/1700
[#1694]: https://github.com/munich-quantum-toolkit/core/pull/1694
[#1687]: https://github.com/munich-quantum-toolkit/core/pull/1687
[#1676]: https://github.com/munich-quantum-toolkit/core/pull/1676
[#1675]: https://github.com/munich-quantum-toolkit/core/pull/1675
[#1674]: https://github.com/munich-quantum-toolkit/core/pull/1674
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ option(BUILD_MQT_CORE_QDMI_SC_DEVICE "Build the MQT Core superconducting QDMI de
${PROJECT_IS_TOP_LEVEL})
option(BUILD_MQT_CORE_DOCUMENTATION "Generate documentation artifacts as part of the CMake build"
OFF)
if(BUILD_MQT_CORE_TESTS
AND (NOT BUILD_MQT_CORE_QDMI_DDSIM_DEVICE
OR NOT BUILD_MQT_CORE_QDMI_NA_DEVICE
OR NOT BUILD_MQT_CORE_QDMI_SC_DEVICE))
message(FATAL_ERROR "BUILD_MQT_CORE_TESTS requires all bundled QDMI devices")
endif()
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(
FATAL_ERROR
Expand Down
1 change: 1 addition & 0 deletions bindings/mlir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ if(NOT TARGET ${TARGET_NAME})
INSTALL_DIR
.
LINK_LIBS
MQTCompilerFoMaCAdapter
MQTCompilerPipeline
MQT::CoreIR)

Expand Down
264 changes: 258 additions & 6 deletions bindings/mlir/register_mlir.cpp

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions bindings/patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,48 @@ mqt\.core\.fomac\.Device\.Operation\.query_custom_property$:
) -> str | bool | int | float | bytes | None:
\doc

mqt\.core\.mlir\.CompilerTarget\.__init__$:
\from collections.abc import Sequence
\from typing import overload
@overload
def __init__(
self,
num_qubits: int,
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...
@overload
def __init__(
self,
name: str,
num_qubits: int,
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...
@overload
def __init__(
self,
sites: Sequence[CompilerTarget.Site],
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...
@overload
def __init__(
self,
name: str,
sites: Sequence[CompilerTarget.Site],
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...

mqt.core.mlir.compile_program:
\from typing import overload, Literal
@overload
Expand All @@ -100,6 +142,7 @@ mqt.core.mlir.compile_program:
*,
output: Literal[OutputFormat.QC, OutputFormat.QC_IMPORT] = ...,
inplace: bool = False,
target: CompilerTarget | None = None,
qco_pipeline: str = "mqt-qco-default",
enable_timing: bool = False,
enable_statistics: bool = False,
Expand All @@ -116,6 +159,7 @@ mqt.core.mlir.compile_program:
*,
output: Literal[OutputFormat.QCO, OutputFormat.QCO_OPTIMIZED],
inplace: bool = False,
target: CompilerTarget | None = None,
qco_pipeline: str = "mqt-qco-default",
enable_timing: bool = False,
enable_statistics: bool = False,
Expand All @@ -132,6 +176,7 @@ mqt.core.mlir.compile_program:
*,
output: Literal[OutputFormat.JEFF],
inplace: bool = False,
target: CompilerTarget | None = None,
qco_pipeline: str = "mqt-qco-default",
enable_timing: bool = False,
enable_statistics: bool = False,
Expand All @@ -148,6 +193,7 @@ mqt.core.mlir.compile_program:
*,
output: Literal[OutputFormat.QIR_BASE, OutputFormat.QIR_ADAPTIVE],
inplace: bool = False,
target: CompilerTarget | None = None,
qco_pipeline: str = "mqt-qco-default",
enable_timing: bool = False,
enable_statistics: bool = False,
Expand All @@ -164,6 +210,7 @@ mqt.core.mlir.compile_program:
*,
output: OutputFormat,
inplace: bool = False,
target: CompilerTarget | None = None,
qco_pipeline: str = "mqt-qco-default",
enable_timing: bool = False,
enable_statistics: bool = False,
Expand Down
5 changes: 4 additions & 1 deletion docs/mlir/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ quantum-classical compilation framework built on the Multi-Level Intermediate
Representation (MLIR). For an overview, see {cite:p}`MQTCompilerCollection2026`.

The {doc}`Python compiler guide <python_compiler_collection>` describes how to
compile and inspect quantum programs from Python. The remaining pages are the
compile and inspect quantum programs from Python. The
{doc}`target-compilation guide <target_compilation>` shows how to compile for
QDMI devices from Python, C++, and `mqt-cc`. The remaining pages are the
technical reference for the underlying MLIR infrastructure.

We define multiple dialects, each with its dedicated purpose:
Expand All @@ -29,6 +31,7 @@ interoperability, we provide {doc}`conversions <Conversions>` between dialects.
:maxdepth: 2

python_compiler_collection
target_compilation
QC
QCO
QTensor
Expand Down
3 changes: 3 additions & 0 deletions docs/mlir/python_compiler_collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Install {doc}`MQT Core <../installation>` and import the compiler interface:
from mqt.core.mlir import OutputFormat, QCProgram, QIRProfile, compile_program
```

To compile for a configured QDMI device, see
{doc}`target compilation <target_compilation>`.

## Compile an OpenQASM program

The following OpenQASM program prepares a Bell state and records the outcome of
Expand Down
104 changes: 104 additions & 0 deletions docs/mlir/target_compilation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Compile for a QDMI device

An MLIR {code}`mlir::CompilerTarget` is an immutable snapshot of a circuit-model
device. It contains the device sites, topology, native operations, and available
calibration data. Compilation decomposes supported multi-qubit operations,
optimizes and maps the program, synthesizes native gates, and verifies that the
result conforms to the target.

The snapshot is independent of its originating QDMI session. It can therefore be
stored, copied cheaply, and reused for multiple compilations.

## Python

Open a configured QDMI device and snapshot it as a compiler target:

```python
from mqt.core.fomac import open_device
from mqt.core.mlir import CompilerTarget, OutputFormat, compile_program

target = CompilerTarget.from_device(open_device("mqt.sc.iqm.garnet"))
compiled = compile_program(
"bell.qasm",
target=target,
output=OutputFormat.QCO_OPTIMIZED,
)
```

Target compilation accepts optimized QCO, QC, or QIR output and uses the
canonical QCO pipeline; it cannot be combined with a custom `qco_pipeline`.

The target can also be constructed directly. Omitting `couplings` selects
all-to-all connectivity; omitting `operations` means that every operation is
native:

```python
target = CompilerTarget(3, couplings=[(0, 1), (1, 2)])
```

Use {py:meth}`~mqt.core.mlir.QCOProgram.compile_for_target` to apply target
compilation to an existing QCO program. For pass-level benchmarking, the C++ API
exposes separate factories for pre-routing optimization, mapping, native
synthesis, and conformance verification.

## Command line from a source build

List the stable IDs of configured QDMI devices:

```console
mqt-cc --qdmi-list-devices
```

Select a device when compiling:

```console
mqt-cc --qdmi-device=mqt.sc.iqm.garnet \
--emit=qco-optimized input.qasm
```

An explicit registry file can be selected before device discovery:

```console
mqt-cc --qdmi-config=/path/to/qdmi.json \
--qdmi-device=example.device input.qasm
```

Target compilation produces optimized QCO, QC, or QIR. It cannot be combined
with a custom `--passes` pipeline because the canonical target pipeline owns the
required pass ordering.

## C++ source-tree API

The source build provides a narrow FoMaC bridge between a live QDMI device and
the compiler-owned target:

```cpp
#include "fomac/FoMaC.hpp"
#include "mlir/Compiler/FoMaCAdapter.h"
#include "mlir/Compiler/Programs.h"

auto device = fomac::Session::openDevice("mqt.sc.iqm.garnet");
auto target = mlir::compilerTargetFromDevice(device);

auto qc = mlir::QCProgram::fromQASMFile("input.qasm");
if (!qc) {
return 1;
}
auto qco = std::move(*qc).intoQCO();
if (!qco || !qco->compileForTarget(target)) {
return 1;
}
```

The adapter accepts circuit-model devices whose operations are available
throughout the topology in both operand orientations. Operand-symmetric gates,
such as CZ, may report each edge once. Neutral-atom zone models require a
different compilation model and are rejected with a diagnostic.

The bundled Garnet and Emerald snapshots contain available T1, T2, and fidelity
data. Operation durations are absent because they were unavailable. See
{doc}`../qdmi/sc_device` for their stable IDs and {doc}`../qdmi/configuration`
for registry configuration.

If the program should use fewer physical qubits, run the {code}`mqt-qubit-reuse`
pipeline before target compilation.
5 changes: 3 additions & 2 deletions docs/qdmi/driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ integration tests.

The QDMI driver and FoMaC libraries are available independently. Device-free
builds can register external device libraries through
[QDMI device configuration](configuration.md). When MQT Core's C++ tests are
enabled, device-specific tests are omitted with their corresponding device.
[QDMI device configuration](configuration.md). Building MQT Core's C++ tests
requires all three bundled devices so that the complete device integration is
tested.

## Python Bindings

Expand Down
32 changes: 32 additions & 0 deletions mlir/include/mlir/Compiler/FoMaCAdapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#pragma once

#include "mlir/Compiler/Target.h"

namespace fomac {
class Device;
} // namespace fomac

namespace mlir {

/**
* @brief Snapshot a circuit-model QDMI device as an MLIR compiler target.
*
* @details The returned target owns all queried metadata and remains valid
* after the originating device and session have been destroyed. Neutral-atom
* zone models and site-dependent operation support are not supported by the
* circuit-model compiler pipeline.
*/
[[nodiscard]] CompilerTarget
compilerTargetFromDevice(const fomac::Device& device);

} // namespace mlir
4 changes: 2 additions & 2 deletions mlir/include/mlir/Compiler/TargetCompilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class OpPassManager;
*
* @details Decomposes supported multi-controlled gates, performs
* target-independent optimization, maps to the target topology, synthesizes
* native operations, verifies target conformance, and cleans up the resulting
* QCO program.
* native operations, performs a final local cleanup, and verifies target
* conformance.
*/
void populateTargetCompilationPipeline(OpPassManager& pm,
const CompilerTarget& target);
Expand Down
20 changes: 19 additions & 1 deletion mlir/lib/Compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ mqt_mlir_target_use_project_options(MQTCompilerTarget)
target_sources(MQTCompilerTarget PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_MLIR_SOURCE_INCLUDE_DIR}
FILES ${MQT_MLIR_SOURCE_INCLUDE_DIR}/mlir/Compiler/Target.h)

# Build the optional FoMaC-to-compiler-target adapter
add_mlir_library(
MQTCompilerFoMaCAdapter
PARTIAL_SOURCES_INTENDED
FoMaCAdapter.cpp
ADDITIONAL_HEADER_DIRS
${MQT_MLIR_SOURCE_INCLUDE_DIR}/mlir/Compiler
LINK_LIBS
PUBLIC
MQTCompilerTarget
MQT::CoreFoMaC)

mqt_mlir_target_use_project_options(MQTCompilerFoMaCAdapter)

target_sources(
MQTCompilerFoMaCAdapter PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_MLIR_SOURCE_INCLUDE_DIR} FILES
${MQT_MLIR_SOURCE_INCLUDE_DIR}/mlir/Compiler/FoMaCAdapter.h)

# Build the compiler pipeline library
add_mlir_library(
MQTCompilerPipeline
Expand Down Expand Up @@ -58,7 +76,7 @@ mqt_mlir_target_use_project_options(MQTCompilerPipeline)

# collect header files
file(GLOB_RECURSE COMPILER_HEADERS_SOURCE "${MQT_MLIR_SOURCE_INCLUDE_DIR}/mlir/Compiler/*.h")
list(FILTER COMPILER_HEADERS_SOURCE EXCLUDE REGEX "/Target\\.h$")
list(FILTER COMPILER_HEADERS_SOURCE EXCLUDE REGEX "/(FoMaCAdapter|Target)\\.h$")

target_sources(MQTCompilerPipeline PUBLIC FILE_SET HEADERS BASE_DIRS ${MQT_MLIR_SOURCE_INCLUDE_DIR}
FILES ${COMPILER_HEADERS_SOURCE})
Loading
Loading