Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
781bf60
♻️ Generalize compiler target facts
burgholzer Aug 23, 2026
7bef032
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 23, 2026
9308dc3
📝 Fold compiler target work into launch changelog
burgholzer Aug 23, 2026
4ca2178
🧪 State DDSIM target facts explicitly
burgholzer Aug 23, 2026
73c5008
⚡️ Use compact LLVM target checks
burgholzer Aug 23, 2026
c18c964
♻️ Use LLVM views for target collections
burgholzer Aug 24, 2026
d860d65
🐛 Preserve compiler target fact semantics
burgholzer Sep 1, 2026
cda6182
🐛 Describe DDSIM compiler target facts
burgholzer Sep 1, 2026
5ed0f5c
🧪 Isolate mqt-cc test scratch files
burgholzer Sep 1, 2026
56ecd62
🧪 Test an unused custom property slot
burgholzer Sep 1, 2026
3f71713
♻️ Integrate topology-free placement
burgholzer Sep 1, 2026
ef17752
♻️ Complete compiler target capabilities
burgholzer Sep 1, 2026
1ad5f72
♻️ Simplify target synthesis invariants
burgholzer Sep 1, 2026
14e0132
🐛 Derive controlled gates from variadic bases
simon1hofmann Sep 2, 2026
7dc1143
🐛 Remove empty controls after phase normalization
simon1hofmann Sep 2, 2026
64bad12
♻️ Move empty control cleanup into phase normalization
simon1hofmann Sep 2, 2026
2ecba6e
♻️ Simplify reverse operation cleanup
burgholzer Sep 2, 2026
808be13
🐛 Preserve reverse deletion iterators
simon1hofmann Sep 2, 2026
ba81d4b
🧪 Update mapping target construction
simon1hofmann Sep 2, 2026
1bc668b
🧪 Update compiler target construction
simon1hofmann Sep 2, 2026
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
271 changes: 271 additions & 0 deletions .agent/plans/generalize-compiler-target.md

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ releases may include breaking changes.
[#1807], [#1808], [#1815], [#1824], [#1869], [#1872], [#1914], [#1925],
[#1927], [#1935], [#1936], [#1938], [#1975], [#1976], [#2006], [#2014],
[#2015], [#2017], [#2026], [#2028], [#2054], [#2058], [#2125], [#2136],
[#2149], [#2150], [#2158], [#2194], [#2210], [#2211], [#2220])
[#2149], [#2150], [#2158], [#2194], [#2210], [#2211], [#2220], [#2218])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**],
[**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**],
[**@simon1hofmann**], [**@J4MMlE**])
Expand Down Expand Up @@ -879,17 +879,18 @@ for previous changelogs._
[#2257]: https://github.com/munich-quantum-toolkit/core/pull/2257
[#2249]: https://github.com/munich-quantum-toolkit/core/pull/2249
[#2246]: https://github.com/munich-quantum-toolkit/core/pull/2246
[#2220]: https://github.com/munich-quantum-toolkit/core/pull/2220
[#2232]: https://github.com/munich-quantum-toolkit/core/pull/2232
[#2228]: https://github.com/munich-quantum-toolkit/core/pull/2228
[#2224]: https://github.com/munich-quantum-toolkit/core/pull/2224
[#2209]: https://github.com/munich-quantum-toolkit/core/pull/2209
[#2211]: https://github.com/munich-quantum-toolkit/core/pull/2211
[#2220]: https://github.com/munich-quantum-toolkit/core/pull/2220
[#2218]: https://github.com/munich-quantum-toolkit/core/pull/2218
[#2217]: https://github.com/munich-quantum-toolkit/core/pull/2217
[#2210]: https://github.com/munich-quantum-toolkit/core/pull/2210
[#2216]: https://github.com/munich-quantum-toolkit/core/pull/2216
[#2203]: https://github.com/munich-quantum-toolkit/core/pull/2203
[#2214]: https://github.com/munich-quantum-toolkit/core/pull/2214
[#2211]: https://github.com/munich-quantum-toolkit/core/pull/2211
[#2210]: https://github.com/munich-quantum-toolkit/core/pull/2210
[#2209]: https://github.com/munich-quantum-toolkit/core/pull/2209
[#2203]: https://github.com/munich-quantum-toolkit/core/pull/2203
[#2194]: https://github.com/munich-quantum-toolkit/core/pull/2194
[#2193]: https://github.com/munich-quantum-toolkit/core/pull/2193
[#2185]: https://github.com/munich-quantum-toolkit/core/pull/2185
Expand Down
2 changes: 1 addition & 1 deletion bindings/mlir/qiskit/QiskitExport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2109,7 +2109,7 @@ nb::object exportCircuit(const mlir::QCProgram& program,
ExportState state;
collectParameters(function, state);
if (target != nullptr) {
state.numQubits = checkedIndex(static_cast<uint64_t>(target->numQubits()),
state.numQubits = checkedIndex(static_cast<uint64_t>(target->numSites()),
"target qubit count");
}
collectResources(function, state, target);
Expand Down
237 changes: 161 additions & 76 deletions bindings/mlir/register_mlir.cpp

Large diffs are not rendered by default.

33 changes: 23 additions & 10 deletions bindings/patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,29 +92,29 @@ mqt\.core\.mlir\.CompilerTarget\.__init__$:
@overload
def __init__(
self,
num_qubits: int,
num_sites: int,
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
connectivity: CompilerTarget.Connectivity,
native_operations: CompilerTarget.NativeOperations,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...
@overload
def __init__(
self,
name: str,
num_qubits: int,
num_sites: int,
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
connectivity: CompilerTarget.Connectivity,
native_operations: CompilerTarget.NativeOperations,
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,
connectivity: CompilerTarget.Connectivity,
native_operations: CompilerTarget.NativeOperations,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...
@overload
Expand All @@ -123,11 +123,24 @@ mqt\.core\.mlir\.CompilerTarget\.__init__$:
name: str,
sites: Sequence[CompilerTarget.Site],
*,
couplings: Sequence[tuple[int, int]] | None = None,
operations: Sequence[CompilerTarget.Operation] | None = None,
connectivity: CompilerTarget.Connectivity,
native_operations: CompilerTarget.NativeOperations,
duration_unit: CompilerTarget.DurationUnit | None = None,
) -> None: ...

mqt\.core\.mlir\.CompilerTarget\.Operation\.__init__$:
\from collections.abc import Sequence
def __init__(
self,
name: str,
arity: int | CompilerTarget.OperationArity,
num_parameters: int,
site_tuples: Sequence[CompilerTarget.SiteTuple] | None = None,
duration: int | None = None,
fidelity: float | None = None,
) -> None:
\doc

mqt\.core\.mlir\.CompilerTarget\.from_device$:
\from mqt.core.qdmi import Device
@staticmethod
Expand Down
54 changes: 48 additions & 6 deletions docs/mlir/target_compilation.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,45 @@ compiled = compile_program(
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:
The target can also be constructed directly. Connectivity and native-operation
support are required:

```python
target = CompilerTarget(3, couplings=[(0, 1), (1, 2)])
target = CompilerTarget(
3,
connectivity=CompilerTarget.Connectivity([(0, 1), (1, 2)]),
native_operations=CompilerTarget.NativeOperations([
CompilerTarget.Operation(
"gphase",
arity=CompilerTarget.OperationArity.fixed(0),
num_parameters=1,
),
CompilerTarget.Operation("u", arity=1, num_parameters=3),
CompilerTarget.Operation("cx", arity=2, num_parameters=0),
CompilerTarget.Operation("measure", arity=1, num_parameters=0),
CompilerTarget.Operation("reset", arity=1, num_parameters=0),
]),
)
```

Use `CompilerTarget.Connectivity.all_to_all()` for an all-to-all target. An
empty `CompilerTarget.NativeOperations([])` reports that no quantum operation is
native. It can be used with passes that need only topology, but target
compilation cannot lower quantum operations without a synthesis basis. Use
`CompilerTarget.NativeOperations.unrestricted()` only when the target accepts
every operation. Creating a target from a QDMI device fails if the device does
not provide a complete connectivity model and a representable native-operation
set. An explicit operation arity is either fixed or variadic with a positive,
inclusive minimum. Fixed zero represents a global-phase operation. A variadic
capability accepts every total width from its minimum through the target's site
count; site-specific calibration tuples are therefore available only for fixed,
positive arities. Structural and program-format constructs are not
compiler-target operations.

Target synthesis preserves a native `gphase`. If the target does not support
`gphase`, target synthesis preserves relative phase effects and removes only the
unobservable global phase of the entry point.

Use {py:meth}`~mqt.core.mlir.QCOProgram.compile_for_target` to apply target
compilation to an existing QCO program. Compilation runs in place. If a pass
fails, earlier passes may already have changed the program. Copy the program
Expand Down Expand Up @@ -107,9 +138,20 @@ if (!qco || !qco->compileForTarget(*target)) {

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
such as CZ, may report each edge once. Operations with arity above two must
report every ordered tuple of distinct sites. Neutral-atom zone models require a
different compilation model and are rejected with a diagnostic.

QDMI 1.3 cannot report an operation-arity range. The bundled DDSIM device uses
an exact, versioned custom-operation marker to state that each canonical
standard gate with one or more targets accepts arbitrary positive controls. The
adapter turns such a base gate into a variadic capability whose minimum is the
base gate's target count. For example, DDSIM reports `h` with minimum one, `rxx`
with minimum two, and `rccx` with minimum three; each also accepts any
additional number of controls up to the simulator's site count. Controlled
aliases such as `mcx` and `mcp` are not enumerated as compiler capabilities.
This private bridge can be removed when QDMI standardizes equivalent metadata.

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`
Expand All @@ -125,6 +167,6 @@ When exporting a program that has already been mapped to a
{py:meth}`~mqt.core.mlir.QCProgram.to_qiskit`. The exporter maps each static
target site ID to its index in {py:attr}`~mqt.core.mlir.CompilerTarget.sites`
and creates a canonical physical Qiskit circuit. The circuit has one register
named {code}`q` with {py:attr}`~mqt.core.mlir.CompilerTarget.num_qubits` qubits.
named {code}`q` with {py:attr}`~mqt.core.mlir.CompilerTarget.num_sites` qubits.
This option does not run target compilation or emit Qiskit layout metadata.
Target-aware export requires static qubits whose site IDs belong to that target.
Loading
Loading