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
13 changes: 8 additions & 5 deletions .agent/plans/qco-dd-execution-and-sampling.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ final basis state. QC coalesces static references; QCO owns one root per index.
- Decision: with an MQT entry point, every `qco.static` belongs to its entry
block with unique indices; helpers take arguments. Verify transforms on both
sides. Rationale: one QCO ownership boundary. Date: 2026-08-29.
- Decision: `sample` encodes returned CBits in return order, MSB-first; no CBit
uses `measureAll`; mixed or undefined outputs fail. Loops use widened `APInt`
and one 10,000-step budget. Date: 2026-08-26.
- Decision: `sample` uses conventional count-string order: the last returned
CBit register comes first, and each register is MSB-first. This avoids adapter
reordering. Date: 2026-09-02.
- Decision: without CBit results, `sample` uses `measureAll`; mixed or undefined
outputs fail. Loops use widened `APInt` and one 10,000-step budget. Date:
2026-08-26.

## Outcomes & Retrospective

Expand All @@ -51,8 +54,8 @@ checks public transform boundaries; and

The Python API is `program.build_functionality(dd_package) -> MatrixDD`,
`program.simulate(initial_state, dd_package, seed=0) -> VectorDD`, and
`program.sample(dd_package, shots=1024, seed=0) -> dict[str, int]`. The public
C++ simulation function always receives an RNG. Static sampling evolves once,
`program.sample(shots=1024, seed=0) -> dict[str, int]`. The public C++
simulation function always receives an RNG. Static sampling evolves once,
adaptive control runs per shot, and returned CBits share storage across calls.

## Milestones
Expand Down
4 changes: 1 addition & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,8 @@ MQT Core. The project-wide policy for AI-assisted contributions is
`cpp-linter` check on every line of each changed C++ file. A changed-line
`clang-tidy` run is useful while iterating but is not sufficient validation.
- Run a component binary directly when iterating, for example
`./build/release/test/ir/mqt-core-ir-test` or
`./build/release/test/qdmi/driver/mqt-core-qdmi-driver-test`.
- Use GoogleTest filters to narrow a binary further, for example
`./build/release/test/ir/mqt-core-ir-test --gtest_filter='StandardOperation.*'`.
- Use GoogleTest filters to narrow a binary further.
- Replace `release` with `debug` for a debug build. Consult `CMakePresets.json`
for other supported configurations.

