From 00ad822d53712971c499ec26b85c79b0724a6b56 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Mon, 4 May 2026 09:13:00 +0200 Subject: [PATCH 01/30] Add SWAPAbsorption Pass --- .../mlir/Dialect/QCO/Transforms/Passes.td | 6 + .../Optimizations/SwapAbsorption.cpp | 124 ++++++++++++++++++ .../Transforms/Optimizations/CMakeLists.txt | 2 +- .../Optimizations/test_swapabsorption.cpp | 84 ++++++++++++ 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp create mode 100644 mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index edca59797e..9109be2f5c 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -101,4 +101,10 @@ def MappingPass : Pass<"place-and-route", "mlir::ModuleOp"> { "The number of inserted SWAPs">]; } +def SwapAbsorptionPass : Pass<"absorb-swaps", "mlir::ModuleOp"> { + let dependentDialects = ["mlir::qco::QCODialect"]; + let summary = ""; + let options = []; +} + #endif // MLIR_DIALECT_QCO_TRANSFORMS_PASSES_TD diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp new file mode 100644 index 0000000000..f89ed1617b --- /dev/null +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -0,0 +1,124 @@ +/* + * 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 + */ + +#include "mlir/Dialect/QCO/IR/QCODialect.h" +#include "mlir/Dialect/QCO/IR/QCOInterfaces.h" +#include "mlir/Dialect/QCO/IR/QCOOps.h" +#include "mlir/Dialect/QCO/Transforms/Passes.h" +#include "mlir/Dialect/QCO/Utils/Drivers.h" +#include "mlir/Dialect/QCO/Utils/WireIterator.h" +#include "mlir/Dialect/QTensor/IR/QTensorOps.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlir::qco { +#define GEN_PASS_DEF_SWAPABSORPTIONPASS +#include "mlir/Dialect/QCO/Transforms/Passes.h.inc" + +namespace { +struct SwapAbsorption : impl::SwapAbsorptionPassBase { +public: + using SwapAbsorptionPassBase::SwapAbsorptionPassBase; + + void runOnOperation() override { + ModuleOp anchor = getOperation(); + IRRewriter rewriter(&getContext()); + insertStatics(anchor, rewriter); + + for (auto func : anchor.getOps()) { + SmallVector wires; + for (auto op : func.getOps()) { + wires.emplace_back(op.getQubit()); + } + + SmallVector readyToAbsorb; + readyToAbsorb.reserve((wires.size() + 1) / 2); + + std::ignore = walkProgramGraph( + wires, [&](const ReadyRange& ready, ReleasedOps& released) { + for (const auto& [op, indices] : ready) { + if (isa(op)) { + readyToAbsorb.emplace_back(op); + } + released.emplace_back(op); + } + return WalkResult::interrupt(); + }); + + for (auto swapOp : readyToAbsorb) { + auto in0 = swapOp.getQubit0In(); + auto in1 = swapOp.getQubit1In(); + + auto out0 = swapOp.getQubit0Out(); + auto out1 = swapOp.getQubit1Out(); + + // TODO: What if single qubit gates are in front of the SWAP input? + // Tipp: Use the WireIterator. + StaticOp op0 = cast(in0.getDefiningOp()); + StaticOp op1 = cast(in1.getDefiningOp()); + + rewriter.replaceAllUsesWith(out0, op1.getQubit()); + rewriter.replaceAllUsesWith(out1, op0.getQubit()); + rewriter.eraseOp(swapOp); + } + } + } + +private: + static void insertStatics(ModuleOp anchor, IRRewriter& rewriter) { + for (auto func : anchor.getOps()) { + SmallVector worklist; + for (Operation& op : func.getOps()) { + worklist.emplace_back(&op); + } + + std::size_t n = llvm::range_size(func.getOps()) - 1; + for (Operation* op : llvm::reverse(worklist)) { + rewriter.setInsertionPoint(op); + + if (auto tensorDealloc = dyn_cast(op)) { + rewriter.eraseOp(tensorDealloc); + continue; + } + + if (auto tensorInsert = dyn_cast(op)) { + auto q = tensorInsert.getScalar(); + rewriter.create(rewriter.getUnknownLoc(), q); + rewriter.eraseOp(tensorInsert); + continue; + } + + if (auto tensorExtract = dyn_cast(op)) { + auto q = tensorExtract.getResult(); + auto staticOp = + rewriter.create(rewriter.getUnknownLoc(), n); + rewriter.replaceAllUsesWith(q, staticOp.getQubit()); + rewriter.eraseOp(tensorExtract); + n--; + continue; + } + + if (auto tensorAlloc = dyn_cast(op)) { + rewriter.eraseOp(tensorAlloc); + continue; + } + } + } + } +}; +} // namespace +} // namespace mlir::qco \ No newline at end of file diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt index 73606c2efb..7a19471e2d 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt @@ -7,7 +7,7 @@ # Licensed under the MIT License set(target_name mqt-core-mlir-unittest-optimizations) -add_executable(${target_name} test_qco_merge_single_qubit_rotation.cpp) +add_executable(${target_name} test_swapabsorption.cpp test_qco_merge_single_qubit_rotation.cpp) target_link_libraries( ${target_name} diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp new file mode 100644 index 0000000000..331363f756 --- /dev/null +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -0,0 +1,84 @@ +/* + * 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 + */ + +#include "mlir/Dialect/QC/IR/QCDialect.h" +#include "mlir/Dialect/QCO/Builder/QCOProgramBuilder.h" +#include "mlir/Dialect/QCO/IR/QCODialect.h" +#include "mlir/Dialect/QCO/Transforms/Passes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace mlir; +using namespace mlir::qco; + +namespace { + +class SwapAbsorbPassTest : public testing::Test { + +protected: + void SetUp() override { + // Register all necessary dialects + DialectRegistry registry; + registry.insert(); + context = std::make_unique(); + context->appendDialectRegistry(registry); + context->loadAllAvailableDialects(); + } + + static void applySwapAbsorb(OwningOpRef& moduleOp) { + PassManager pm(moduleOp->getContext()); + pm.addPass(qco::createSwapAbsorptionPass()); + auto res = pm.run(*moduleOp); + + ASSERT_TRUE(succeeded(res)); + } + + std::unique_ptr context; +}; +}; // namespace + +TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { + + qco::QCOProgramBuilder builder(context.get()); + builder.initialize(); + + const auto q00 = builder.allocQubit(); + const auto q10 = builder.allocQubit(); + const auto q20 = builder.allocQubit(); + + const auto q01 = builder.h(q00); + const auto [q02, q11] = builder.cx(q01, q10); + + builder.sink(q02); + builder.sink(q11); + + auto moduleThroughPass = builder.finalize(); + auto originalModule = moduleThroughPass->clone(); + + applySwapAbsorb(moduleThroughPass); + ASSERT_TRUE(mlir::OperationEquivalence::isEquivalentTo( + moduleThroughPass.get(), originalModule, + mlir::OperationEquivalence::Flags::IgnoreLocations)); +} \ No newline at end of file From 77250d1445847f25423390fa60a3f08bdc91ffe1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 07:15:07 +0000 Subject: [PATCH 02/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp | 2 +- .../Dialect/QCO/Transforms/Optimizations/CMakeLists.txt | 2 +- .../QCO/Transforms/Optimizations/test_swapabsorption.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index f89ed1617b..a7864ed7ca 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -121,4 +121,4 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { } }; } // namespace -} // namespace mlir::qco \ No newline at end of file +} // namespace mlir::qco diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt index 7a19471e2d..efdc904899 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt @@ -7,7 +7,7 @@ # Licensed under the MIT License set(target_name mqt-core-mlir-unittest-optimizations) -add_executable(${target_name} test_swapabsorption.cpp test_qco_merge_single_qubit_rotation.cpp) +add_executable(${target_name} test_qco_merge_single_qubit_rotation.cpp test_swapabsorption.cpp) target_link_libraries( ${target_name} diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 331363f756..d52c2cc17f 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -81,4 +81,4 @@ TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { ASSERT_TRUE(mlir::OperationEquivalence::isEquivalentTo( moduleThroughPass.get(), originalModule, mlir::OperationEquivalence::Flags::IgnoreLocations)); -} \ No newline at end of file +} From 515e6bfa2d6163ebf4d18798a5f10d604ab939d2 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Mon, 4 May 2026 09:32:30 +0200 Subject: [PATCH 03/30] Fix linting --- .../QCO/Transforms/Optimizations/SwapAbsorption.cpp | 8 ++++---- .../QCO/Transforms/Optimizations/test_swapabsorption.cpp | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index f89ed1617b..4cfd052d9c 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -8,8 +8,6 @@ * Licensed under the MIT License */ -#include "mlir/Dialect/QCO/IR/QCODialect.h" -#include "mlir/Dialect/QCO/IR/QCOInterfaces.h" #include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/Transforms/Passes.h" #include "mlir/Dialect/QCO/Utils/Drivers.h" @@ -17,7 +15,6 @@ #include "mlir/Dialect/QTensor/IR/QTensorOps.h" #include -#include #include #include #include @@ -25,6 +22,9 @@ #include #include +#include +#include + namespace mlir::qco { #define GEN_PASS_DEF_SWAPABSORPTIONPASS #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" @@ -33,7 +33,7 @@ namespace { struct SwapAbsorption : impl::SwapAbsorptionPassBase { public: using SwapAbsorptionPassBase::SwapAbsorptionPassBase; - +protected: void runOnOperation() override { ModuleOp anchor = getOperation(); IRRewriter rewriter(&getContext()); diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 331363f756..0fdc921b58 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -8,24 +8,21 @@ * Licensed under the MIT License */ -#include "mlir/Dialect/QC/IR/QCDialect.h" #include "mlir/Dialect/QCO/Builder/QCOProgramBuilder.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" #include "mlir/Dialect/QCO/Transforms/Passes.h" #include -#include -#include #include #include #include #include #include +#include #include #include #include #include -#include #include #include @@ -66,7 +63,6 @@ TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { const auto q00 = builder.allocQubit(); const auto q10 = builder.allocQubit(); - const auto q20 = builder.allocQubit(); const auto q01 = builder.h(q00); const auto [q02, q11] = builder.cx(q01, q10); From b0474ff3e284575959d3fdcd31c1d130976498c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 07:33:05 +0000 Subject: [PATCH 04/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 394d8328b3..ce02a636ab 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -22,8 +22,8 @@ #include #include -#include #include +#include namespace mlir::qco { #define GEN_PASS_DEF_SWAPABSORPTIONPASS @@ -33,6 +33,7 @@ namespace { struct SwapAbsorption : impl::SwapAbsorptionPassBase { public: using SwapAbsorptionPassBase::SwapAbsorptionPassBase; + protected: void runOnOperation() override { ModuleOp anchor = getOperation(); From 10302c52bd6b0d66c8b3e533e5e4aacb3c369736 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Mon, 4 May 2026 21:55:14 +0200 Subject: [PATCH 05/30] remove SwapAbsorbtion::insertStatics() --- .../Optimizations/SwapAbsorption.cpp | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index ce02a636ab..c98b7428df 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -38,7 +38,6 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { void runOnOperation() override { ModuleOp anchor = getOperation(); IRRewriter rewriter(&getContext()); - insertStatics(anchor, rewriter); for (auto func : anchor.getOps()) { SmallVector wires; @@ -78,48 +77,6 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { } } } - -private: - static void insertStatics(ModuleOp anchor, IRRewriter& rewriter) { - for (auto func : anchor.getOps()) { - SmallVector worklist; - for (Operation& op : func.getOps()) { - worklist.emplace_back(&op); - } - - std::size_t n = llvm::range_size(func.getOps()) - 1; - for (Operation* op : llvm::reverse(worklist)) { - rewriter.setInsertionPoint(op); - - if (auto tensorDealloc = dyn_cast(op)) { - rewriter.eraseOp(tensorDealloc); - continue; - } - - if (auto tensorInsert = dyn_cast(op)) { - auto q = tensorInsert.getScalar(); - rewriter.create(rewriter.getUnknownLoc(), q); - rewriter.eraseOp(tensorInsert); - continue; - } - - if (auto tensorExtract = dyn_cast(op)) { - auto q = tensorExtract.getResult(); - auto staticOp = - rewriter.create(rewriter.getUnknownLoc(), n); - rewriter.replaceAllUsesWith(q, staticOp.getQubit()); - rewriter.eraseOp(tensorExtract); - n--; - continue; - } - - if (auto tensorAlloc = dyn_cast(op)) { - rewriter.eraseOp(tensorAlloc); - continue; - } - } - } - } }; } // namespace } // namespace mlir::qco From da710c700d9e6f90f8b667c116dbc15dd48c9b70 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Mon, 4 May 2026 21:57:00 +0200 Subject: [PATCH 06/30] change unittests to use static qubits --- .../QCO/Transforms/Optimizations/test_swapabsorption.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index b2f529a1a8..880810439a 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -61,9 +61,9 @@ TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { qco::QCOProgramBuilder builder(context.get()); builder.initialize(); - const auto q00 = builder.allocQubit(); - const auto q10 = builder.allocQubit(); - + const auto q00 = builder.staticQubit(0); + const auto q10 = builder.staticQubit(1); + const auto q01 = builder.h(q00); const auto [q02, q11] = builder.cx(q01, q10); From d793c7392105c6132a0677e034749ff2f87d0b29 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Tue, 5 May 2026 21:59:46 +0200 Subject: [PATCH 07/30] SwapAbsorbtion: PassReordersTwoQubitCircuitWithLeadingSwap --- .../Optimizations/test_swapabsorption.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 880810439a..70dee8cafb 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -10,6 +10,7 @@ #include "mlir/Dialect/QCO/Builder/QCOProgramBuilder.h" #include "mlir/Dialect/QCO/IR/QCODialect.h" +#include "mlir/Dialect/QCO/IR/QCOOps.h" #include "mlir/Dialect/QCO/Transforms/Passes.h" #include @@ -78,3 +79,26 @@ TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { moduleThroughPass.get(), originalModule, mlir::OperationEquivalence::Flags::IgnoreLocations)); } + +TEST_F(SwapAbsorbPassTest, PassReordersTwoQubitCircuitWithLeadingSwap) { + + qco::QCOProgramBuilder builder(context.get()); + builder.initialize(); + + const auto q00 = builder.staticQubit(0); + const auto q10 = builder.staticQubit(1); + + const auto [q01, q11] = builder.swap(q00, q10); + + const auto q02 = builder.id(q01); + const auto q12 = builder.id(q11); + + builder.sink(q02); + builder.sink(q12); + + auto moduleThroughPass = builder.finalize(); + applySwapAbsorb(moduleThroughPass); + + ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); +} From de8941126256305aa3cfa02f84eb572f6606d797 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:40:14 +0000 Subject: [PATCH 08/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QCO/Transforms/Optimizations/test_swapabsorption.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 70dee8cafb..5b0554846d 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -64,7 +64,7 @@ TEST_F(SwapAbsorbPassTest, PassDoesNotChangeSwaplessProgram) { const auto q00 = builder.staticQubit(0); const auto q10 = builder.staticQubit(1); - + const auto q01 = builder.h(q00); const auto [q02, q11] = builder.cx(q01, q10); @@ -87,7 +87,7 @@ TEST_F(SwapAbsorbPassTest, PassReordersTwoQubitCircuitWithLeadingSwap) { const auto q00 = builder.staticQubit(0); const auto q10 = builder.staticQubit(1); - + const auto [q01, q11] = builder.swap(q00, q10); const auto q02 = builder.id(q01); From 3dbe1a321ef82a51af492a986b174eadc08396ee Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Wed, 6 May 2026 22:21:10 +0200 Subject: [PATCH 09/30] swap-absorb: PassAbsorbsTwoIndependentSwaps --- .../Optimizations/test_swapabsorption.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 5b0554846d..64ebace4e3 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -102,3 +102,35 @@ TEST_F(SwapAbsorbPassTest, PassReordersTwoQubitCircuitWithLeadingSwap) { ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); } + +TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoIndependentSwaps) { + + qco::QCOProgramBuilder builder(context.get()); + builder.initialize(); + + const auto q00 = builder.staticQubit(0); + const auto q10 = builder.staticQubit(1); + const auto q20 = builder.staticQubit(2); + const auto q30 = builder.staticQubit(3); + + const auto [q01, q11] = builder.swap(q00, q10); + const auto [q21, q31] = builder.swap(q20, q30); + + const auto q02 = builder.id(q01); + const auto q12 = builder.id(q11); + const auto q22 = builder.id(q21); + const auto q32 = builder.id(q31); + + builder.sink(q02); + builder.sink(q12); + builder.sink(q22); + builder.sink(q32); + + auto moduleThroughPass = builder.finalize(); + applySwapAbsorb(moduleThroughPass); + + ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q30, ((IdOp)q22.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q20, ((IdOp)q32.getDefiningOp()).getInputQubit(0)); +} \ No newline at end of file From 3b2af5de4f89eeb7245d6b03004a9b2b95703138 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Wed, 27 May 2026 17:45:53 +0200 Subject: [PATCH 10/30] remove unused includes --- .../Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index c98b7428df..4a0ac4f57d 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -12,7 +12,6 @@ #include "mlir/Dialect/QCO/Transforms/Passes.h" #include "mlir/Dialect/QCO/Utils/Drivers.h" #include "mlir/Dialect/QCO/Utils/WireIterator.h" -#include "mlir/Dialect/QTensor/IR/QTensorOps.h" #include #include @@ -22,9 +21,6 @@ #include #include -#include -#include - namespace mlir::qco { #define GEN_PASS_DEF_SWAPABSORPTIONPASS #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" From 6312c37d1f0417d1d8a27b6823a1eba032366b93 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Wed, 27 May 2026 17:48:50 +0200 Subject: [PATCH 11/30] PassAbsorbsSwapWithLeadingSingleQubitGates --- .../Optimizations/SwapAbsorption.cpp | 9 ++----- .../Optimizations/test_swapabsorption.cpp | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 4a0ac4f57d..4551662636 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -62,13 +62,8 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { auto out0 = swapOp.getQubit0Out(); auto out1 = swapOp.getQubit1Out(); - // TODO: What if single qubit gates are in front of the SWAP input? - // Tipp: Use the WireIterator. - StaticOp op0 = cast(in0.getDefiningOp()); - StaticOp op1 = cast(in1.getDefiningOp()); - - rewriter.replaceAllUsesWith(out0, op1.getQubit()); - rewriter.replaceAllUsesWith(out1, op0.getQubit()); + rewriter.replaceAllUsesWith(out0, in1); + rewriter.replaceAllUsesWith(out1, in0); rewriter.eraseOp(swapOp); } } diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 64ebace4e3..557f640a1e 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -133,4 +133,30 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoIndependentSwaps) { ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); ASSERT_EQ(q30, ((IdOp)q22.getDefiningOp()).getInputQubit(0)); ASSERT_EQ(q20, ((IdOp)q32.getDefiningOp()).getInputQubit(0)); +} + +TEST_F(SwapAbsorbPassTest, PassAbsorbsSwapWithLeadingSingleQubitGates) { + + qco::QCOProgramBuilder builder(context.get()); + builder.initialize(); + + const auto q00 = builder.staticQubit(0); + const auto q10 = builder.staticQubit(1); + + const auto q01 = builder.id(q00); + const auto q11 = builder.id(q10); + + const auto [q02, q12] = builder.swap(q01, q11); + + const auto q03 = builder.id(q02); + const auto q13 = builder.id(q12); + + builder.sink(q03); + builder.sink(q13); + + auto moduleThroughPass = builder.finalize(); + applySwapAbsorb(moduleThroughPass); + + ASSERT_EQ(q11, ((IdOp)q03.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q01, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); } \ No newline at end of file From 1a884d8485e0ab0d370105f25f39835ab0cef5ea Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 05:58:14 +0000 Subject: [PATCH 12/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialect/QCO/Transforms/Optimizations/CMakeLists.txt | 7 +++---- .../QCO/Transforms/Optimizations/test_swapabsorption.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt index 229d57495c..47a33d0b01 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/CMakeLists.txt @@ -7,10 +7,9 @@ # Licensed under the MIT License set(target_name mqt-core-mlir-unittest-optimizations) -add_executable(${target_name} test_qco_hadamard_lifting.cpp - test_qco_merge_single_qubit_rotation.cpp - test_quantum_loop_unroll.cpp - test_swapabsorption.cpp) +add_executable( + ${target_name} test_qco_hadamard_lifting.cpp test_qco_merge_single_qubit_rotation.cpp + test_quantum_loop_unroll.cpp test_swapabsorption.cpp) target_link_libraries( ${target_name} diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 557f640a1e..bfe4c1f5ec 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -159,4 +159,4 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsSwapWithLeadingSingleQubitGates) { ASSERT_EQ(q11, ((IdOp)q03.getDefiningOp()).getInputQubit(0)); ASSERT_EQ(q01, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); -} \ No newline at end of file +} From c4bb64fb8e72cb9d86cdc0c8ea3e7b9b4863d30a Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Thu, 28 May 2026 21:41:07 +0200 Subject: [PATCH 13/30] PassAbsorbsTwoDependentSwaps --- .../Optimizations/SwapAbsorption.cpp | 54 +++++++++++-------- .../Optimizations/test_swapabsorption.cpp | 28 ++++++++++ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 4551662636..29a7c37646 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -13,11 +13,9 @@ #include "mlir/Dialect/QCO/Utils/Drivers.h" #include "mlir/Dialect/QCO/Utils/WireIterator.h" -#include #include #include #include -#include #include #include @@ -43,30 +41,44 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { SmallVector readyToAbsorb; readyToAbsorb.reserve((wires.size() + 1) / 2); + findSwapsReadyForAbsorption(wires, readyToAbsorb); - std::ignore = walkProgramGraph( - wires, [&](const ReadyRange& ready, ReleasedOps& released) { - for (const auto& [op, indices] : ready) { - if (isa(op)) { - readyToAbsorb.emplace_back(op); - } - released.emplace_back(op); + do { + for (auto swapOp : readyToAbsorb) { + absorbSingleSwap(swapOp, rewriter); + } + readyToAbsorb.clear(); + findSwapsReadyForAbsorption(wires, readyToAbsorb); + } + while(!readyToAbsorb.empty()); + } + } + +private: + void findSwapsReadyForAbsorption(SmallVector wires, SmallVector &readyToAbsorb) + { + std::ignore = walkProgramGraph( + wires, [&](const ReadyRange& ready, ReleasedOps& released) { + for (const auto& [op, indices] : ready) { + if (isa(op)) { + readyToAbsorb.emplace_back(op); } - return WalkResult::interrupt(); - }); + released.emplace_back(op); + } + return WalkResult::interrupt(); + }); + } - for (auto swapOp : readyToAbsorb) { - auto in0 = swapOp.getQubit0In(); - auto in1 = swapOp.getQubit1In(); + void absorbSingleSwap(SWAPOp swapOp, IRRewriter &rewriter) { + auto in0 = swapOp.getQubit0In(); + auto in1 = swapOp.getQubit1In(); - auto out0 = swapOp.getQubit0Out(); - auto out1 = swapOp.getQubit1Out(); + auto out0 = swapOp.getQubit0Out(); + auto out1 = swapOp.getQubit1Out(); - rewriter.replaceAllUsesWith(out0, in1); - rewriter.replaceAllUsesWith(out1, in0); - rewriter.eraseOp(swapOp); - } - } + rewriter.replaceAllUsesWith(out0, in1); + rewriter.replaceAllUsesWith(out1, in0); + rewriter.eraseOp(swapOp); } }; } // namespace diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index bfe4c1f5ec..fc81ffe748 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -160,3 +160,31 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsSwapWithLeadingSingleQubitGates) { ASSERT_EQ(q11, ((IdOp)q03.getDefiningOp()).getInputQubit(0)); ASSERT_EQ(q01, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); } + +TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoDependentSwaps) { + + qco::QCOProgramBuilder builder(context.get()); + builder.initialize(); + + const auto q00 = builder.staticQubit(0); + const auto q10 = builder.staticQubit(1); + const auto q20 = builder.staticQubit(2); + + const auto [q01, q11] = builder.swap(q00, q10); + const auto [q12, q21] = builder.swap(q11, q20); + + const auto q02 = builder.id(q01); + const auto q13 = builder.id(q12); + const auto q22 = builder.id(q21); + + builder.sink(q02); + builder.sink(q13); + builder.sink(q22); + + auto moduleThroughPass = builder.finalize(); + applySwapAbsorb(moduleThroughPass); + + ASSERT_EQ(q20, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, ((IdOp)q22.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); +} From a7793613287bda29d1842325d8cf9556f5e91353 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 19:41:42 +0000 Subject: [PATCH 14/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QCO/Transforms/Optimizations/SwapAbsorption.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 29a7c37646..f9bb8d583d 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -49,14 +49,13 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { } readyToAbsorb.clear(); findSwapsReadyForAbsorption(wires, readyToAbsorb); - } - while(!readyToAbsorb.empty()); + } while (!readyToAbsorb.empty()); } } private: - void findSwapsReadyForAbsorption(SmallVector wires, SmallVector &readyToAbsorb) - { + void findSwapsReadyForAbsorption(SmallVector wires, + SmallVector& readyToAbsorb) { std::ignore = walkProgramGraph( wires, [&](const ReadyRange& ready, ReleasedOps& released) { for (const auto& [op, indices] : ready) { @@ -69,7 +68,7 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { }); } - void absorbSingleSwap(SWAPOp swapOp, IRRewriter &rewriter) { + void absorbSingleSwap(SWAPOp swapOp, IRRewriter& rewriter) { auto in0 = swapOp.getQubit0In(); auto in1 = swapOp.getQubit1In(); From 3bf15be56daa3d4f91eaddce969f619aa84a88b1 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Fri, 29 May 2026 14:39:40 +0200 Subject: [PATCH 15/30] fix some lint warnings --- .../Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 29a7c37646..07a31bc1d4 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -19,6 +19,8 @@ #include #include +#include + namespace mlir::qco { #define GEN_PASS_DEF_SWAPABSORPTIONPASS #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" @@ -55,7 +57,7 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { } private: - void findSwapsReadyForAbsorption(SmallVector wires, SmallVector &readyToAbsorb) + static void findSwapsReadyForAbsorption(SmallVector wires, SmallVector &readyToAbsorb) { std::ignore = walkProgramGraph( wires, [&](const ReadyRange& ready, ReleasedOps& released) { @@ -69,7 +71,7 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { }); } - void absorbSingleSwap(SWAPOp swapOp, IRRewriter &rewriter) { + static void absorbSingleSwap(SWAPOp swapOp, IRRewriter &rewriter) { auto in0 = swapOp.getQubit0In(); auto in1 = swapOp.getQubit1In(); From 03917b6f0ffdd578bd1275fbc6048903ed4e83a2 Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 29 May 2026 15:23:37 +0200 Subject: [PATCH 16/30] Fix linter error --- .../Optimizations/SwapAbsorption.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 83ea451460..5bc2155727 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -36,27 +36,25 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { IRRewriter rewriter(&getContext()); for (auto func : anchor.getOps()) { - SmallVector wires; - for (auto op : func.getOps()) { - wires.emplace_back(op.getQubit()); - } - SmallVector readyToAbsorb; - readyToAbsorb.reserve((wires.size() + 1) / 2); - findSwapsReadyForAbsorption(wires, readyToAbsorb); - do { - for (auto swapOp : readyToAbsorb) { - absorbSingleSwap(swapOp, rewriter); + SmallVector wires; + for (auto op : func.getOps()) { + wires.emplace_back(op.getQubit()); } + readyToAbsorb.clear(); findSwapsReadyForAbsorption(wires, readyToAbsorb); + + for (auto swapOp : readyToAbsorb) { + absorbSingleSwap(swapOp, rewriter); + } } while (!readyToAbsorb.empty()); } } private: - static void findSwapsReadyForAbsorption(SmallVector wires, + static void findSwapsReadyForAbsorption(MutableArrayRef wires, SmallVector& readyToAbsorb) { std::ignore = walkProgramGraph( wires, [&](const ReadyRange& ready, ReleasedOps& released) { From 8948b78a08dcd255cfdda82362a4acbfc89a51ce Mon Sep 17 00:00:00 2001 From: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:55:40 +0200 Subject: [PATCH 17/30] add pass summary and description Signed-off-by: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> --- mlir/include/mlir/Dialect/QCO/Transforms/Passes.td | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index 335e22ecfb..52ab24ac92 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -176,8 +176,19 @@ def HadamardLifting : Pass<"hadamard-lifting", "mlir::ModuleOp"> { def SwapAbsorptionPass : Pass<"absorb-swaps", "mlir::ModuleOp"> { let dependentDialects = ["mlir::qco::QCODialect"]; - let summary = ""; + let summary = "Eliminate SWAP operations by rewiring circuit"; let options = []; + let description = [{ + This pass removes SWAP operations by absorbing their effect into the surrounding circuit. + + For a SWAP operation exchanging qubits q0 and q1, the pass replaces all uses of the first output wire + with the second input wire and vice versa. As a result, the logical permutation introduced by the SWAP is + propagated through the IR and the SWAP operation itself can be removed. + + The pass repeatedly identifies SWAP operations that are ready to be processed and absorbs them one by one. + Each absorption may expose additional SWAP operations that can subsequently be eliminated. + This process continues until no further SWAP operations can be absorbed. + }]; } #endif // MLIR_DIALECT_QCO_TRANSFORMS_PASSES_TD From 982efb7e95f8975d78bde07af06b552bfc442510 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:57:25 +0000 Subject: [PATCH 18/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mlir/include/mlir/Dialect/QCO/Transforms/Passes.td | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index 52ab24ac92..689e36af1f 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -181,12 +181,12 @@ def SwapAbsorptionPass : Pass<"absorb-swaps", "mlir::ModuleOp"> { let description = [{ This pass removes SWAP operations by absorbing their effect into the surrounding circuit. - For a SWAP operation exchanging qubits q0 and q1, the pass replaces all uses of the first output wire - with the second input wire and vice versa. As a result, the logical permutation introduced by the SWAP is + For a SWAP operation exchanging qubits q0 and q1, the pass replaces all uses of the first output wire + with the second input wire and vice versa. As a result, the logical permutation introduced by the SWAP is propagated through the IR and the SWAP operation itself can be removed. The pass repeatedly identifies SWAP operations that are ready to be processed and absorbs them one by one. - Each absorption may expose additional SWAP operations that can subsequently be eliminated. + Each absorption may expose additional SWAP operations that can subsequently be eliminated. This process continues until no further SWAP operations can be absorbed. }]; } From 343387dd46a543a9bc93d14534d2dc6156da3844 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:13:38 +0200 Subject: [PATCH 19/30] remove empty pass options Co-authored-by: matthias Signed-off-by: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> --- mlir/include/mlir/Dialect/QCO/Transforms/Passes.td | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index 689e36af1f..6ffb4707e6 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -177,7 +177,6 @@ def HadamardLifting : Pass<"hadamard-lifting", "mlir::ModuleOp"> { def SwapAbsorptionPass : Pass<"absorb-swaps", "mlir::ModuleOp"> { let dependentDialects = ["mlir::qco::QCODialect"]; let summary = "Eliminate SWAP operations by rewiring circuit"; - let options = []; let description = [{ This pass removes SWAP operations by absorbing their effect into the surrounding circuit. From a108a9b7c87ec5a38cce575ef6051caad39ad2eb Mon Sep 17 00:00:00 2001 From: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:15:20 +0200 Subject: [PATCH 20/30] remove unnecessary comment Co-authored-by: matthias Signed-off-by: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> --- .../Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index fc81ffe748..60c317bb72 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -37,7 +37,6 @@ class SwapAbsorbPassTest : public testing::Test { protected: void SetUp() override { - // Register all necessary dialects DialectRegistry registry; registry.insert(); context = std::make_unique(); From 5b9c7f75d2a2d190cc251d41470e4ac59c096be7 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:20:32 +0200 Subject: [PATCH 21/30] enhance swap absobrtion according review Signed-off-by: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> --- .../Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 5bc2155727..4d6376b25d 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -37,11 +37,15 @@ struct SwapAbsorption : impl::SwapAbsorptionPassBase { for (auto func : anchor.getOps()) { SmallVector readyToAbsorb; + SmallVector wires; do { - SmallVector wires; + wires.clear(); for (auto op : func.getOps()) { wires.emplace_back(op.getQubit()); } + if (wires.empty()) { + return; + } readyToAbsorb.clear(); findSwapsReadyForAbsorption(wires, readyToAbsorb); From 4d762f536720384f6026757e73db4dfddd4e35e4 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 3 Jun 2026 08:42:11 +0200 Subject: [PATCH 22/30] Update CHANGELOG.md [skip ci] --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dad0d3abf3..2b55203b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Added +- ✨ Add a `absorb-swaps` pass for absorbing initial SWAPs ([#1750]) ([**@jmoosburger**], [**@MatthiasReumann**]) - 🚸 Add [CMake presets] to provide a standardized and reproducible way to configure builds ([#1660]) ([**@denialhaag**]) - ✨ Add a `quantum-loop-unroll` pass for unrolling for-loop operations containing quantum operations ([#1718]) ([**@MatthiasReumann**]) - ✨ Add a `hadamard-lifting` pass for lifting Hadamard gates above Pauli gates ([#1605]) ([**@lirem101**], [**@burgholzer**]) @@ -402,6 +403,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#1750]: https://github.com/munich-quantum-toolkit/core/pull/1750 [#1749]: https://github.com/munich-quantum-toolkit/core/pull/1749 [#1748]: https://github.com/munich-quantum-toolkit/core/pull/1748 [#1737]: https://github.com/munich-quantum-toolkit/core/pull/1737 @@ -649,6 +651,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool [**@simon1hofmann**]: https://github.com/simon1hofmann [**@keefehuang**]: https://github.com/keefehuang [**@J4MMlE**]: https://github.com/J4MMlE +[**@jmoosburger**]: https://github.com/jmoosburger From 806a4a9b5e4ef353bf5ce9061e3641d3c578f6f4 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 3 Jun 2026 08:56:36 +0200 Subject: [PATCH 23/30] Update pass tablegen --- .../mlir/Dialect/QCO/Transforms/Passes.td | 19 ++++++++----------- .../Optimizations/SwapAbsorption.cpp | 6 +++--- .../Optimizations/test_swapabsorption.cpp | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index 6ffb4707e6..c81909e4be 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -174,19 +174,16 @@ def HadamardLifting : Pass<"hadamard-lifting", "mlir::ModuleOp"> { }]; } -def SwapAbsorptionPass : Pass<"absorb-swaps", "mlir::ModuleOp"> { +def SwapAbsorption : Pass<"absorb-swaps", "mlir::ModuleOp"> { let dependentDialects = ["mlir::qco::QCODialect"]; - let summary = "Eliminate SWAP operations by rewiring circuit"; + let summary = "This pass absorbs SWAP operations into the initial program-to-hardware mapping."; let description = [{ - This pass removes SWAP operations by absorbing their effect into the surrounding circuit. - - For a SWAP operation exchanging qubits q0 and q1, the pass replaces all uses of the first output wire - with the second input wire and vice versa. As a result, the logical permutation introduced by the SWAP is - propagated through the IR and the SWAP operation itself can be removed. - - The pass repeatedly identifies SWAP operations that are ready to be processed and absorbs them one by one. - Each absorption may expose additional SWAP operations that can subsequently be eliminated. - This process continues until no further SWAP operations can be absorbed. + For a SWAP operation exchanging static qubits q0 and q1, the pass replaces the use of the + first (second) input qubit with the second (first) output qubit of the SWAP and subsequently + removes the operation. As a result, the initial program-to-hardware mapping is changed. + This process is repeated until no more SWAP operations can be absorbed. + + The pass assumes that the quantum program is already mapped to static qubits. }]; } diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index 4d6376b25d..ccce35a807 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -22,13 +22,13 @@ #include namespace mlir::qco { -#define GEN_PASS_DEF_SWAPABSORPTIONPASS +#define GEN_PASS_DEF_SWAPABSORPTION #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" namespace { -struct SwapAbsorption : impl::SwapAbsorptionPassBase { +struct SwapAbsorption : impl::SwapAbsorptionBase { public: - using SwapAbsorptionPassBase::SwapAbsorptionPassBase; + using SwapAbsorptionBase::SwapAbsorptionBase; protected: void runOnOperation() override { diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index 60c317bb72..eba0ec646d 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -46,7 +46,7 @@ class SwapAbsorbPassTest : public testing::Test { static void applySwapAbsorb(OwningOpRef& moduleOp) { PassManager pm(moduleOp->getContext()); - pm.addPass(qco::createSwapAbsorptionPass()); + pm.addPass(qco::createSwapAbsorption()); auto res = pm.run(*moduleOp); ASSERT_TRUE(succeeded(res)); From 4ef76205a534197930a10b1094aa693dcb7db6ae Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 06:57:29 +0000 Subject: [PATCH 24/30] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mlir/include/mlir/Dialect/QCO/Transforms/Passes.td | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td index c81909e4be..1799b5aa18 100644 --- a/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/QCO/Transforms/Passes.td @@ -176,14 +176,15 @@ def HadamardLifting : Pass<"hadamard-lifting", "mlir::ModuleOp"> { def SwapAbsorption : Pass<"absorb-swaps", "mlir::ModuleOp"> { let dependentDialects = ["mlir::qco::QCODialect"]; - let summary = "This pass absorbs SWAP operations into the initial program-to-hardware mapping."; + let summary = "This pass absorbs SWAP operations into the initial " + "program-to-hardware mapping."; let description = [{ - For a SWAP operation exchanging static qubits q0 and q1, the pass replaces the use of the - first (second) input qubit with the second (first) output qubit of the SWAP and subsequently - removes the operation. As a result, the initial program-to-hardware mapping is changed. + For a SWAP operation exchanging static qubits q0 and q1, the pass replaces the use of the + first (second) input qubit with the second (first) output qubit of the SWAP and subsequently + removes the operation. As a result, the initial program-to-hardware mapping is changed. This process is repeated until no more SWAP operations can be absorbed. - - The pass assumes that the quantum program is already mapped to static qubits. + + The pass assumes that the quantum program is already mapped to static qubits. }]; } From bee32c946af96bdb53032c7e8a83b47ae2b63d20 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 18 Jun 2026 17:19:47 +0200 Subject: [PATCH 25/30] :zap: Streamline pass implementation Signed-off-by: burgholzer --- .../Optimizations/SwapAbsorption.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp index ccce35a807..c6c7e78c00 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Optimizations/SwapAbsorption.cpp @@ -19,15 +19,12 @@ #include #include -#include - namespace mlir::qco { #define GEN_PASS_DEF_SWAPABSORPTION #include "mlir/Dialect/QCO/Transforms/Passes.h.inc" namespace { struct SwapAbsorption : impl::SwapAbsorptionBase { -public: using SwapAbsorptionBase::SwapAbsorptionBase; protected: @@ -51,7 +48,8 @@ struct SwapAbsorption : impl::SwapAbsorptionBase { findSwapsReadyForAbsorption(wires, readyToAbsorb); for (auto swapOp : readyToAbsorb) { - absorbSingleSwap(swapOp, rewriter); + rewriter.replaceOp(swapOp, + {swapOp.getQubit1In(), swapOp.getQubit0In()}); } } while (!readyToAbsorb.empty()); } @@ -71,18 +69,6 @@ struct SwapAbsorption : impl::SwapAbsorptionBase { return WalkResult::interrupt(); }); } - - static void absorbSingleSwap(SWAPOp swapOp, IRRewriter& rewriter) { - auto in0 = swapOp.getQubit0In(); - auto in1 = swapOp.getQubit1In(); - - auto out0 = swapOp.getQubit0Out(); - auto out1 = swapOp.getQubit1Out(); - - rewriter.replaceAllUsesWith(out0, in1); - rewriter.replaceAllUsesWith(out1, in0); - rewriter.eraseOp(swapOp); - } }; } // namespace } // namespace mlir::qco From 4dac9d25f9c19fe767044d0c4f4f95409f5b0d51 Mon Sep 17 00:00:00 2001 From: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> Date: Sat, 20 Jun 2026 15:42:57 +0200 Subject: [PATCH 26/30] typo in changelog Co-authored-by: Lukas Burgholzer Signed-off-by: Johannes Moosburger <96540096+jmoosburger@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86c4d97e89..ef9c0a36f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ with the exception that minor releases may include breaking changes. ### Added -- ✨ Add a `absorb-swaps` pass for absorbing initial SWAPs ([#1750]) - ([**@jmoosburger**], [**@MatthiasReumann**]) +- ✨ Add an `absorb-swaps` pass for absorbing initial SWAPs ([#1750]) + ([**@jmoosburger**], [**@MatthiasReumann**], [**@burgholzer**]) - ✨ Add a `fuse-single-qubit-unitary-runs` pass for fusing compile-time single-qubit unitary runs via Euler resynthesis ([#1672]) ([**@simon1hofmann**], [**@burgholzer**]) From bda8d0fd3dfae513aeacf408b17effbb6f5f3efe Mon Sep 17 00:00:00 2001 From: Daniel Haag <121057143+denialhaag@users.noreply.github.com> Date: Fri, 19 Jun 2026 19:10:48 +0200 Subject: [PATCH 27/30] =?UTF-8?q?=E2=9C=85=20Improve=20test=20stability=20?= =?UTF-8?q?(#1794)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR should improve the stability of some of the timing-based QDMI tests. We have recently seen them failing more and more. ## Checklist - [x] The pull request only contains commits that are focused and relevant to this change. - [x] ~~I have added appropriate tests that cover the new/changed functionality.~~ - [x] ~~I have updated the documentation to reflect these changes.~~ - [x] ~~I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.~~ - [x] ~~I have added migration instructions to the upgrade guide (if needed).~~ - [x] The changes follow the project's style guidelines and introduce no new warnings. - [x] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes. --- test/algorithms/test_qpe.cpp | 2 +- test/qdmi/devices/dd/device_status_test.cpp | 31 ++------------------ test/qdmi/devices/dd/error_handling_test.cpp | 4 +-- test/qdmi/devices/dd/helpers/circuits.hpp | 14 +++++++-- test/qdmi/devices/dd/job_lifecycle_test.cpp | 2 +- 5 files changed, 18 insertions(+), 35 deletions(-) diff --git a/test/algorithms/test_qpe.cpp b/test/algorithms/test_qpe.cpp index 553f3dfac1..287b658b70 100644 --- a/test/algorithms/test_qpe.cpp +++ b/test/algorithms/test_qpe.cpp @@ -175,7 +175,7 @@ TEST_P(QPE, IQPETest) { auto qc = qc::createIterativeQPE(lambda, precision); ASSERT_EQ(qc.getNqubits(), 2U); - constexpr auto shots = 8192U; + constexpr auto shots = 16384U; const auto measurements = dd::sample(qc, shots); // sort the measurements diff --git a/test/qdmi/devices/dd/device_status_test.cpp b/test/qdmi/devices/dd/device_status_test.cpp index 67054e518a..2943ebf93c 100644 --- a/test/qdmi/devices/dd/device_status_test.cpp +++ b/test/qdmi/devices/dd/device_status_test.cpp @@ -39,9 +39,9 @@ TEST(DeviceStatus, TransitionsBusyThenIdleAfterJob) { // it. Submit a job to force BUSY then completion to IDLE. const qdmi_test::JobGuard j{s.session}; ASSERT_EQ(qdmi_test::setProgram(j.job, QDMI_PROGRAM_FORMAT_QASM3, - qdmi_test::QASM3_BELL_SAMPLING), + qdmi_test::QASM3_HEAVY_SAMPLING), QDMI_SUCCESS); - ASSERT_EQ(qdmi_test::setShots(j.job, 4096), QDMI_SUCCESS); + ASSERT_EQ(qdmi_test::setShots(j.job, 16384), QDMI_SUCCESS); ASSERT_EQ(MQT_DDSIM_QDMI_device_job_submit(j.job), QDMI_SUCCESS); // Poll while running to observe BUSY at least once. @@ -65,30 +65,3 @@ TEST(DeviceStatus, TransitionsBusyThenIdleAfterJob) { // After completion, the status should be IDLE. EXPECT_EQ(queryStatus(s.session), QDMI_DEVICE_STATUS_IDLE); } - -TEST(DeviceStatus, MultipleConcurrentJobsKeepBusyUntilLastFinishes) { - const qdmi_test::SessionGuard s{}; - - const qdmi_test::JobGuard j1{s.session}; - const qdmi_test::JobGuard j2{s.session}; - ASSERT_EQ(qdmi_test::setProgram(j1.job, QDMI_PROGRAM_FORMAT_QASM3, - qdmi_test::QASM3_BELL_SAMPLING), - QDMI_SUCCESS); - ASSERT_EQ(qdmi_test::setProgram(j2.job, QDMI_PROGRAM_FORMAT_QASM3, - qdmi_test::QASM3_HEAVY_SAMPLING5), - QDMI_SUCCESS); - ASSERT_EQ(qdmi_test::setShots(j1.job, 1024), QDMI_SUCCESS); - ASSERT_EQ(qdmi_test::setShots(j2.job, 16384), QDMI_SUCCESS); - - ASSERT_EQ(MQT_DDSIM_QDMI_device_job_submit(j1.job), QDMI_SUCCESS); - ASSERT_EQ(MQT_DDSIM_QDMI_device_job_submit(j2.job), QDMI_SUCCESS); - - // Wait for first to finish - ASSERT_EQ(MQT_DDSIM_QDMI_device_job_wait(j1.job, 0), QDMI_SUCCESS); - // Status should still be BUSY while the second runs - EXPECT_EQ(queryStatus(s.session), QDMI_DEVICE_STATUS_BUSY); - - // Wait for second, then status should go IDLE - ASSERT_EQ(MQT_DDSIM_QDMI_device_job_wait(j2.job, 0), QDMI_SUCCESS); - EXPECT_EQ(queryStatus(s.session), QDMI_DEVICE_STATUS_IDLE); -} diff --git a/test/qdmi/devices/dd/error_handling_test.cpp b/test/qdmi/devices/dd/error_handling_test.cpp index b2766c051a..c67f1ec19b 100644 --- a/test/qdmi/devices/dd/error_handling_test.cpp +++ b/test/qdmi/devices/dd/error_handling_test.cpp @@ -75,9 +75,9 @@ TEST_F(ErrorHandling, GetResultsBeforeDone) { const qdmi_test::SessionGuard s{}; const qdmi_test::JobGuard j{s.session}; ASSERT_EQ(qdmi_test::setProgram(j.job, QDMI_PROGRAM_FORMAT_QASM3, - qdmi_test::QASM3_BELL_SAMPLING), + qdmi_test::QASM3_HEAVY_SAMPLING), QDMI_SUCCESS); - ASSERT_EQ(qdmi_test::setShots(j.job, 64), QDMI_SUCCESS); + ASSERT_EQ(qdmi_test::setShots(j.job, 16384), QDMI_SUCCESS); // Before submit → invalid EXPECT_EQ(MQT_DDSIM_QDMI_device_job_get_results( j.job, QDMI_JOB_RESULT_HIST_KEYS, 0, nullptr, nullptr), diff --git a/test/qdmi/devices/dd/helpers/circuits.hpp b/test/qdmi/devices/dd/helpers/circuits.hpp index 156dd1de94..b6f7564ff1 100644 --- a/test/qdmi/devices/dd/helpers/circuits.hpp +++ b/test/qdmi/devices/dd/helpers/circuits.hpp @@ -32,9 +32,9 @@ cx q[0], q[1]; inline constexpr const char* QASM3_MALFORMED = "Definitely not OpenQASM"; -// A slightly heavier 5-qubit sampling circuit to prolong runtime slightly while +// A slightly heavier dynamic sampling circuit to prolong runtime slightly while // remaining fast -inline constexpr auto QASM3_HEAVY_SAMPLING5 = R"( +inline constexpr auto QASM3_HEAVY_SAMPLING = R"( OPENQASM 3; include "stdgates.inc"; qubit[5] q; @@ -58,6 +58,16 @@ cx q[1], q[2]; cx q[0], q[1]; // Measure all qubits c = measure q; +// Add dynamic component +if (c == 3) { + rx(0.7) q[0]; + ry(0.5) q[1]; + rz(1.1) q[2]; + ry(0.3) q[3]; + rx(0.9) q[4]; +} +// Measure all qubits again +c = measure q; )"; } // namespace qdmi_test diff --git a/test/qdmi/devices/dd/job_lifecycle_test.cpp b/test/qdmi/devices/dd/job_lifecycle_test.cpp index 267740641b..bf9be9282f 100644 --- a/test/qdmi/devices/dd/job_lifecycle_test.cpp +++ b/test/qdmi/devices/dd/job_lifecycle_test.cpp @@ -111,7 +111,7 @@ TEST(JobLifecycle, FreeWhileRunningWaitsForCompletion) { ASSERT_EQ(MQT_DDSIM_QDMI_device_session_create_device_job(s.session, &job), QDMI_SUCCESS); ASSERT_EQ(qdmi_test::setProgram(job, QDMI_PROGRAM_FORMAT_QASM3, - qdmi_test::QASM3_HEAVY_SAMPLING5), + qdmi_test::QASM3_HEAVY_SAMPLING), QDMI_SUCCESS); ASSERT_EQ(qdmi_test::setShots(job, 4096), QDMI_SUCCESS); ASSERT_EQ(MQT_DDSIM_QDMI_device_job_submit(job), QDMI_SUCCESS); From 7b06a2c117d19deab6637e59e3396cacb45f6178 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:20:09 +0000 Subject: [PATCH 28/30] =?UTF-8?q?=E2=AC=86=EF=B8=8F=F0=9F=A9=B9=20Update?= =?UTF-8?q?=20minor=20stable=20updates=20to=20v2026.06.12=20(#1796)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff91510405..c50291fcb6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -47,7 +47,7 @@ repos: ## Check pyproject.toml file - repo: https://github.com/henryiii/validate-pyproject-schema-store - rev: 2026.05.28 + rev: 2026.06.12 hooks: - id: validate-pyproject priority: 0 From 6776770a4f18c8c3658072debcfc48ab90527bcd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:26:29 +0000 Subject: [PATCH 29/30] =?UTF-8?q?=E2=AC=86=EF=B8=8F=F0=9F=A9=B9=20Update?= =?UTF-8?q?=20patch=20updates=20(#1795)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c50291fcb6..f365d82b98 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: ## Check JSON schemata - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.37.2 + rev: 0.37.3 hooks: - id: check-github-workflows priority: 0 @@ -54,7 +54,7 @@ repos: ## Ensure uv.lock is up to date - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.11.19 + rev: 0.11.21 hooks: - id: uv-lock priority: 0 @@ -104,7 +104,7 @@ repos: ## Format configuration files with prettier - repo: https://github.com/rbubley/mirrors-prettier - rev: v3.8.3 + rev: v3.8.4 hooks: - id: prettier types_or: [yaml, html, css, scss, javascript, json, json5] @@ -145,7 +145,7 @@ repos: ## Format and lint Python files with ruff - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.16 + rev: v0.15.17 hooks: - id: ruff-format types_or: [python, pyi, jupyter, markdown] @@ -156,7 +156,7 @@ repos: ## Check Python types with ty - repo: https://github.com/astral-sh/ty-pre-commit - rev: v0.0.47 + rev: v0.0.49 hooks: - id: ty args: [--only-dev] From 4b1cd34b76ffdacd2b090a80f2d8083ff0de441c Mon Sep 17 00:00:00 2001 From: Johannes Moosburger Date: Sat, 20 Jun 2026 16:50:32 +0200 Subject: [PATCH 30/30] replace c casts with mlir::casts --- .../Optimizations/test_swapabsorption.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp index eba0ec646d..9f46daa371 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Optimizations/test_swapabsorption.cpp @@ -98,8 +98,8 @@ TEST_F(SwapAbsorbPassTest, PassReordersTwoQubitCircuitWithLeadingSwap) { auto moduleThroughPass = builder.finalize(); applySwapAbsorb(moduleThroughPass); - ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q10, mlir::cast(q02.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, mlir::cast(q12.getDefiningOp()).getInputQubit(0)); } TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoIndependentSwaps) { @@ -128,10 +128,10 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoIndependentSwaps) { auto moduleThroughPass = builder.finalize(); applySwapAbsorb(moduleThroughPass); - ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q00, ((IdOp)q12.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q30, ((IdOp)q22.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q20, ((IdOp)q32.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q10, mlir::cast(q02.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, mlir::cast(q12.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q30, mlir::cast(q22.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q20, mlir::cast(q32.getDefiningOp()).getInputQubit(0)); } TEST_F(SwapAbsorbPassTest, PassAbsorbsSwapWithLeadingSingleQubitGates) { @@ -156,8 +156,8 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsSwapWithLeadingSingleQubitGates) { auto moduleThroughPass = builder.finalize(); applySwapAbsorb(moduleThroughPass); - ASSERT_EQ(q11, ((IdOp)q03.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q01, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q11, mlir::cast(q03.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q01, mlir::cast(q13.getDefiningOp()).getInputQubit(0)); } TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoDependentSwaps) { @@ -183,7 +183,7 @@ TEST_F(SwapAbsorbPassTest, PassAbsorbsTwoDependentSwaps) { auto moduleThroughPass = builder.finalize(); applySwapAbsorb(moduleThroughPass); - ASSERT_EQ(q20, ((IdOp)q13.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q00, ((IdOp)q22.getDefiningOp()).getInputQubit(0)); - ASSERT_EQ(q10, ((IdOp)q02.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q20, mlir::cast(q13.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q00, mlir::cast(q22.getDefiningOp()).getInputQubit(0)); + ASSERT_EQ(q10, mlir::cast(q02.getDefiningOp()).getInputQubit(0)); }