Expand Down
16 changes: 7 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ releases may include breaking changes.
([#2259]) ([**@denialhaag**])
- ⬆️ Raise the macOS deployment target to 13.3 to enable `std::format` in libc++
([#2259]) ([**@denialhaag**])
- πŸ’₯ Move circuit IR OpenQASM serialization from operation subclasses to
`OpenQASMSerializer` ([#2249]) ([**@simon1hofmann**])
- πŸ’₯ Require Python 3.11 or newer ([#2209]) ([**@denialhaag**],
[**@burgholzer**])
- ⬆️ Update `nanobind` to version 3.0.1 ([#2209], [#2283]) ([**@denialhaag**],
Expand All @@ -109,8 +107,6 @@ releases may include breaking changes.
([**@burgholzer**])
- πŸ› Protect process-wide DD, IR, and QDMI state for free-threaded Python
([#2209]) ([**@burgholzer**])
- πŸ’₯ Prune dead and misleading CoreIR APIs and remove random-number generator
state from `QuantumComputation` ([#2111], [#2112]) ([**@simon1hofmann**])
Comment thread
simon1hofmann marked this conversation as resolved.
- πŸ’₯ Update QIR execution for QIR 2.1, isolated runtimes, deterministic QDMI
sampling, and safe statevector extraction ([#2035], [#2036], [#2246])
([**@burgholzer**], [**@denialhaag**])
Expand All @@ -121,13 +117,15 @@ releases may include breaking changes.

### Removed

- πŸ’₯ Remove `qc::QuantumComputation`, `MQT::CoreIR`, and `MQT::CoreQASM`. Use
compiler-backed QC/QCO APIs in v4 or the MQT Core v3 release series for legacy
code ([#2111], [#2112], [#2288]) ([**@burgholzer**], [**@simon1hofmann**])
- πŸ’₯ Remove the `spdlog` dependency from MQT Core source builds, installed CMake
packages, and Python wheels. QDMI diagnostics continue to be written to
standard error ([#2270]) ([**@denialhaag**])
- πŸ’₯ Remove `CircuitOptimizer`. Move circuit flattening and final-measurement
removal to `QuantumComputation`, equivalence-checking transformations to MQT
QCEC, and mapping transformations to MQT QMAP. Move single-qubit gate fusion
to both downstream packages. Remove the public circuit dependency graph and
- πŸ’₯ Remove `CircuitOptimizer`. Move equivalence-checking transformations to MQT
QCEC and mapping transformations to MQT QMAP. Move single-qubit gate fusion to
both downstream packages. Remove the public circuit dependency graph and
transformations without production consumers ([#2262]) ([**@simon1hofmann**])
- πŸ’₯ Remove test-only DD state generators and recursive functionality
construction from MQT Core ([#2257]) ([**@simon1hofmann**])
Expand Down Expand Up @@ -871,13 +869,13 @@ for previous changelogs._
[#2298]: https://github.com/munich-quantum-toolkit/core/pull/2298
[#2284]: https://github.com/munich-quantum-toolkit/core/pull/2284
[#2283]: https://github.com/munich-quantum-toolkit/core/pull/2283
[#2288]: https://github.com/munich-quantum-toolkit/core/pull/2288
[#2278]: https://github.com/munich-quantum-toolkit/core/pull/2278
[#2270]: https://github.com/munich-quantum-toolkit/core/pull/2270
[#2262]: https://github.com/munich-quantum-toolkit/core/pull/2262
[#2259]: https://github.com/munich-quantum-toolkit/core/pull/2259
[#2258]: https://github.com/munich-quantum-toolkit/core/pull/2258
[#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
Expand Down
21 changes: 7 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ option(BUILD_MQT_CORE_DOCUMENTATION "Generate documentation artifacts as part of
if(BUILD_MQT_CORE_DOCUMENTATION AND NOT BUILD_MQT_CORE_MLIR)
message(FATAL_ERROR "BUILD_MQT_CORE_DOCUMENTATION requires BUILD_MQT_CORE_MLIR")
endif()
if(BUILD_MQT_CORE_TESTS AND (NOT BUILD_MQT_CORE_QDMI_DDSIM_DEVICE OR NOT
BUILD_MQT_CORE_QDMI_SC_DEVICE))
message(FATAL_ERROR "BUILD_MQT_CORE_TESTS requires all bundled QDMI devices")
if(BUILD_MQT_CORE_TESTS AND (NOT BUILD_MQT_CORE_QDMI_SC_DEVICE
OR (BUILD_MQT_CORE_MLIR AND NOT BUILD_MQT_CORE_QDMI_DDSIM_DEVICE)))
message(FATAL_ERROR "BUILD_MQT_CORE_TESTS requires all available bundled QDMI devices")
endif()
if(BUILD_MQT_CORE_MLIR)
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
Expand Down Expand Up @@ -149,7 +149,6 @@ if(BUILD_MQT_CORE_MLIR)
COMMENT "Copying and cleaning up generated MLIR documentation"
VERBATIM)
endif()

if(BUILD_MQT_CORE_DOCUMENTATION)
if(PROJECT_IS_TOP_LEVEL)
add_custom_target(mqt-core-docs DEPENDS mlir-doc)
Expand All @@ -164,25 +163,19 @@ if(BUILD_MQT_CORE_MLIR)
COMMENT "Copying and cleaning up generated MLIR documentation"
VERBATIM)
endif()
foreach(binding ir dd qdmi)
foreach(binding dd qdmi)
add_dependencies(${MQT_CORE_TARGET_NAME}-${binding}-bindings mqt-core-docs)
endforeach()
endif()
endif()

if(BUILD_MQT_CORE_BINDINGS)
set(MQT_CORE_WHEEL_TARGETS
mqt-core-bench-bindings
mqt-core-bench-library
mqt-core-ir
mqt-core-dd
mqt-core-ir-bindings
mqt-core-dd-bindings
mqt-core-qdmi-bindings)
set(MQT_CORE_WHEEL_TARGETS mqt-core-bench-bindings mqt-core-bench-library mqt-core-dd
mqt-core-dd-bindings mqt-core-qdmi-bindings)
if(BUILD_MQT_CORE_MLIR)
list(APPEND MQT_CORE_WHEEL_TARGETS mqt-core-bench mqt-core-mlir-bindings)
endif()
if(BUILD_MQT_CORE_QDMI_DDSIM_DEVICE)
if(BUILD_MQT_CORE_MLIR AND BUILD_MQT_CORE_QDMI_DDSIM_DEVICE)
list(APPEND MQT_CORE_WHEEL_TARGETS mqt-core-qdmi-ddsim-device)
endif()
if(BUILD_MQT_CORE_QDMI_SC_DEVICE)
Expand Down
39 changes: 29 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ forms the backbone of the quantum software tools developed as part of the

## Key Features

- Fully fledged intermediate representation (IR) for quantum computations.
- An MLIR-based compiler collection for quantum programs.
- A state-of-the-art decision diagram (DD) package for quantum computing.
- A QIR runtime based on the decision diagram package.

Expand Down Expand Up @@ -94,17 +94,36 @@ To support this endeavor, please consider:
uv pip install mqt.core
```

The following code gives an example on the usage:
The following example compiles an OpenQASM program to QIR and executes it on the
QDMI DDSIM device:

```python3
from mqt.core.ir import QuantumComputation

qc = QuantumComputation(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure(range(2), range(2))

print(qc)
from mqt.core.mlir import CompilerTarget, OutputFormat, compile_program
from mqt.core.qdmi import ProgramFormat
from mqt.core.qdmi.driver import open_device

source = """OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] result;
h q[0];
cx q[0], q[1];
result = measure q;
"""

device = open_device("mqt.ddsim.default")
program = compile_program(
source,
target=CompilerTarget.from_device(device),
output=OutputFormat.QIR_BASE,
)
job = device.submit_job(
program.to_bitcode(),
ProgramFormat.QIR_BASE_MODULE,
num_shots=1024,
)
job.wait()
print(job.get_counts())
```

**Detailed documentation and examples are available at
Expand Down
122 changes: 48 additions & 74 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@ of changes including minor and patch releases, please refer to the

## [Unreleased]

### Removal of the classic circuit representation

MQT Core 4 removes the complete classic circuit surface. This includes the C++
`qc::QuantumComputation` hierarchy, the `MQT::CoreIR` and `MQT::CoreQASM` CMake
targets, and the installed `ir/` and `qasm3/` headers. Python no longer provides
`mqt.core.ir`, the top-level `mqt.core.load` helper, or the classic
`mqt.core.plugins.qiskit.mqt_to_qiskit` and `qiskit_to_mqt` converters. MQT Core
4 deliberately provides no compatibility alias or adapter for these APIs.

Use the compiler-backed Python interface in new code:

```python
from mqt.core.mlir import OutputFormat, QCProgram, compile_program

Comment thread
burgholzer marked this conversation as resolved.
qc_program = QCProgram.from_qasm_file("circuit.qasm")
qco_program = compile_program(qc_program, output=OutputFormat.QCO_OPTIMIZED)
```

Use `QCProgram.from_qasm_str` for source text, `QCProgram.from_qiskit` for a
Qiskit `QuantumCircuit`, and `QCProgram.to_qiskit` for conversion back to
Qiskit. For decision-diagram simulation, lower to a `QCOProgram` and use its
`sample`, `simulate`, or `build_functionality` methods. The circuit-taking
functions in `mqt.core.dd` and the operation-taking `DDPackage` methods have
been removed; the raw vector and matrix DD constructors remain available.
Comment thread
burgholzer marked this conversation as resolved.

The MQT Core v3 release series continues to provide the classic circuit
interfaces for repositories that have not migrated. Pin `mqt-core>=3,<4` and
stay on that release series. C++ consumers should likewise use a v3 release
branch or a matching v3 version constraint. MQT Core v3 and v4 cannot provide
their Python or CMake packages in the same environment.

### Removal of the `spdlog` dependency

MQT Core no longer discovers, downloads, builds, installs, or exports `spdlog`.
Expand All @@ -20,17 +51,11 @@ dependency instead.

### CircuitOptimizer removal

MQT Core no longer provides `qc::CircuitOptimizer`. Replace the two generic
transformations with `QuantumComputation` member calls:

- Replace `qc::CircuitOptimizer::flattenOperations(qc, customGatesOnly)` with
`qc.flattenOperations(customGatesOnly)`.
- Replace `qc::CircuitOptimizer::removeFinalMeasurements(qc)` with
`qc.removeFinalMeasurements()`.

Include `ir/QuantumComputation.hpp` and link `MQT::CoreIR`. MQT QCEC and MQT
QMAP each own their single-qubit gate-fusion implementation. MQT Core provides
no replacement for `singleQubitGateFusion` outside those packages.
MQT Core no longer provides `qc::CircuitOptimizer`. MQT QCEC and MQT QMAP each
own their single-qubit gate-fusion implementation. MQT Core provides no
replacement for `flattenOperations`, `removeFinalMeasurements`, or
`singleQubitGateFusion` outside packages that still use the classic circuit
representation.

MQT QCEC now owns the equivalence-checking transformations `swapReconstruction`,
`removeDiagonalGatesBeforeMeasure`, `eliminateResets`, `deferMeasurements`,
Expand All @@ -50,8 +75,8 @@ Core replacement. Build the small traversal structure in the package that
consumes it. MQT QMAP and MQT QuSAT demonstrate this migration.

The public `removeIdentities`, `removeOperation`, `collectBlocks`, and
`collectCliffordBlocks` functions have no replacement. Erase operations through
`QuantumComputation` where needed.
`collectCliffordBlocks` functions have no replacement. Keep a package-specific
implementation with a consumer that still needs one.

The `MQT::CoreCircuitOptimizer` CMake target and the
`circuit_optimizer/CircuitOptimizer.hpp` header are removed. The
Expand All @@ -66,13 +91,14 @@ generated decision diagrams with selected shapes for tests and have no direct
replacement.

MQT Core also removed `dd::buildFunctionalityRecursive`. The Python
`mqt.core.dd.build_unitary` and `mqt.core.dd.build_functionality` functions no
longer accept the `recursive` argument and always use sequential construction.
Use MQT DDSIM's unitary simulator when recursive pairwise construction is
required.
`mqt.core.dd.sample`, `simulate_statevector`, `build_unitary`, `simulate`, and
`build_functionality` functions were removed together with the classic circuit
representation. Compile to a `mqt.core.mlir.QCOProgram` and call its `sample`,
`simulate`, or `build_functionality` method instead. Use MQT DDSIM's unitary
simulator when recursive pairwise construction is required.

The zero, basis, GHZ, W, dense-vector, and sequential circuit constructors
remain available.
The zero, basis, GHZ, W, dense-vector, dense-matrix, and raw gate-matrix DD
constructors remain available.

### macOS support

Expand Down Expand Up @@ -193,58 +219,6 @@ The class and function names do not change. For example:
auto device = qdmi::Session::openDevice("mqt.ddsim.default");
```

### CoreIR API cleanup

The CoreIR API cleanup requires the following migrations:

- Replace `getNmeasuredQubits()` and `num_measured_qubits` with
`getNoutputQubits()` and `num_output_qubits`, respectively.
- Replace permutation-aware `Operation::equals()` and `getUsedQubitsPermuted()`
calls by applying the permutation to cloned operations before comparing them.
- Replace `getHighestLogicalQubitIndex()`, `printStatistics()`, and
`printPermutation()` with `initialLayout.maxValue()`, the individual count
accessors, and direct `Permutation` iteration, respectively.
- Construct output-permutation measurements explicitly instead of calling
`appendMeasurementsAccordingToOutputPermutation()`.
- Replace direct `Operation::dumpOpenQASM2()`, `dumpOpenQASM3()`, or
`dumpOpenQASM()` calls with `OpenQASMSerializer`. The register-map aliases
moved from `ir/Register.hpp` to `ir/OpenQASMSerializer.hpp`:

```cpp
#include "ir/OpenQASMSerializer.hpp"

qc::OpenQASMSerializer(stream, qc::Format::OpenQASM2)
.serialize(operation, qubitMap, bitMap);
```

Use `qc::Format::OpenQASM3` for OpenQASM 3 output. The relocated maps own
their register metadata instead of retaining references to the registers used
to construct them. Packages that define custom `Operation` subclasses must own
serialization for their extended syntax; in particular, MQT QMAP owns
neutral-atom OpenQASM serialization.

The register lookup helpers `getQubitRegister()`, `getPhysicalQubitIndex()`, and
`physicalQubitIsAncillary()` are now private implementation details.

`QuantumComputation` no longer stores a random-number generator or seed. Remove
the third `seed` argument from C++ and Python constructor calls. C++ callers
that used `QuantumComputation::getGenerator()` must create and own a
random-number generator instead. Randomized circuit generators continue to
accept a seed and now own a separate generator for each call.

### Removal of the legacy circuit-to-MLIR translator

The compiler no longer accepts `qc::QuantumComputation` or
`mqt.core.ir.QuantumComputation` objects. The
`mlir::QCProgram::fromQuantumComputation` and Python
`QCProgram.from_quantum_computation` functions have been removed. Pass OpenQASM,
a Qiskit circuit, or a typed MLIR program to the compiler instead. Existing
Python code can convert a legacy circuit to OpenQASM 3 before compilation:

```python
program = compile_program(computation.qasm3_str())
```

### Removal of the ZX-calculus library

MQT Core no longer provides the `mqt-core-zx` library, the `MQT::CoreZX` CMake
Expand Down Expand Up @@ -276,9 +250,9 @@ return `QDMI_ERROR_NOTSUPPORTED`.

MQT Core now builds its MLIR-based compiler infrastructure by default. This
configuration requires LLVM 23.1+ with MLIR and includes QIR support in the
DDSIM QDMI device. Set `BUILD_MQT_CORE_MLIR=OFF` to build the core IR, decision
diagram, OpenQASM, and QDMI libraries without LLVM/MLIR or DDSIM QIR support.
The DDSIM device continues to support OpenQASM 2 and OpenQASM 3 programs.
DDSIM QDMI device. Set `BUILD_MQT_CORE_MLIR=OFF` to build the decision-diagram
and QDMI libraries without LLVM/MLIR. The compiler-backed DDSIM device requires
MLIR and is skipped in this configuration.

We offer pre-built distributions for all supported platforms as part of the
`setup-mlir` project at
Expand Down
1 change: 0 additions & 1 deletion bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# Licensed under the MIT License

add_subdirectory(bench)
add_subdirectory(ir)
add_subdirectory(dd)
add_subdirectory(qdmi)
if(BUILD_MQT_CORE_MLIR)
Expand Down
Loading
Loading