From 9f12eaa290c4b3e571498160cb8f84f77397e956 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 23 Oct 2025 10:29:32 +0200 Subject: [PATCH 01/27] Remove beta factor and ndepth calculation --- .../mlir/Dialect/MQTOpt/Transforms/Passes.td | 2 -- .../MQTOpt/Transforms/Transpilation/Router.h | 32 ++++++------------- .../Transpilation/sc/PlacementPass.cpp | 2 +- .../Transpilation/sc/RoutingPass.cpp | 4 +-- .../sc/RoutingVerificationPass.cpp | 2 +- 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td index 40881938b1..9dda7dbdd6 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td @@ -122,8 +122,6 @@ def RoutingPassSC : Pass<"route-sc", "mlir::ModuleOp"> { "astar option: Number of lookahead steps (heuristic horizon)">, Option<"alpha", "alpha", "float", "1.0F", "astar option: The alpha factor in the cost function">, - Option<"beta", "beta", "float", "1.0F", - "astar option: The beta factor in the cost function">, Option<"lambda", "lambda", "float", "0.5F", "astar option: The lambda factor in the cost function"> ]; diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 1bcb7c9e85..58181ae540 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -69,13 +69,12 @@ struct NaiveRouter final : RouterBase { */ struct HeuristicWeights { float alpha; - float beta; mlir::SmallVector lambdas; - HeuristicWeights(const float alpha, const float beta, const float lambda, + HeuristicWeights(const float alpha, const float lambda, const std::size_t nlookahead) - : alpha(alpha), beta(beta), lambdas(1 + nlookahead) { - lambdas[0] = 1.0; + : alpha(alpha), lambdas(1 + nlookahead) { + lambdas[0] = 1.; for (std::size_t i = 1; i < lambdas.size(); ++i) { lambdas[i] = lambdas[i - 1] * lambda; } @@ -94,7 +93,7 @@ struct AStarHeuristicRouter final : RouterBase { const Architecture& arch) const override { /// Initialize queue. MinQueue frontier{}; - expand(frontier, SearchNode(layout, arch.nqubits()), layers, arch); + expand(frontier, SearchNode(layout), layers, arch); /// Iterative searching and expanding. while (!frontier.empty()) { @@ -117,8 +116,7 @@ struct AStarHeuristicRouter final : RouterBase { * @brief Construct a root node with the given layout. Initialize the * sequence with an empty vector and set the cost to zero. */ - SearchNode(ThinLayout layout, const std::size_t nqubits) - : layout_(std::move(layout)), depthBuckets_(nqubits) {} + explicit SearchNode(ThinLayout layout) : layout_(std::move(layout)) {} /** * @brief Construct a non-root node from its parent node. Apply the given @@ -127,21 +125,13 @@ struct AStarHeuristicRouter final : RouterBase { SearchNode(const SearchNode& parent, QubitIndexPair swap, const Layers& layers, const Architecture& arch, const HeuristicWeights& weights) - : seq_(parent.seq_), layout_(parent.layout_), - depthBuckets_(parent.depthBuckets_), ndepth_(parent.ndepth_) { + : seq_(parent.seq_), layout_(parent.layout_) { /// Apply node-specific swap to given layout. layout_.swap(layout_.getProgramIndex(swap.first), layout_.getProgramIndex(swap.second)); /// Add swap to sequence. seq_.push_back(swap); - /// Update degrees. - const uint16_t start = - std::max(depthBuckets_[swap.first], depthBuckets_[swap.second]); - const uint16_t finish = start + 1; - depthBuckets_[swap.first] = depthBuckets_[swap.second] = finish; - ndepth_ = std::max(ndepth_, finish); - /// Evaluate cost function. f_ = g(weights) + h(layers, arch, weights); // NOLINT } @@ -178,12 +168,11 @@ struct AStarHeuristicRouter final : RouterBase { /** * @brief Calculate the path cost for the A* search algorithm. * - * The path cost function evaluates the weighted sum of the currently - * required SWAPs and additionally added depth. + * The path cost function is the weighted sum of the currently required + * SWAPs. */ [[nodiscard]] float g(const HeuristicWeights& weights) { - return (weights.alpha * static_cast(seq_.size())) + - (weights.beta * static_cast(ndepth_)); + return (weights.alpha * static_cast(seq_.size())); } /** @@ -216,9 +205,6 @@ struct AStarHeuristicRouter final : RouterBase { mlir::SmallVector seq_; ThinLayout layout_; - mlir::SmallVector depthBuckets_; - uint16_t ndepth_{0}; - float f_{0}; }; diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp index 1dc40f57ce..590ab2a16a 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp @@ -425,7 +425,7 @@ struct PlacementPassSC final : impl::PlacementPassSCBase { using PlacementPassSCBase::PlacementPassSCBase; void runOnOperation() override { - const auto arch = getArchitecture(ArchitectureName::MQTTest); + const auto arch = getArchitecture(ArchitectureName::IBMFalcon); const auto placer = getPlacer(*arch); const auto start = std::chrono::steady_clock::now(); diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index d94e714122..6a57cf732b 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -505,7 +505,7 @@ struct RoutingPassSC final : impl::RoutingPassSCBase { private: [[nodiscard]] Mapper getMapper() { /// TODO: Configurable Architecture. - auto arch = getArchitecture(ArchitectureName::MQTTest); + auto arch = getArchitecture(ArchitectureName::IBMFalcon); switch (static_cast(method)) { case RoutingMethod::Naive: @@ -514,7 +514,7 @@ struct RoutingPassSC final : impl::RoutingPassSCBase { std::make_unique(), numSwaps); case RoutingMethod::AStar: LLVM_DEBUG({ llvm::dbgs() << "getRouter: method=astar\n"; }); - const HeuristicWeights weights(alpha, beta, lambda, nlookahead); + const HeuristicWeights weights(alpha, lambda, nlookahead); return Mapper(std::move(arch), std::make_unique(nlookahead), std::make_unique(weights), numSwaps); diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp index a692719ede..17bd4c3672 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp @@ -220,7 +220,7 @@ WalkResult handleMeasure(MeasureOp op, VerificationContext& ctx) { struct RoutingVerificationPassSC final : impl::RoutingVerificationSCPassBase { void runOnOperation() override { - const auto arch = getArchitecture(ArchitectureName::MQTTest); + const auto arch = getArchitecture(ArchitectureName::IBMFalcon); VerificationContext ctx(*arch); const auto res = From a64d10cbddff835bf37118d8f127b49eefffda1a Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 23 Oct 2025 10:29:51 +0200 Subject: [PATCH 02/27] Precompute neighbours in Architecture --- .../Transforms/Transpilation/Architecture.h | 24 ++++-- .../Transforms/Transpilation/Architecture.cpp | 73 ++++++++++++++++--- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h index cc3c72f670..2a07bb092e 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h @@ -25,7 +25,7 @@ namespace mqt::ir::opt { /** * @brief Enumerates the available target architectures. */ -enum class ArchitectureName : std::uint8_t { MQTTest }; +enum class ArchitectureName : std::uint8_t { MQTTest, IBMFalcon }; /** * @brief A quantum accelerator's architecture. @@ -33,15 +33,17 @@ enum class ArchitectureName : std::uint8_t { MQTTest }; */ class Architecture { public: - using CouplingMap = llvm::DenseSet>; + using CouplingSet = mlir::DenseSet>; + using NeighbourVector = mlir::SmallVector>; explicit Architecture(std::string name, std::size_t nqubits, - CouplingMap couplingMap) + CouplingSet couplingSet) : name_(std::move(name)), nqubits_(nqubits), - couplingMap_(std::move(couplingMap)), + couplingSet_(std::move(couplingSet)), neighbours_(nqubits), dist_(nqubits, llvm::SmallVector(nqubits, UINT64_MAX)), prev_(nqubits, llvm::SmallVector(nqubits, UINT64_MAX)) { floydWarshallWithPathReconstruction(); + collectNeighbours(); } /** @@ -58,7 +60,7 @@ class Architecture { * @brief Return true if @p u and @p v are adjacent. */ [[nodiscard]] bool areAdjacent(QubitIndex u, QubitIndex v) const { - return couplingMap_.contains({u, v}); + return couplingSet_.contains({u, v}); } /** @@ -76,7 +78,8 @@ class Architecture { /** * @brief Collect all neighbours of @p u. */ - [[nodiscard]] llvm::SmallVector neighboursOf(QubitIndex u) const; + [[nodiscard]] llvm::SmallVector + neighboursOf(QubitIndex u) const; private: using Matrix = llvm::SmallVector>; @@ -89,9 +92,16 @@ class Architecture { */ void floydWarshallWithPathReconstruction(); + /** + * @brief Collect the neighbours of all qubits. + * @details Has a time complexity of O(nqubits) + */ + void collectNeighbours(); + std::string name_; std::size_t nqubits_; - CouplingMap couplingMap_; + CouplingSet couplingSet_; + NeighbourVector neighbours_; Matrix dist_; Matrix prev_; diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp index b743828d0f..075efbc51d 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp @@ -48,7 +48,7 @@ Architecture::shortestPathBetween(QubitIndex u, QubitIndex v) const { } void Architecture::floydWarshallWithPathReconstruction() { - for (const auto& [u, v] : couplingMap_) { + for (const auto& [u, v] : couplingSet_) { dist_[u][v] = 1; prev_[u][v] = u; } @@ -73,15 +73,15 @@ void Architecture::floydWarshallWithPathReconstruction() { } } -[[nodiscard]] llvm::SmallVector -Architecture::neighboursOf(QubitIndex u) const { - llvm::SmallVector n; - for (const auto [i, j] : couplingMap_) { - if (i == u) { - n.push_back(j); - } +void Architecture::collectNeighbours() { + for (const auto& [u, v] : couplingSet_) { + neighbours_[u].push_back(v); } - return n; +} + +[[nodiscard]] llvm::SmallVector +Architecture::neighboursOf(QubitIndex u) const { + return neighbours_[u]; } std::unique_ptr getArchitecture(const ArchitectureName& name) { @@ -93,12 +93,65 @@ std::unique_ptr getArchitecture(const ArchitectureName& name) { // | | // 4 -- 5 - const Architecture::CouplingMap couplingMap{ + const Architecture::CouplingSet couplingMap{ {0, 1}, {1, 0}, {0, 2}, {2, 0}, {1, 3}, {3, 1}, {2, 3}, {3, 2}, {2, 4}, {4, 2}, {3, 5}, {5, 3}, {4, 5}, {5, 4}}; return std::make_unique("MQT-Test", 6, couplingMap); } + case ArchitectureName::IBMFalcon: { + const Architecture::CouplingSet couplingMap{ + {0, 1}, {0, 14}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, + {3, 2}, {3, 4}, {4, 3}, {4, 5}, {4, 15}, {5, 4}, + {5, 6}, {6, 5}, {6, 7}, {7, 6}, {7, 8}, {8, 7}, + {8, 16}, {9, 10}, {10, 9}, {10, 11}, {11, 10}, {11, 12}, + {12, 11}, {12, 13}, {12, 17}, {13, 12}, {14, 0}, {14, 18}, + {15, 4}, {15, 22}, {16, 8}, {16, 26}, {17, 12}, {17, 30}, + {18, 14}, {18, 19}, {19, 18}, {19, 20}, {20, 19}, {20, 21}, + {20, 33}, {21, 20}, {21, 22}, {22, 15}, {22, 21}, {22, 23}, + {23, 22}, {23, 24}, {24, 23}, {24, 25}, {24, 34}, {25, 24}, + {25, 26}, {26, 16}, {26, 25}, {26, 27}, {27, 26}, {27, 28}, + {28, 27}, {28, 29}, {28, 35}, {29, 28}, {29, 30}, {30, 17}, + {30, 29}, {30, 31}, {31, 30}, {31, 32}, {32, 31}, {32, 36}, + {33, 20}, {33, 39}, {34, 24}, {34, 43}, {35, 28}, {35, 47}, + {36, 32}, {36, 51}, {37, 38}, {37, 52}, {38, 37}, {38, 39}, + {39, 33}, {39, 38}, {39, 40}, {40, 39}, {40, 41}, {41, 40}, + {41, 42}, {41, 53}, {42, 41}, {42, 43}, {43, 34}, {43, 42}, + {43, 44}, {44, 43}, {44, 45}, {45, 44}, {45, 46}, {45, 54}, + {46, 45}, {46, 47}, {47, 35}, {47, 46}, {47, 48}, {48, 47}, + {48, 49}, {49, 48}, {49, 50}, {49, 55}, {50, 49}, {50, 51}, + {51, 36}, {51, 50}, {52, 37}, {52, 56}, {53, 41}, {53, 60}, + {54, 45}, {54, 64}, {55, 49}, {55, 68}, {56, 52}, {56, 57}, + {57, 56}, {57, 58}, {58, 57}, {58, 59}, {58, 71}, {59, 58}, + {59, 60}, {60, 53}, {60, 59}, {60, 61}, {61, 60}, {61, 62}, + {62, 61}, {62, 63}, {62, 72}, {63, 62}, {63, 64}, {64, 54}, + {64, 63}, {64, 65}, {65, 64}, {65, 66}, {66, 65}, {66, 67}, + {66, 73}, {67, 66}, {67, 68}, {68, 55}, {68, 67}, {68, 69}, + {69, 68}, {69, 70}, {70, 69}, {70, 74}, {71, 58}, {71, 77}, + {72, 62}, {72, 81}, {73, 66}, {73, 85}, {74, 70}, {74, 89}, + {75, 76}, {75, 90}, {76, 75}, {76, 77}, {77, 71}, {77, 76}, + {77, 78}, {78, 77}, {78, 79}, {79, 78}, {79, 80}, {79, 91}, + {80, 79}, {80, 81}, {81, 72}, {81, 80}, {81, 82}, {82, 81}, + {82, 83}, {83, 82}, {83, 84}, {83, 92}, {84, 83}, {84, 85}, + {85, 73}, {85, 84}, {85, 86}, {86, 85}, {86, 87}, {87, 86}, + {87, 88}, {87, 93}, {88, 87}, {88, 89}, {89, 74}, {89, 88}, + {90, 75}, {90, 94}, {91, 79}, {91, 98}, {92, 83}, {92, 102}, + {93, 87}, {93, 106}, {94, 90}, {94, 95}, {95, 94}, {95, 96}, + {96, 95}, {96, 97}, {96, 109}, {97, 96}, {97, 98}, {98, 91}, + {98, 97}, {98, 99}, {99, 98}, {99, 100}, {100, 99}, {100, 101}, + {100, 110}, {101, 100}, {101, 102}, {102, 92}, {102, 101}, {102, 103}, + {103, 102}, {103, 104}, {104, 103}, {104, 105}, {104, 111}, {105, 104}, + {105, 106}, {106, 93}, {106, 105}, {106, 107}, {107, 106}, {107, 108}, + {108, 107}, {108, 112}, {109, 96}, {110, 100}, {110, 118}, {111, 104}, + {111, 122}, {112, 108}, {112, 126}, {113, 114}, {114, 113}, {114, 115}, + {115, 114}, {115, 116}, {116, 115}, {116, 117}, {117, 116}, {117, 118}, + {118, 110}, {118, 117}, {118, 119}, {119, 118}, {119, 120}, {120, 119}, + {120, 121}, {121, 120}, {121, 122}, {122, 111}, {122, 121}, {122, 123}, + {123, 122}, {123, 124}, {124, 123}, {124, 125}, {125, 124}, {125, 126}, + {126, 112}, {126, 125}}; + + return std::make_unique("IBM-Falcon", 127, couplingMap); + } } throw std::invalid_argument("Unsupported architecture."); From 424698335d278e6c6de497ebc2f85a15a7ba8793 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 23 Oct 2025 15:13:29 +0200 Subject: [PATCH 03/27] Add early exit on expansion --- .../MQTOpt/Transforms/Transpilation/Router.h | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 58181ae540..b0b88a17a5 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,7 @@ namespace mqt::ir::opt { /** * @brief A vector of SWAPs. */ -using PlannerResult = mlir::SmallVector; +using RouterResult = mlir::SmallVector; /** * @brief A planner determines the sequence of swaps required to route an array @@ -35,17 +36,17 @@ of gates. */ struct RouterBase { virtual ~RouterBase() = default; - [[nodiscard]] virtual PlannerResult route(const Layers&, const ThinLayout&, - const Architecture&) const = 0; + [[nodiscard]] virtual RouterResult route(const Layers&, const ThinLayout&, + const Architecture&) const = 0; }; /** * @brief Use shortest path swapping to make one gate executable. */ struct NaiveRouter final : RouterBase { - [[nodiscard]] PlannerResult route(const Layers& layers, - const ThinLayout& layout, - const Architecture& arch) const override { + [[nodiscard]] RouterResult route(const Layers& layers, + const ThinLayout& layout, + const Architecture& arch) const override { if (layers.size() != 1 || layers.front().size() != 1) { throw std::invalid_argument( "NaiveRouter expects exactly one layer with one gate"); @@ -88,43 +89,48 @@ struct AStarHeuristicRouter final : RouterBase { explicit AStarHeuristicRouter(HeuristicWeights weights) : weights_(std::move(weights)) {} - [[nodiscard]] PlannerResult route(const Layers& layers, - const ThinLayout& layout, - const Architecture& arch) const override { + [[nodiscard]] RouterResult route(const Layers& layers, + const ThinLayout& layout, + const Architecture& arch) const override { + Node root(layout); + + /// Early exit. No SWAPs required: + if (root.isGoal(layers.front(), arch)) { + return {}; + } + /// Initialize queue. MinQueue frontier{}; - expand(frontier, SearchNode(layout), layers, arch); + frontier.emplace(root); /// Iterative searching and expanding. while (!frontier.empty()) { - SearchNode curr = frontier.top(); + Node curr = frontier.top(); frontier.pop(); - if (curr.isGoal(layers.front(), arch)) { - return curr.getSequence(); + /// Expand frontier with all neighbouring SWAPs in the current front. + if (const auto opt = expand(frontier, curr, layers, arch)) { + return opt.value(); } - - expand(frontier, curr, layers, arch); } return {}; } private: - struct SearchNode { + struct Node { /** * @brief Construct a root node with the given layout. Initialize the * sequence with an empty vector and set the cost to zero. */ - explicit SearchNode(ThinLayout layout) : layout_(std::move(layout)) {} + explicit Node(ThinLayout layout) : layout_(std::move(layout)) {} /** * @brief Construct a non-root node from its parent node. Apply the given * swap to the layout of the parent node and evaluate the cost. */ - SearchNode(const SearchNode& parent, QubitIndexPair swap, - const Layers& layers, const Architecture& arch, - const HeuristicWeights& weights) + Node(const Node& parent, QubitIndexPair swap, const Layers& layers, + const Architecture& arch, const HeuristicWeights& weights) : seq_(parent.seq_), layout_(parent.layout_) { /// Apply node-specific swap to given layout. layout_.swap(layout_.getProgramIndex(swap.first), @@ -160,9 +166,7 @@ struct AStarHeuristicRouter final : RouterBase { */ [[nodiscard]] const ThinLayout& getLayout() const { return layout_; } - [[nodiscard]] bool operator>(const SearchNode& rhs) const { - return f_ > rhs.f_; - } + [[nodiscard]] bool operator>(const Node& rhs) const { return f_ > rhs.f_; } private: /** @@ -208,21 +212,22 @@ struct AStarHeuristicRouter final : RouterBase { float f_{0}; }; - using MinQueue = - std::priority_queue, std::greater<>>; + using MinQueue = std::priority_queue, std::greater<>>; /** - * @brief Expand frontier with all possible neighbouring SWAPs in the current - * front. + * @brief Expand frontier with all neighbouring SWAPs in the current front. + * @returns SWAP sequence if a goal node is expanded. Otherwise: std::nullopt. */ - void expand(MinQueue& frontier, const SearchNode& node, const Layers& layers, - const Architecture& arch) const { + std::optional expand(MinQueue& frontier, const Node& node, + const Layers& layers, + const Architecture& arch) const { llvm::SmallDenseSet visited{}; for (const QubitIndexPair gate : layers.front()) { for (const auto prog : {gate.first, gate.second}) { const auto hw0 = node.getLayout().getHardwareIndex(prog); for (const auto hw1 : arch.neighboursOf(hw0)) { /// Ensure consistent hashing/comparison + /// TODO: This should be done automatically by a QubitIndexPair class. const QubitIndexPair swap = hw0 < hw1 ? QubitIndexPair{hw0, hw1} : QubitIndexPair{hw1, hw0}; @@ -230,11 +235,21 @@ struct AStarHeuristicRouter final : RouterBase { continue; } - frontier.emplace(node, swap, layers, arch, weights_); + Node child(node, swap, layers, arch, weights_); + + /// Early exit if child node is a goal node. + if (child.isGoal(layers.front(), arch)) { + return child.getSequence(); + } + + frontier.push(std::move(child)); + visited.insert(swap); } } } + + return std::nullopt; } HeuristicWeights weights_; From b45b2d5dd9632c3770e0854af75ce979897c6468 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 23 Oct 2025 16:10:57 +0200 Subject: [PATCH 04/27] Use std::minmax --- .../Dialect/MQTOpt/Transforms/Transpilation/Common.h | 1 + .../Dialect/MQTOpt/Transforms/Transpilation/Router.h | 11 ++++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h index c304195fd9..34690a4ea8 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h @@ -39,6 +39,7 @@ using QubitIndex = uint32_t; * @brief Represents a pair of qubit indices. */ using QubitIndexPair = std::pair; + /** * @brief Return true if the function contains "entry_point" in the passthrough * attribute. diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index b0b88a17a5..27b06fcf58 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -109,8 +109,8 @@ struct AStarHeuristicRouter final : RouterBase { frontier.pop(); /// Expand frontier with all neighbouring SWAPs in the current front. - if (const auto opt = expand(frontier, curr, layers, arch)) { - return opt.value(); + if (const auto optSeq = expand(frontier, curr, layers, arch)) { + return optSeq.value(); } } @@ -226,11 +226,8 @@ struct AStarHeuristicRouter final : RouterBase { for (const auto prog : {gate.first, gate.second}) { const auto hw0 = node.getLayout().getHardwareIndex(prog); for (const auto hw1 : arch.neighboursOf(hw0)) { - /// Ensure consistent hashing/comparison - /// TODO: This should be done automatically by a QubitIndexPair class. - const QubitIndexPair swap = - hw0 < hw1 ? QubitIndexPair{hw0, hw1} : QubitIndexPair{hw1, hw0}; - + /// Ensure consistent hashing/comparison. + const QubitIndexPair swap = std::minmax(hw0, hw1); if (visited.contains(swap)) { continue; } From d133c20fce6df396ff87cdc04cfa21d6971780f2 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 23 Oct 2025 16:44:10 +0200 Subject: [PATCH 05/27] Add closed set --- .../MQTOpt/Transforms/Transpilation/Layout.h | 31 +++++++++++++++++++ .../MQTOpt/Transforms/Transpilation/Router.h | 24 +++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h index 5f4d08084c..91d43f4458 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h @@ -12,6 +12,7 @@ #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h" +#include #include #include #include @@ -114,6 +115,9 @@ class [[nodiscard]] ThinLayout { * @brief Maps a hardware qubit index to its program index. */ SmallVector hardwareToProgram_; + +private: + friend struct llvm::DenseMapInfo; }; /** @@ -260,3 +264,30 @@ class [[nodiscard]] Layout : public ThinLayout { SmallVector qubits_; }; } // namespace mqt::ir::opt + +namespace llvm { +template <> struct DenseMapInfo { + using Layout = mqt::ir::opt::ThinLayout; + using VectorInfo = DenseMapInfo>; + + static Layout getEmptyKey() { + Layout layout(0); + layout.programToHardware_ = VectorInfo::getEmptyKey(); + return layout; + } + + static Layout getTombstoneKey() { + Layout layout(0); + layout.programToHardware_ = VectorInfo::getTombstoneKey(); + return layout; + } + + static unsigned getHashValue(const Layout& layout) { + return VectorInfo::getHashValue(layout.programToHardware_); + } + + static bool isEqual(const Layout& lhs, const Layout& rhs) { + return VectorInfo::isEqual(lhs.programToHardware_, rhs.programToHardware_); + } +}; +} // namespace llvm diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 27b06fcf58..8f1f7de17f 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -103,13 +103,17 @@ struct AStarHeuristicRouter final : RouterBase { MinQueue frontier{}; frontier.emplace(root); + /// Initialize closed set. + ClosedSet visited; + visited.insert(root.layout()); + /// Iterative searching and expanding. while (!frontier.empty()) { Node curr = frontier.top(); frontier.pop(); /// Expand frontier with all neighbouring SWAPs in the current front. - if (const auto optSeq = expand(frontier, curr, layers, arch)) { + if (const auto optSeq = expand(frontier, curr, visited, layers, arch)) { return optSeq.value(); } } @@ -164,7 +168,7 @@ struct AStarHeuristicRouter final : RouterBase { /** * @brief Return a const reference to the node's layout. */ - [[nodiscard]] const ThinLayout& getLayout() const { return layout_; } + [[nodiscard]] const ThinLayout& layout() const { return layout_; } [[nodiscard]] bool operator>(const Node& rhs) const { return f_ > rhs.f_; } @@ -212,6 +216,7 @@ struct AStarHeuristicRouter final : RouterBase { float f_{0}; }; + using ClosedSet = mlir::DenseSet; using MinQueue = std::priority_queue, std::greater<>>; /** @@ -219,16 +224,16 @@ struct AStarHeuristicRouter final : RouterBase { * @returns SWAP sequence if a goal node is expanded. Otherwise: std::nullopt. */ std::optional expand(MinQueue& frontier, const Node& node, - const Layers& layers, + ClosedSet& visited, const Layers& layers, const Architecture& arch) const { - llvm::SmallDenseSet visited{}; + llvm::SmallDenseSet swaps{}; for (const QubitIndexPair gate : layers.front()) { for (const auto prog : {gate.first, gate.second}) { - const auto hw0 = node.getLayout().getHardwareIndex(prog); + const auto hw0 = node.layout().getHardwareIndex(prog); for (const auto hw1 : arch.neighboursOf(hw0)) { /// Ensure consistent hashing/comparison. const QubitIndexPair swap = std::minmax(hw0, hw1); - if (visited.contains(swap)) { + if (swaps.insert(swap).second) { continue; } @@ -239,9 +244,12 @@ struct AStarHeuristicRouter final : RouterBase { return child.getSequence(); } - frontier.push(std::move(child)); + /// Skip already visited permutations. + if (!visited.insert(child.layout()).second) { + continue; + } - visited.insert(swap); + frontier.push(std::move(child)); } } } From d47a8eb1052f8818fddb9174409a0384d64d1730 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Fri, 24 Oct 2025 09:00:20 +0200 Subject: [PATCH 06/27] Reorder astar router class --- .../MQTOpt/Transforms/Transpilation/Router.h | 134 ++++++++---------- 1 file changed, 60 insertions(+), 74 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 8f1f7de17f..7b789fce0c 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -89,45 +89,19 @@ struct AStarHeuristicRouter final : RouterBase { explicit AStarHeuristicRouter(HeuristicWeights weights) : weights_(std::move(weights)) {} - [[nodiscard]] RouterResult route(const Layers& layers, - const ThinLayout& layout, - const Architecture& arch) const override { - Node root(layout); - - /// Early exit. No SWAPs required: - if (root.isGoal(layers.front(), arch)) { - return {}; - } - - /// Initialize queue. - MinQueue frontier{}; - frontier.emplace(root); - - /// Initialize closed set. - ClosedSet visited; - visited.insert(root.layout()); - - /// Iterative searching and expanding. - while (!frontier.empty()) { - Node curr = frontier.top(); - frontier.pop(); - - /// Expand frontier with all neighbouring SWAPs in the current front. - if (const auto optSeq = expand(frontier, curr, visited, layers, arch)) { - return optSeq.value(); - } - } - - return {}; - } - private: + using ClosedSet = mlir::DenseSet; + struct Node { + mlir::SmallVector sequence; + ThinLayout layout; + float f; + /** * @brief Construct a root node with the given layout. Initialize the * sequence with an empty vector and set the cost to zero. */ - explicit Node(ThinLayout layout) : layout_(std::move(layout)) {} + explicit Node(ThinLayout layout) : layout(std::move(layout)), f(0) {} /** * @brief Construct a non-root node from its parent node. Apply the given @@ -135,15 +109,16 @@ struct AStarHeuristicRouter final : RouterBase { */ Node(const Node& parent, QubitIndexPair swap, const Layers& layers, const Architecture& arch, const HeuristicWeights& weights) - : seq_(parent.seq_), layout_(parent.layout_) { + : sequence(parent.sequence), layout(parent.layout), f(0) { /// Apply node-specific swap to given layout. - layout_.swap(layout_.getProgramIndex(swap.first), - layout_.getProgramIndex(swap.second)); + layout.swap(layout.getProgramIndex(swap.first), + layout.getProgramIndex(swap.second)); + /// Add swap to sequence. - seq_.push_back(swap); + sequence.push_back(swap); /// Evaluate cost function. - f_ = g(weights) + h(layers, arch, weights); // NOLINT + f = g(weights) + h(layers, arch, weights); // NOLINT } /** @@ -153,24 +128,12 @@ struct AStarHeuristicRouter final : RouterBase { [[nodiscard]] bool isGoal(const mlir::ArrayRef& gates, const Architecture& arch) const { return std::ranges::all_of(gates, [&](const QubitIndexPair gate) { - return arch.areAdjacent(layout_.getHardwareIndex(gate.first), - layout_.getHardwareIndex(gate.second)); + return arch.areAdjacent(layout.getHardwareIndex(gate.first), + layout.getHardwareIndex(gate.second)); }); } - /** - * @brief Return the sequence of SWAPs. - */ - [[nodiscard]] mlir::SmallVector getSequence() const { - return seq_; - } - - /** - * @brief Return a const reference to the node's layout. - */ - [[nodiscard]] const ThinLayout& layout() const { return layout_; } - - [[nodiscard]] bool operator>(const Node& rhs) const { return f_ > rhs.f_; } + [[nodiscard]] bool operator>(const Node& rhs) const { return f > rhs.f; } private: /** @@ -180,7 +143,7 @@ struct AStarHeuristicRouter final : RouterBase { * SWAPs. */ [[nodiscard]] float g(const HeuristicWeights& weights) { - return (weights.alpha * static_cast(seq_.size())); + return (weights.alpha * static_cast(sequence.size())); } /** @@ -190,18 +153,13 @@ struct AStarHeuristicRouter final : RouterBase { * layer. For each gate, this is determined by the shortest distance between * its hardware qubits. Intuitively, this is the number of SWAPs that a * naive router would insert to route the layers. - * - * - * @todo Optimize to O(1) incremental updates by only recalculating costs - * affected by the most recent SWAP, similar to the LightSABRE - * algorithm approach. */ [[nodiscard]] float h(const Layers& layers, const Architecture& arch, - const HeuristicWeights& weights) { + const HeuristicWeights& weights) const { float nn{0}; for (const auto [i, layer] : llvm::enumerate(layers)) { for (const auto [prog0, prog1] : layer) { - const auto [hw0, hw1] = layout_.getHardwareIndices(prog0, prog1); + const auto [hw0, hw1] = layout.getHardwareIndices(prog0, prog1); const std::size_t dist = arch.distanceBetween(hw0, hw1); const std::size_t nswaps = dist < 2 ? 0 : dist - 2; nn += weights.lambdas[i] * static_cast(nswaps); @@ -209,43 +167,71 @@ struct AStarHeuristicRouter final : RouterBase { } return nn; } - - mlir::SmallVector seq_; - ThinLayout layout_; - - float f_{0}; }; - using ClosedSet = mlir::DenseSet; using MinQueue = std::priority_queue, std::greater<>>; +public: + [[nodiscard]] RouterResult route(const Layers& layers, + const ThinLayout& layout, + const Architecture& arch) const override { + Node root(layout); + + /// Early exit. No SWAPs required: + if (root.isGoal(layers.front(), arch)) { + return {}; + } + + /// Initialize queue. + MinQueue frontier{}; + frontier.emplace(root); + + /// Initialize closed set. + ClosedSet visited; + visited.insert(root.layout); + + /// Iterative searching and expanding. + while (!frontier.empty()) { + Node curr = frontier.top(); + frontier.pop(); + + /// Expand frontier with all neighbouring SWAPs in the current front. + if (const auto optSeq = expand(frontier, curr, visited, layers, arch)) { + return optSeq.value(); + } + } + + return {}; + } + +private: /** * @brief Expand frontier with all neighbouring SWAPs in the current front. * @returns SWAP sequence if a goal node is expanded. Otherwise: std::nullopt. */ - std::optional expand(MinQueue& frontier, const Node& node, + std::optional expand(MinQueue& frontier, const Node& parent, ClosedSet& visited, const Layers& layers, const Architecture& arch) const { - llvm::SmallDenseSet swaps{}; + llvm::SmallDenseSet swaps{}; for (const QubitIndexPair gate : layers.front()) { for (const auto prog : {gate.first, gate.second}) { - const auto hw0 = node.layout().getHardwareIndex(prog); + const auto hw0 = parent.layout.getHardwareIndex(prog); for (const auto hw1 : arch.neighboursOf(hw0)) { /// Ensure consistent hashing/comparison. const QubitIndexPair swap = std::minmax(hw0, hw1); - if (swaps.insert(swap).second) { + if (!swaps.insert(swap).second) { continue; } - Node child(node, swap, layers, arch, weights_); + Node child(parent, swap, layers, arch, weights_); /// Early exit if child node is a goal node. if (child.isGoal(layers.front(), arch)) { - return child.getSequence(); + return child.sequence; } /// Skip already visited permutations. - if (!visited.insert(child.layout()).second) { + if (!visited.insert(child.layout).second) { continue; } From fbdb8e9a66724e7c6647d601a35fda0313e54cfa Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Mon, 27 Oct 2025 08:53:08 +0100 Subject: [PATCH 07/27] Refactor getIns and getOuts: remove interface methods --- .../Transforms/Transpilation/Common.cpp | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp index 9a9284dc34..83bff3df54 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp @@ -20,7 +20,6 @@ #include #include #include -#include namespace mqt::ir::opt { namespace { @@ -48,34 +47,39 @@ bool isEntryPoint(mlir::func::FuncOp op) { }); } -/** - * @brief Check if a unitary acts on two qubits. - * @param u A unitary. - * @returns True iff the qubit gate acts on two qubits. - */ bool isTwoQubitGate(UnitaryInterface u) { - return u.getAllInQubits().size() == 2; + return (u.getInQubits().size() + u.getPosCtrlInQubits().size() + + u.getNegCtrlInQubits().size()) == 2; } -/** - * @brief Return input qubit pair for a two-qubit unitary. - * @param u A two-qubit unitary. - * @return Pair of SSA values consisting of the first and second in-qubits. - */ [[nodiscard]] std::pair getIns(UnitaryInterface op) { assert(isTwoQubitGate(op)); - const std::vector inQubits = op.getAllInQubits(); - return {inQubits[0], inQubits[1]}; + + const auto target = op.getInQubits(); + const auto targetSize = target.size(); + + if (targetSize == 2) { + return {target[0], target[1]}; + } + + const auto posCtrl = op.getPosCtrlInQubits(); + return (posCtrl.size() == 1) + ? std::pair{target[0], posCtrl[0]} + : std::pair{target[0], op.getNegCtrlInQubits()[0]}; } -/** - * @brief Return output qubit pair for a two-qubit unitary. - * @param u A two-qubit unitary. - * @return Pair of SSA values consisting of the first and second out-qubits. - */ [[nodiscard]] std::pair getOuts(UnitaryInterface op) { assert(isTwoQubitGate(op)); - const std::vector outQubits = op.getAllOutQubits(); - return {outQubits[0], outQubits[1]}; + const auto target = op.getOutQubits(); + const auto targetSize = target.size(); + + if (targetSize == 2) { + return {target[0], target[1]}; + } + + const auto posCtrl = op.getPosCtrlOutQubits(); + return (posCtrl.size() == 1) + ? std::pair{target[0], posCtrl[0]} + : std::pair{target[0], op.getNegCtrlOutQubits()[0]}; } } // namespace mqt::ir::opt From d03cfd49880ee7c502535c735e114078e050735a Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Mon, 27 Oct 2025 08:53:24 +0100 Subject: [PATCH 08/27] Remove msTime --- mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td | 3 +-- .../MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td index 9dda7dbdd6..b5c0bb6ac2 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td @@ -126,8 +126,7 @@ def RoutingPassSC : Pass<"route-sc", "mlir::ModuleOp"> { "astar option: The lambda factor in the cost function"> ]; let statistics = [ - Statistic<"numSwaps", "num-additional-swaps", "The number of additional SWAPs">, - Statistic<"msTime", "runtime-milliseconds", "The runtime in milliseconds"> + Statistic<"numSwaps", "num-additional-swaps", "The number of additional SWAPs"> ]; } diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index 6a57cf732b..9f2c6a9673 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -492,14 +492,9 @@ struct RoutingPassSC final : impl::RoutingPassSCBase { void runOnOperation() override { Mapper mapper = getMapper(); - - const auto start = std::chrono::steady_clock::now(); if (failed(route(getOperation(), &getContext(), mapper))) { signalPassFailure(); } - const auto end = std::chrono::steady_clock::now(); - msTime = std::chrono::duration_cast(end - start) - .count(); } private: From 2ebf3839f5af0ba0cd04b1bfd72192593637850b Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Mon, 27 Oct 2025 09:14:43 +0100 Subject: [PATCH 09/27] Reorder typeswitch cases to better reflect most frequent ops --- .../Transforms/Transpilation/Scheduler.h | 124 ++++++++++++++---- .../Transpilation/sc/PlacementPass.cpp | 25 ++-- .../Transpilation/sc/RoutingPass.cpp | 19 +-- 3 files changed, 120 insertions(+), 48 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index 682a5f8fa4..69e9d41bfc 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -14,6 +14,9 @@ #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h" #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h" +#include "llvm/Support/Casting.h" + +#include #include #include #include @@ -62,21 +65,22 @@ struct SequentialOpScheduler final : SchedulerBase { */ struct ParallelOpScheduler final : SchedulerBase { explicit ParallelOpScheduler(const std::size_t nlookahead) - : nlookahead_(nlookahead) {} + : nlayers_(1 + nlookahead) {} [[nodiscard]] Layers schedule(UnitaryInterface op, const Layout& layout) const override { + Layers layers(nlayers_); Layout layoutCopy(layout); - Layers layers(1 + nlookahead_); const auto* region = op->getParentRegion(); - const auto qubits = layoutCopy.getHardwareQubits(); - const auto nqubits = qubits.size(); for (Layer& layer : layers) { mlir::DenseSet seenTwoQubit; mlir::SmallVector readyTwoQubit; + const auto qubits = layoutCopy.getHardwareQubits(); + const auto nqubits = qubits.size(); + /// The maximum amount of two-qubit gates in a layer is nqubits / 2. /// Assuming sparsity we half this value: nqubits / (2 * 2) seenTwoQubit.reserve(nqubits / 4); @@ -93,30 +97,19 @@ struct ParallelOpScheduler final : SchedulerBase { break; } + /// TypeSwitch performs sequential dyn_cast checks. + /// Hence, always put most frequent ops first. + mlir::TypeSwitch(user) - .Case([&](mlir::scf::ForOp op) { - /// This assumes that the first n results are the hardw. qubits. - head = op->getResult(layoutCopy.lookupHardwareIndex(head)); - }) - .Case([&](mlir::scf::IfOp op) { - /// This assumes that the first n results are the hardw. qubits. - head = op->getResult(layoutCopy.lookupHardwareIndex(head)); - }) - .Case([&](ResetOp op) { head = op.getOutQubit(); }) - .Case([&](MeasureOp op) { head = op.getOutQubit(); }) - .Case([&](BarrierOp op) { - for (const auto [in, out] : - llvm::zip_equal(op.getInQubits(), op.getOutQubits())) { - if (in == head) { - head = out; - break; - } - } - return; - }) .Case([&](UnitaryInterface op) { - if (mlir::isa(op)) { - stop = true; + if (mlir::isa(op)) { + for (const auto [in, out] : + llvm::zip_equal(op.getInQubits(), op.getOutQubits())) { + if (in == head) { + head = out; + break; + } + } return; } @@ -132,6 +125,16 @@ struct ParallelOpScheduler final : SchedulerBase { head = op.getOutQubits().front(); }) + .Case([&](ResetOp op) { head = op.getOutQubit(); }) + .Case([&](MeasureOp op) { head = op.getOutQubit(); }) + .Case([&](mlir::scf::ForOp op) { + /// This assumes that the first n results are the hardw. qubits. + head = op->getResult(layoutCopy.lookupHardwareIndex(head)); + }) + .Case([&](mlir::scf::IfOp op) { + /// This assumes that the first n results are the hardw. qubits. + head = op->getResult(layoutCopy.lookupHardwareIndex(head)); + }) .Default([&](mlir::Operation*) { stop = true; }); if (prev != head) { @@ -141,13 +144,20 @@ struct ParallelOpScheduler final : SchedulerBase { } } + if (readyTwoQubit.empty()) { + break; + } + for (const UnitaryInterface op : readyTwoQubit) { const auto [in0, in1] = getIns(op); const auto [out0, out1] = getOuts(op); - layer.emplace_back(layoutCopy.lookupProgramIndex(in0), - layoutCopy.lookupProgramIndex(in1)); layoutCopy.remapQubitValue(in0, out0); layoutCopy.remapQubitValue(in1, out1); + + layer.emplace_back(layoutCopy.lookupProgramIndex(out0), + layoutCopy.lookupProgramIndex(out1)); + + // skipTwoQubitBlock(out0, out1, layoutCopy, region); } } @@ -166,6 +176,62 @@ struct ParallelOpScheduler final : SchedulerBase { } private: + static void skipTwoQubitBlock(const Value q0, const Value q1, Layout& layout, + const Region* region) { + + std::array current{q0, q1}; + while (true) { + std::array gates{}; + + for (const auto [i, tail] : llvm::enumerate(current)) { + Value head = tail; + + while (!head.use_empty()) { + mlir::Operation* user = getUserInRegion(head, region); + if (user == nullptr) { + break; + } + + auto gate = mlir::dyn_cast(user); + if (!gate) { + break; + } + + if (llvm::isa(gate)) { + break; + } + + if (isTwoQubitGate(gate)) { + gates[i] = gate; + break; + } + + head = gate.getOutQubits().front(); + } + + if (tail != head) { + layout.remapQubitValue(tail, head); + } + } + + if (gates[0] == nullptr || gates[1] == nullptr) { + break; + } + + if (gates[0] != gates[1]) { + break; + } + + LLVM_DEBUG(llvm::dbgs() + << "skipTwoQubitBlock: skip= " << gates[0]->getName() << '\n'); + const auto [in0, in1] = getIns(gates[0]); + const auto [out0, out1] = getOuts(gates[0]); + layout.remapQubitValue(in0, out0); + layout.remapQubitValue(in1, out1); + current = {out0, out1}; + } + } + static mlir::Operation* getUserInRegion(const mlir::Value v, const mlir::Region* region) { for (mlir::Operation* user : v.getUsers()) { @@ -176,6 +242,6 @@ struct ParallelOpScheduler final : SchedulerBase { return nullptr; } - std::size_t nlookahead_ = 1; + std::size_t nlayers_; }; } // namespace mqt::ir::opt diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp index 590ab2a16a..730f90e246 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp @@ -378,8 +378,22 @@ LogicalResult run(ModuleOp module, MLIRContext* mlirCtx, const OpBuilder::InsertionGuard guard(rewriter); rewriter.setInsertionPoint(curr); + /// TypeSwitch performs sequential dyn_cast checks. + /// Hence, always put most frequent ops first. + const auto res = TypeSwitch(curr) + /// mqtopt Dialect + .Case( + [&](UnitaryInterface op) { return handleUnitary(op, ctx); }) + .Case( + [&](AllocQubitOp op) { return handleAlloc(op, ctx, rewriter); }) + .Case([&](DeallocQubitOp op) { + return handleDealloc(op, ctx, rewriter); + }) + .Case([&](ResetOp op) { return handleReset(op, ctx); }) + .Case( + [&](MeasureOp op) { return handleMeasure(op, ctx); }) /// built-in Dialect .Case( [&](ModuleOp /* op */) { return WalkResult::advance(); }) @@ -395,17 +409,6 @@ LogicalResult run(ModuleOp module, MLIRContext* mlirCtx, [&](scf::IfOp op) { return handleIf(op, ctx, rewriter); }) .Case( [&](scf::YieldOp op) { return handleYield(op, ctx, rewriter); }) - /// mqtopt Dialect - .Case( - [&](AllocQubitOp op) { return handleAlloc(op, ctx, rewriter); }) - .Case([&](DeallocQubitOp op) { - return handleDealloc(op, ctx, rewriter); - }) - .Case([&](ResetOp op) { return handleReset(op, ctx); }) - .Case( - [&](MeasureOp op) { return handleMeasure(op, ctx); }) - .Case( - [&](UnitaryInterface op) { return handleUnitary(op, ctx); }) /// Skip the rest. .Default([](auto) { return WalkResult::skip(); }); diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index 9f2c6a9673..4a1ab70635 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -445,8 +445,19 @@ LogicalResult route(ModuleOp module, MLIRContext* ctx, Mapper& mapper) { const OpBuilder::InsertionGuard guard(rewriter); rewriter.setInsertionPoint(curr); + /// TypeSwitch performs sequential dyn_cast checks. + /// Hence, always put most frequent ops first. + const auto res = TypeSwitch(curr) + /// mqtopt Dialect + .Case([&](UnitaryInterface op) { + return handleUnitary(op, mapper, rewriter); + }) + .Case([&](QubitOp op) { return handleQubit(op, mapper); }) + .Case([&](ResetOp op) { return handleReset(op, mapper); }) + .Case( + [&](MeasureOp op) { return handleMeasure(op, mapper); }) /// built-in Dialect .Case([&]([[maybe_unused]] ModuleOp op) { return WalkResult::advance(); @@ -464,14 +475,6 @@ LogicalResult route(ModuleOp module, MLIRContext* ctx, Mapper& mapper) { .Case([&](scf::YieldOp op) { return handleYield(op, mapper, rewriter); }) - /// mqtopt Dialect - .Case([&](QubitOp op) { return handleQubit(op, mapper); }) - .Case([&](ResetOp op) { return handleReset(op, mapper); }) - .Case( - [&](MeasureOp op) { return handleMeasure(op, mapper); }) - .Case([&](UnitaryInterface op) { - return handleUnitary(op, mapper, rewriter); - }) /// Skip the rest. .Default([](auto) { return WalkResult::skip(); }); From cfd0c8542564ed0743e5e1b91d3a6f8b7a8bf29d Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Tue, 28 Oct 2025 10:04:33 +0100 Subject: [PATCH 10/27] Refactor ParallelOpScheduler --- .../Transforms/Transpilation/Scheduler.h | 269 +++++++++--------- 1 file changed, 134 insertions(+), 135 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index 69e9d41bfc..c59ee45f00 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -14,7 +14,8 @@ #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h" #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Layout.h" -#include "llvm/Support/Casting.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #define DEBUG_TYPE "route-sc" @@ -31,13 +33,13 @@ namespace mqt::ir::opt { /** * @brief A vector of gates. */ -using Layer = mlir::SmallVector; +using Layer = SmallVector; /** * @brief A vector of layers. * [0]=current, [1]=lookahead (optional), >=2 future layers */ -using Layers = mlir::SmallVector; +using Layers = SmallVector; /** * @brief A scheduler divides the circuit into routable sections. @@ -45,7 +47,7 @@ using Layers = mlir::SmallVector; struct SchedulerBase { virtual ~SchedulerBase() = default; [[nodiscard]] virtual Layers schedule(UnitaryInterface op, - const Layout& layout) const = 0; + Layout layout) const = 0; }; /** @@ -53,7 +55,7 @@ struct SchedulerBase { */ struct SequentialOpScheduler final : SchedulerBase { [[nodiscard]] Layers schedule(UnitaryInterface op, - const Layout& layout) const override { + Layout layout) const override { const auto [in0, in1] = getIns(op); return {{{layout.lookupProgramIndex(in0), layout.lookupProgramIndex(in1)}}}; } @@ -68,79 +70,47 @@ struct ParallelOpScheduler final : SchedulerBase { : nlayers_(1 + nlookahead) {} [[nodiscard]] Layers schedule(UnitaryInterface op, - const Layout& layout) const override { - Layers layers(nlayers_); - Layout layoutCopy(layout); - - const auto* region = op->getParentRegion(); - - for (Layer& layer : layers) { - mlir::DenseSet seenTwoQubit; - mlir::SmallVector readyTwoQubit; - - const auto qubits = layoutCopy.getHardwareQubits(); - const auto nqubits = qubits.size(); - - /// The maximum amount of two-qubit gates in a layer is nqubits / 2. - /// Assuming sparsity we half this value: nqubits / (2 * 2) - seenTwoQubit.reserve(nqubits / 4); - readyTwoQubit.reserve(nqubits / 4); - - for (const mlir::Value q : qubits) { - bool stop = false; - mlir::Value prev = q; - mlir::Value head = q; - - while (!head.use_empty() && !stop) { - mlir::Operation* user = getUserInRegion(head, region); - if (user == nullptr) { - break; - } - - /// TypeSwitch performs sequential dyn_cast checks. - /// Hence, always put most frequent ops first. - - mlir::TypeSwitch(user) - .Case([&](UnitaryInterface op) { - if (mlir::isa(op)) { - for (const auto [in, out] : - llvm::zip_equal(op.getInQubits(), op.getOutQubits())) { - if (in == head) { - head = out; - break; - } - } - return; - } - - /// Insert two-qubit gates into seen-set. - /// If this is the second encounter, the gate is ready. - if (isTwoQubitGate(op)) { - if (!seenTwoQubit.insert(op.getOperation()).second) { - readyTwoQubit.emplace_back(op); - } - stop = true; - return; - } - - head = op.getOutQubits().front(); - }) - .Case([&](ResetOp op) { head = op.getOutQubit(); }) - .Case([&](MeasureOp op) { head = op.getOutQubit(); }) - .Case([&](mlir::scf::ForOp op) { - /// This assumes that the first n results are the hardw. qubits. - head = op->getResult(layoutCopy.lookupHardwareIndex(head)); - }) - .Case([&](mlir::scf::IfOp op) { - /// This assumes that the first n results are the hardw. qubits. - head = op->getResult(layoutCopy.lookupHardwareIndex(head)); - }) - .Default([&](mlir::Operation*) { stop = true; }); - - if (prev != head) { - layoutCopy.remapQubitValue(prev, head); - prev = head; - } + Layout layout) const override { + Layers layers; + layers.reserve(nlayers_); + + /// Worklist of active qubits. + SmallVector wl; + SmallVector nextWl; + wl.reserve(layout.getHardwareQubits().size()); + nextWl.reserve(layout.getHardwareQubits().size()); + + // Initialize worklist. + llvm::copy_if(layout.getHardwareQubits(), std::back_inserter(wl), + [](Value q) { return !q.use_empty(); }); + + /// Set of two-qubit gates seen at least once. + llvm::SmallDenseSet openTwoQubit; + + /// Vector of two-qubit gates seen twice. + SmallVector readyTwoQubit; + + while (!wl.empty() && layers.size() < nlayers_) { + for (const Value q : wl) { + const auto opt = + advanceDefUseUntilTwoQubitGate(q, op->getParentRegion(), layout); + + if (!opt) { + continue; + } + + const auto& [qNext, gate] = opt.value(); + + if (q != qNext) { + layout.remapQubitValue(q, qNext); + } + + /// If we've seen a two-qubit gate twice, we move it from "open" to + /// "ready". + if (!openTwoQubit.insert(gate).second) { + readyTwoQubit.push_back(gate); + openTwoQubit.erase(gate); + continue; } } @@ -148,17 +118,33 @@ struct ParallelOpScheduler final : SchedulerBase { break; } - for (const UnitaryInterface op : readyTwoQubit) { - const auto [in0, in1] = getIns(op); - const auto [out0, out1] = getOuts(op); - layoutCopy.remapQubitValue(in0, out0); - layoutCopy.remapQubitValue(in1, out1); + nextWl.clear(); + layers.emplace_back(); + layers.back().reserve(readyTwoQubit.size()); + + for (const auto& op : readyTwoQubit) { + const UnitaryInterface u = dyn_cast(op); + const auto [in0, in1] = getIns(u); + const auto [out0, out1] = getOuts(u); - layer.emplace_back(layoutCopy.lookupProgramIndex(out0), - layoutCopy.lookupProgramIndex(out1)); + layout.remapQubitValue(in0, out0); + layout.remapQubitValue(in1, out1); - // skipTwoQubitBlock(out0, out1, layoutCopy, region); + layers.back().emplace_back(layout.lookupProgramIndex(out0), + layout.lookupProgramIndex(out1)); + + if (!out0.use_empty()) { + nextWl.push_back(out0); + } + + if (!out1.use_empty()) { + nextWl.push_back(out1); + } } + + /// Prepare for next iteration. + readyTwoQubit.clear(); + wl = std::move(nextWl); } LLVM_DEBUG({ @@ -176,65 +162,78 @@ struct ParallelOpScheduler final : SchedulerBase { } private: - static void skipTwoQubitBlock(const Value q0, const Value q1, Layout& layout, - const Region* region) { - - std::array current{q0, q1}; + static std::optional> + advanceDefUseUntilTwoQubitGate(const Value q, const Region* region, + const Layout& layout) { + Value head = q; + Operation* twoQubitOp = nullptr; while (true) { - std::array gates{}; - - for (const auto [i, tail] : llvm::enumerate(current)) { - Value head = tail; - - while (!head.use_empty()) { - mlir::Operation* user = getUserInRegion(head, region); - if (user == nullptr) { - break; - } - - auto gate = mlir::dyn_cast(user); - if (!gate) { - break; - } - - if (llvm::isa(gate)) { - break; - } - - if (isTwoQubitGate(gate)) { - gates[i] = gate; - break; - } - - head = gate.getOutQubits().front(); - } - - if (tail != head) { - layout.remapQubitValue(tail, head); - } + if (head.use_empty()) { // No two-qubit gate found. + return std::nullopt; } - if (gates[0] == nullptr || gates[1] == nullptr) { - break; + if (twoQubitOp != nullptr) { // Two-qubit gate found. + return std::make_pair(head, twoQubitOp); } - if (gates[0] != gates[1]) { - break; + Operation* user = getUserInRegion(head, region); + if (user == nullptr) { // No two-qubit gate found. + return std::nullopt; } - LLVM_DEBUG(llvm::dbgs() - << "skipTwoQubitBlock: skip= " << gates[0]->getName() << '\n'); - const auto [in0, in1] = getIns(gates[0]); - const auto [out0, out1] = getOuts(gates[0]); - layout.remapQubitValue(in0, out0); - layout.remapQubitValue(in1, out1); - current = {out0, out1}; + bool endOfRegion = false; + TypeSwitch(user) + /// MQT + /// BarrierOp is a UnitaryInterface, however, requires special care. + .Case([&](BarrierOp op) { + for (const auto [in, out] : + llvm::zip_equal(op.getInQubits(), op.getOutQubits())) { + if (in == head) { + head = out; + return; + } + } + llvm_unreachable("head must be in barrier"); + }) + .Case([&](UnitaryInterface op) { + if (isTwoQubitGate(op)) { + twoQubitOp = op; + return; + } + + head = op.getOutQubits().front(); + }) + .Case([&](ResetOp op) { head = op.getOutQubit(); }) + .Case([&](MeasureOp op) { head = op.getOutQubit(); }) + /// SCF + /// The scf functions assume that the first n results are the + /// hardw. qubits. We can use 'q' to get the hardware index + /// because the def-use chain keeps the index constant. + .Case([&](scf::ForOp op) { + head = op->getResult(layout.lookupHardwareIndex(q)); + }) + .Case([&](scf::IfOp op) { + head = op->getResult(layout.lookupHardwareIndex(q)); + }) + .Case([&](scf::YieldOp) { endOfRegion = true; }) + .Default([&](Operation* op) { + LLVM_DEBUG({ + llvm::dbgs() << "unknown operation in def-use chain: "; + op->dump(); + }); + llvm_unreachable("unknown operation in def-use chain"); + }); + + if (endOfRegion) { + return std::nullopt; + } } + + return std::nullopt; } - static mlir::Operation* getUserInRegion(const mlir::Value v, - const mlir::Region* region) { - for (mlir::Operation* user : v.getUsers()) { + static Operation* getUserInRegion(const Value v, const Region* region) { + for (Operation* user : v.getUsers()) { if (user->getParentRegion() == region) { return user; } From ed83dc273fd82ddd21c62ef29184308151e75fa0 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Tue, 28 Oct 2025 10:22:43 +0100 Subject: [PATCH 11/27] Move getUserInRegion to Common.h --- .../MQTOpt/Transforms/Transpilation/Common.h | 15 ++++++++++++--- .../MQTOpt/Transforms/Transpilation/Common.cpp | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h index 34690a4ea8..ce568c0746 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h @@ -51,19 +51,28 @@ using QubitIndexPair = std::pair; * @param u A unitary. * @returns True iff the qubit gate acts on two qubits. */ -[[nodiscard]] bool isTwoQubitGate(UnitaryInterface u); +[[nodiscard]] bool isTwoQubitGate(UnitaryInterface op); /** * @brief Return input qubit pair for a two-qubit unitary. - * @param u A two-qubit unitary. + * @param op A two-qubit unitary. * @return Pair of SSA values consisting of the first and second in-qubits. */ [[nodiscard]] std::pair getIns(UnitaryInterface op); /** * @brief Return output qubit pair for a two-qubit unitary. - * @param u A two-qubit unitary. + * @param op A two-qubit unitary. * @return Pair of SSA values consisting of the first and second out-qubits. */ [[nodiscard]] std::pair getOuts(UnitaryInterface op); + +/** + * @brief Return the first user of a value in a given region. + * @param v The value. + * @param region The targeted region. + * @return A pointer to the user, or nullptr if non exists. + */ +[[nodiscard]] mlir::Operation* getUserInRegion(mlir::Value v, + mlir::Region* region); } // namespace mqt::ir::opt diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp index 83bff3df54..8ac72423ac 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp @@ -47,9 +47,9 @@ bool isEntryPoint(mlir::func::FuncOp op) { }); } -bool isTwoQubitGate(UnitaryInterface u) { - return (u.getInQubits().size() + u.getPosCtrlInQubits().size() + - u.getNegCtrlInQubits().size()) == 2; +bool isTwoQubitGate(UnitaryInterface op) { + return (op.getInQubits().size() + op.getPosCtrlInQubits().size() + + op.getNegCtrlInQubits().size()) == 2; } [[nodiscard]] std::pair getIns(UnitaryInterface op) { @@ -82,4 +82,14 @@ bool isTwoQubitGate(UnitaryInterface u) { ? std::pair{target[0], posCtrl[0]} : std::pair{target[0], op.getNegCtrlOutQubits()[0]}; } + +[[nodiscard]] mlir::Operation* getUserInRegion(mlir::Value v, + mlir::Region* region) { + for (mlir::Operation* user : v.getUsers()) { + if (user->getParentRegion() == region) { + return user; + } + } + return nullptr; +} } // namespace mqt::ir::opt From 9cf9f6f0469e75452218908babf5deb360b56dc5 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 09:11:00 +0100 Subject: [PATCH 12/27] Add two-qubit block skipping --- .../Transforms/Transpilation/Scheduler.h | 74 +++++++++++++------ 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index c59ee45f00..97496dfa39 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -62,8 +62,8 @@ struct SequentialOpScheduler final : SchedulerBase { }; /** - * @brief A crawl scheduler "crawls" the DAG for all gates that can be executed - * in parallel, i.e., they act on different qubits. + * @brief A parallel scheduler collects 1 + nlookahead layers of parallelly + * executable gates. */ struct ParallelOpScheduler final : SchedulerBase { explicit ParallelOpScheduler(const std::size_t nlookahead) @@ -88,13 +88,13 @@ struct ParallelOpScheduler final : SchedulerBase { llvm::SmallDenseSet openTwoQubit; /// Vector of two-qubit gates seen twice. - SmallVector readyTwoQubit; + SmallVector readyTwoQubit; + + Region* region = op->getParentRegion(); while (!wl.empty() && layers.size() < nlayers_) { for (const Value q : wl) { - const auto opt = - advanceDefUseUntilTwoQubitGate(q, op->getParentRegion(), layout); - + const auto opt = advanceToTwoQubitGate(q, region, layout); if (!opt) { continue; } @@ -105,8 +105,6 @@ struct ParallelOpScheduler final : SchedulerBase { layout.remapQubitValue(q, qNext); } - /// If we've seen a two-qubit gate twice, we move it from "open" to - /// "ready". if (!openTwoQubit.insert(gate).second) { readyTwoQubit.push_back(gate); openTwoQubit.erase(gate); @@ -123,16 +121,17 @@ struct ParallelOpScheduler final : SchedulerBase { layers.back().reserve(readyTwoQubit.size()); for (const auto& op : readyTwoQubit) { - const UnitaryInterface u = dyn_cast(op); - const auto [in0, in1] = getIns(u); - const auto [out0, out1] = getOuts(u); + const auto [in0, in1] = getIns(op); + + layers.back().emplace_back(layout.lookupProgramIndex(in0), + layout.lookupProgramIndex(in1)); + + const auto [out0, out1] = + advanceTwoQubitBlock(getOuts(op), layout, region); layout.remapQubitValue(in0, out0); layout.remapQubitValue(in1, out1); - layers.back().emplace_back(layout.lookupProgramIndex(out0), - layout.lookupProgramIndex(out1)); - if (!out0.use_empty()) { nextWl.push_back(out0); } @@ -162,11 +161,15 @@ struct ParallelOpScheduler final : SchedulerBase { } private: - static std::optional> - advanceDefUseUntilTwoQubitGate(const Value q, const Region* region, - const Layout& layout) { + using ValuePair = std::pair; + + /** + * @returns Next two-qubit gate on qubit wire, or std::nullopt if none exists. + */ + static std::optional> + advanceToTwoQubitGate(const Value q, Region* region, const Layout& layout) { Value head = q; - Operation* twoQubitOp = nullptr; + UnitaryInterface twoQubitOp = nullptr; while (true) { if (head.use_empty()) { // No two-qubit gate found. return std::nullopt; @@ -216,7 +219,7 @@ struct ParallelOpScheduler final : SchedulerBase { head = op->getResult(layout.lookupHardwareIndex(q)); }) .Case([&](scf::YieldOp) { endOfRegion = true; }) - .Default([&](Operation* op) { + .Default([&]([[maybe_unused]] Operation* op) { LLVM_DEBUG({ llvm::dbgs() << "unknown operation in def-use chain: "; op->dump(); @@ -232,13 +235,36 @@ struct ParallelOpScheduler final : SchedulerBase { return std::nullopt; } - static Operation* getUserInRegion(const Value v, const Region* region) { - for (Operation* user : v.getUsers()) { - if (user->getParentRegion() == region) { - return user; + static ValuePair advanceTwoQubitBlock(const ValuePair outs, Layout& layout, + Region* region) { + std::array heads{outs.first, outs.second}; + std::array gates{}; + + while (true) { + /// Advance both input qubits to a two-qubit gate. + /// Exit: If none is found. + /// If the two-qubit gates are not the same. + /// Otherwise, advance two-qubit gate and repeat process. + bool exit = false; + for (const auto [i, q] : llvm::enumerate(heads)) { + const auto opt = advanceToTwoQubitGate(q, region, layout); + if (!opt) { + exit = true; + break; + } + heads[i] = opt->first; + gates[i] = opt->second; } + + if (exit || gates[0] != gates[1]) { + break; + } + + const auto [out0, out1] = getOuts(gates[0]); + heads = {out0, out1}; } - return nullptr; + + return heads; } std::size_t nlayers_; From 2e78dd8401b68f8b4d73354db7a705a366cb1023 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 09:11:49 +0100 Subject: [PATCH 13/27] Remove msTime from placement pass --- mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td | 3 --- .../MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp | 5 ----- .../MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp | 4 ++-- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td index b5c0bb6ac2..680e095a4a 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td @@ -103,9 +103,6 @@ def PlacementPassSC : Pass<"placement-sc", "mlir::ModuleOp"> { clEnumValN(PlacementStrategy::Random, "random", "Random placement"), clEnumValN(PlacementStrategy::Identity, "identity", "Identity placement"))}]> ]; - let statistics = [ - Statistic<"tms", "runtime-milliseconds", "The runtime in milliseconds"> - ]; } def RoutingPassSC : Pass<"route-sc", "mlir::ModuleOp"> { diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp index 730f90e246..78daf90f08 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -431,14 +430,10 @@ struct PlacementPassSC final : impl::PlacementPassSCBase { const auto arch = getArchitecture(ArchitectureName::IBMFalcon); const auto placer = getPlacer(*arch); - const auto start = std::chrono::steady_clock::now(); if (PlacementContext ctx(*arch, *placer); failed(run(getOperation(), &getContext(), ctx))) { signalPassFailure(); } - const auto end = std::chrono::steady_clock::now(); - tms = std::chrono::duration_cast(end - start) - .count(); } private: diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index 4a1ab70635..88e7d42f6d 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -18,7 +18,6 @@ #include "mlir/Dialect/MQTOpt/Transforms/Transpilation/Stack.h" #include -#include #include #include #include @@ -183,7 +182,8 @@ class Mapper { for (const auto [hw0, hw1] : swaps) { const Value in0 = stack().top().lookupHardwareValue(hw0); const Value in1 = stack().top().lookupHardwareValue(hw1); - const auto [prog0, prog1] = stack().top().getProgramIndices(hw0, hw1); + [[maybe_unused]] const auto [prog0, prog1] = + stack().top().getProgramIndices(hw0, hw1); LLVM_DEBUG({ llvm::dbgs() << llvm::format( From fa2fbfb76b78f601230b85c2ce31df945c361fba Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 10:22:22 +0100 Subject: [PATCH 14/27] Revert early exit --- .../MQTOpt/Transforms/Transpilation/Router.h | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 7b789fce0c..276f6cdd8e 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -186,19 +186,17 @@ struct AStarHeuristicRouter final : RouterBase { MinQueue frontier{}; frontier.emplace(root); - /// Initialize closed set. - ClosedSet visited; - visited.insert(root.layout); - /// Iterative searching and expanding. while (!frontier.empty()) { Node curr = frontier.top(); frontier.pop(); - /// Expand frontier with all neighbouring SWAPs in the current front. - if (const auto optSeq = expand(frontier, curr, visited, layers, arch)) { - return optSeq.value(); + if (curr.isGoal(layers.front(), arch)) { + return curr.sequence; } + + /// Expand frontier with all neighbouring SWAPs in the current front. + expand(frontier, curr, layers, arch); } return {}; @@ -209,9 +207,8 @@ struct AStarHeuristicRouter final : RouterBase { * @brief Expand frontier with all neighbouring SWAPs in the current front. * @returns SWAP sequence if a goal node is expanded. Otherwise: std::nullopt. */ - std::optional expand(MinQueue& frontier, const Node& parent, - ClosedSet& visited, const Layers& layers, - const Architecture& arch) const { + void expand(MinQueue& frontier, const Node& parent, const Layers& layers, + const Architecture& arch) const { llvm::SmallDenseSet swaps{}; for (const QubitIndexPair gate : layers.front()) { for (const auto prog : {gate.first, gate.second}) { @@ -223,24 +220,10 @@ struct AStarHeuristicRouter final : RouterBase { continue; } - Node child(parent, swap, layers, arch, weights_); - - /// Early exit if child node is a goal node. - if (child.isGoal(layers.front(), arch)) { - return child.sequence; - } - - /// Skip already visited permutations. - if (!visited.insert(child.layout).second) { - continue; - } - - frontier.push(std::move(child)); + frontier.emplace(parent, swap, layers, arch, weights_); } } } - - return std::nullopt; } HeuristicWeights weights_; From ce7d64fe4644f898bcd0f526c0704918341b0436 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 13:06:52 +0100 Subject: [PATCH 15/27] Re-add closed map --- .../MQTOpt/Transforms/Transpilation/Router.h | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index 276f6cdd8e..df25917f32 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -28,7 +27,7 @@ namespace mqt::ir::opt { /** * @brief A vector of SWAPs. */ -using RouterResult = mlir::SmallVector; +using RouterResult = SmallVector; /** * @brief A planner determines the sequence of swaps required to route an array @@ -53,7 +52,7 @@ struct NaiveRouter final : RouterBase { } /// This assumes an avg. of 16 SWAPs per gate. - mlir::SmallVector swaps; + SmallVector swaps; for (const auto [prog0, prog1] : layers.front()) { const auto [hw0, hw1] = layout.getHardwareIndices(prog0, prog1); const auto path = arch.shortestPathBetween(hw0, hw1); @@ -70,7 +69,7 @@ struct NaiveRouter final : RouterBase { */ struct HeuristicWeights { float alpha; - mlir::SmallVector lambdas; + SmallVector lambdas; HeuristicWeights(const float alpha, const float lambda, const std::size_t nlookahead) @@ -90,10 +89,10 @@ struct AStarHeuristicRouter final : RouterBase { : weights_(std::move(weights)) {} private: - using ClosedSet = mlir::DenseSet; + using ClosedMap = DenseMap; struct Node { - mlir::SmallVector sequence; + SmallVector sequence; ThinLayout layout; float f; @@ -125,7 +124,7 @@ struct AStarHeuristicRouter final : RouterBase { * @brief Return true if the current sequence of SWAPs makes all gates * executable. */ - [[nodiscard]] bool isGoal(const mlir::ArrayRef& gates, + [[nodiscard]] bool isGoal(const ArrayRef& gates, const Architecture& arch) const { return std::ranges::all_of(gates, [&](const QubitIndexPair gate) { return arch.areAdjacent(layout.getHardwareIndex(gate.first), @@ -133,6 +132,11 @@ struct AStarHeuristicRouter final : RouterBase { }); } + /** + * @returns The depth in the search tree. + */ + [[nodiscard]] std::size_t depth() const { return sequence.size(); } + [[nodiscard]] bool operator>(const Node& rhs) const { return f > rhs.f; } private: @@ -142,8 +146,8 @@ struct AStarHeuristicRouter final : RouterBase { * The path cost function is the weighted sum of the currently required * SWAPs. */ - [[nodiscard]] float g(const HeuristicWeights& weights) { - return (weights.alpha * static_cast(sequence.size())); + [[nodiscard]] float g(const HeuristicWeights& weights) const { + return (weights.alpha * static_cast(depth())); } /** @@ -186,6 +190,9 @@ struct AStarHeuristicRouter final : RouterBase { MinQueue frontier{}; frontier.emplace(root); + /// Initialize visited map. + ClosedMap visited; + /// Iterative searching and expanding. while (!frontier.empty()) { Node curr = frontier.top(); @@ -195,6 +202,17 @@ struct AStarHeuristicRouter final : RouterBase { return curr.sequence; } + /// Don't revisit layouts that were discovered with a lower depth. + const auto [it, inserted] = + visited.try_emplace(curr.layout, curr.depth()); + if (!inserted && it->second <= curr.depth()) { + continue; + } + + if (!inserted) { + it->second = curr.sequence.size(); + } + /// Expand frontier with all neighbouring SWAPs in the current front. expand(frontier, curr, layers, arch); } From b5e4cbf325595062d38bd544b8f34f4a5bf5e313 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 18:38:27 +0100 Subject: [PATCH 16/27] Final touches --- .../mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h | 8 +++----- .../Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h index df25917f32..88b6698c25 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Router.h @@ -205,11 +205,10 @@ struct AStarHeuristicRouter final : RouterBase { /// Don't revisit layouts that were discovered with a lower depth. const auto [it, inserted] = visited.try_emplace(curr.layout, curr.depth()); - if (!inserted && it->second <= curr.depth()) { - continue; - } - if (!inserted) { + if (it->second <= curr.depth()) { + continue; + } it->second = curr.sequence.size(); } @@ -223,7 +222,6 @@ struct AStarHeuristicRouter final : RouterBase { private: /** * @brief Expand frontier with all neighbouring SWAPs in the current front. - * @returns SWAP sequence if a goal node is expanded. Otherwise: std::nullopt. */ void expand(MinQueue& frontier, const Node& parent, const Layers& layers, const Architecture& arch) const { diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index 97496dfa39..63b9efc830 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -235,6 +235,9 @@ struct ParallelOpScheduler final : SchedulerBase { return std::nullopt; } + /** + * @returns Pair of Values after two-qubit block. + */ static ValuePair advanceTwoQubitBlock(const ValuePair outs, Layout& layout, Region* region) { std::array heads{outs.first, outs.second}; From 81a5ce945fe8093c3ba8e412ea84849c22e8b6c3 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 18:40:17 +0100 Subject: [PATCH 17/27] Remove IBMFalcon --- .../Transforms/Transpilation/Architecture.h | 2 +- .../Transforms/Transpilation/Architecture.cpp | 53 ------------------- .../Transpilation/sc/PlacementPass.cpp | 2 +- .../Transpilation/sc/RoutingPass.cpp | 2 +- .../sc/RoutingVerificationPass.cpp | 2 +- 5 files changed, 4 insertions(+), 57 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h index 2a07bb092e..cbbb201e96 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Architecture.h @@ -25,7 +25,7 @@ namespace mqt::ir::opt { /** * @brief Enumerates the available target architectures. */ -enum class ArchitectureName : std::uint8_t { MQTTest, IBMFalcon }; +enum class ArchitectureName : std::uint8_t { MQTTest }; /** * @brief A quantum accelerator's architecture. diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp index 075efbc51d..bd0947c1d7 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Architecture.cpp @@ -99,59 +99,6 @@ std::unique_ptr getArchitecture(const ArchitectureName& name) { return std::make_unique("MQT-Test", 6, couplingMap); } - case ArchitectureName::IBMFalcon: { - const Architecture::CouplingSet couplingMap{ - {0, 1}, {0, 14}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, - {3, 2}, {3, 4}, {4, 3}, {4, 5}, {4, 15}, {5, 4}, - {5, 6}, {6, 5}, {6, 7}, {7, 6}, {7, 8}, {8, 7}, - {8, 16}, {9, 10}, {10, 9}, {10, 11}, {11, 10}, {11, 12}, - {12, 11}, {12, 13}, {12, 17}, {13, 12}, {14, 0}, {14, 18}, - {15, 4}, {15, 22}, {16, 8}, {16, 26}, {17, 12}, {17, 30}, - {18, 14}, {18, 19}, {19, 18}, {19, 20}, {20, 19}, {20, 21}, - {20, 33}, {21, 20}, {21, 22}, {22, 15}, {22, 21}, {22, 23}, - {23, 22}, {23, 24}, {24, 23}, {24, 25}, {24, 34}, {25, 24}, - {25, 26}, {26, 16}, {26, 25}, {26, 27}, {27, 26}, {27, 28}, - {28, 27}, {28, 29}, {28, 35}, {29, 28}, {29, 30}, {30, 17}, - {30, 29}, {30, 31}, {31, 30}, {31, 32}, {32, 31}, {32, 36}, - {33, 20}, {33, 39}, {34, 24}, {34, 43}, {35, 28}, {35, 47}, - {36, 32}, {36, 51}, {37, 38}, {37, 52}, {38, 37}, {38, 39}, - {39, 33}, {39, 38}, {39, 40}, {40, 39}, {40, 41}, {41, 40}, - {41, 42}, {41, 53}, {42, 41}, {42, 43}, {43, 34}, {43, 42}, - {43, 44}, {44, 43}, {44, 45}, {45, 44}, {45, 46}, {45, 54}, - {46, 45}, {46, 47}, {47, 35}, {47, 46}, {47, 48}, {48, 47}, - {48, 49}, {49, 48}, {49, 50}, {49, 55}, {50, 49}, {50, 51}, - {51, 36}, {51, 50}, {52, 37}, {52, 56}, {53, 41}, {53, 60}, - {54, 45}, {54, 64}, {55, 49}, {55, 68}, {56, 52}, {56, 57}, - {57, 56}, {57, 58}, {58, 57}, {58, 59}, {58, 71}, {59, 58}, - {59, 60}, {60, 53}, {60, 59}, {60, 61}, {61, 60}, {61, 62}, - {62, 61}, {62, 63}, {62, 72}, {63, 62}, {63, 64}, {64, 54}, - {64, 63}, {64, 65}, {65, 64}, {65, 66}, {66, 65}, {66, 67}, - {66, 73}, {67, 66}, {67, 68}, {68, 55}, {68, 67}, {68, 69}, - {69, 68}, {69, 70}, {70, 69}, {70, 74}, {71, 58}, {71, 77}, - {72, 62}, {72, 81}, {73, 66}, {73, 85}, {74, 70}, {74, 89}, - {75, 76}, {75, 90}, {76, 75}, {76, 77}, {77, 71}, {77, 76}, - {77, 78}, {78, 77}, {78, 79}, {79, 78}, {79, 80}, {79, 91}, - {80, 79}, {80, 81}, {81, 72}, {81, 80}, {81, 82}, {82, 81}, - {82, 83}, {83, 82}, {83, 84}, {83, 92}, {84, 83}, {84, 85}, - {85, 73}, {85, 84}, {85, 86}, {86, 85}, {86, 87}, {87, 86}, - {87, 88}, {87, 93}, {88, 87}, {88, 89}, {89, 74}, {89, 88}, - {90, 75}, {90, 94}, {91, 79}, {91, 98}, {92, 83}, {92, 102}, - {93, 87}, {93, 106}, {94, 90}, {94, 95}, {95, 94}, {95, 96}, - {96, 95}, {96, 97}, {96, 109}, {97, 96}, {97, 98}, {98, 91}, - {98, 97}, {98, 99}, {99, 98}, {99, 100}, {100, 99}, {100, 101}, - {100, 110}, {101, 100}, {101, 102}, {102, 92}, {102, 101}, {102, 103}, - {103, 102}, {103, 104}, {104, 103}, {104, 105}, {104, 111}, {105, 104}, - {105, 106}, {106, 93}, {106, 105}, {106, 107}, {107, 106}, {107, 108}, - {108, 107}, {108, 112}, {109, 96}, {110, 100}, {110, 118}, {111, 104}, - {111, 122}, {112, 108}, {112, 126}, {113, 114}, {114, 113}, {114, 115}, - {115, 114}, {115, 116}, {116, 115}, {116, 117}, {117, 116}, {117, 118}, - {118, 110}, {118, 117}, {118, 119}, {119, 118}, {119, 120}, {120, 119}, - {120, 121}, {121, 120}, {121, 122}, {122, 111}, {122, 121}, {122, 123}, - {123, 122}, {123, 124}, {124, 123}, {124, 125}, {125, 124}, {125, 126}, - {126, 112}, {126, 125}}; - - return std::make_unique("IBM-Falcon", 127, couplingMap); - } } throw std::invalid_argument("Unsupported architecture."); diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp index 78daf90f08..a57d2fdda0 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/PlacementPass.cpp @@ -427,7 +427,7 @@ struct PlacementPassSC final : impl::PlacementPassSCBase { using PlacementPassSCBase::PlacementPassSCBase; void runOnOperation() override { - const auto arch = getArchitecture(ArchitectureName::IBMFalcon); + const auto arch = getArchitecture(ArchitectureName::MQTTest); const auto placer = getPlacer(*arch); if (PlacementContext ctx(*arch, *placer); diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index 88e7d42f6d..45173314b0 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -503,7 +503,7 @@ struct RoutingPassSC final : impl::RoutingPassSCBase { private: [[nodiscard]] Mapper getMapper() { /// TODO: Configurable Architecture. - auto arch = getArchitecture(ArchitectureName::IBMFalcon); + auto arch = getArchitecture(ArchitectureName::MQTTest); switch (static_cast(method)) { case RoutingMethod::Naive: diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp index 17bd4c3672..a692719ede 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingVerificationPass.cpp @@ -220,7 +220,7 @@ WalkResult handleMeasure(MeasureOp op, VerificationContext& ctx) { struct RoutingVerificationPassSC final : impl::RoutingVerificationSCPassBase { void runOnOperation() override { - const auto arch = getArchitecture(ArchitectureName::IBMFalcon); + const auto arch = getArchitecture(ArchitectureName::MQTTest); VerificationContext ctx(*arch); const auto res = From 33941aae3975d7f63761c9f1b98ffb21d15b4d27 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Wed, 29 Oct 2025 18:59:15 +0100 Subject: [PATCH 18/27] Fix compile error on linux and windows --- .../mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index 63b9efc830..20bd459287 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -267,7 +267,7 @@ struct ParallelOpScheduler final : SchedulerBase { heads = {out0, out1}; } - return heads; + return {heads[0], heads[1]}; } std::size_t nlayers_; From bcacb8429a8a79f1a310679efb6217b7142aa43f Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 07:51:22 +0100 Subject: [PATCH 19/27] Add ValuePair to Common.h --- .../Dialect/MQTOpt/Transforms/Transpilation/Common.h | 9 +++++++-- .../Dialect/MQTOpt/Transforms/Transpilation/Common.cpp | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h index ce568c0746..4a9dc7ab6a 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Common.h @@ -35,6 +35,11 @@ constexpr std::size_t IF_PARENT_DEPTH = 2UL; */ using QubitIndex = uint32_t; +/** + * @brief A pair of SSA Values. + */ +using ValuePair = std::pair; + /** * @brief Represents a pair of qubit indices. */ @@ -58,14 +63,14 @@ using QubitIndexPair = std::pair; * @param op A two-qubit unitary. * @return Pair of SSA values consisting of the first and second in-qubits. */ -[[nodiscard]] std::pair getIns(UnitaryInterface op); +[[nodiscard]] ValuePair getIns(UnitaryInterface op); /** * @brief Return output qubit pair for a two-qubit unitary. * @param op A two-qubit unitary. * @return Pair of SSA values consisting of the first and second out-qubits. */ -[[nodiscard]] std::pair getOuts(UnitaryInterface op); +[[nodiscard]] ValuePair getOuts(UnitaryInterface op); /** * @brief Return the first user of a value in a given region. diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp index 8ac72423ac..36174506af 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp @@ -52,7 +52,7 @@ bool isTwoQubitGate(UnitaryInterface op) { op.getNegCtrlInQubits().size()) == 2; } -[[nodiscard]] std::pair getIns(UnitaryInterface op) { +[[nodiscard]] ValuePair getIns(UnitaryInterface op) { assert(isTwoQubitGate(op)); const auto target = op.getInQubits(); @@ -68,7 +68,7 @@ bool isTwoQubitGate(UnitaryInterface op) { : std::pair{target[0], op.getNegCtrlInQubits()[0]}; } -[[nodiscard]] std::pair getOuts(UnitaryInterface op) { +[[nodiscard]] ValuePair getOuts(UnitaryInterface op) { assert(isTwoQubitGate(op)); const auto target = op.getOutQubits(); const auto targetSize = target.size(); From 8dd2a864e67d86760b87f6c9c943b8d40f877c58 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 09:04:19 +0100 Subject: [PATCH 20/27] Fix scheduler problems --- .../Transforms/Transpilation/Scheduler.h | 118 +++++++++--------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index 20bd459287..a4f9826d1c 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -102,6 +102,7 @@ struct ParallelOpScheduler final : SchedulerBase { const auto& [qNext, gate] = opt.value(); if (q != qNext) { + LLVM_DEBUG(llvm::dbgs() << "remap!\n"); layout.remapQubitValue(q, qNext); } @@ -120,24 +121,63 @@ struct ParallelOpScheduler final : SchedulerBase { layers.emplace_back(); layers.back().reserve(readyTwoQubit.size()); + /// At this point all qubit values are remapped to the input of a + /// two-qubit gate: "value.user == two-qubit-gate". + /// + /// We release the ready two-qubit gates by forwarding their inputs + /// to their outputs. Then, we advance to the end of its two-qubit block. + /// Intuitively, whenever a gate in readyTwoQubit is routed, all one and + /// two-qubit gates acting on the same qubits are executable as well. + for (const auto& op : readyTwoQubit) { - const auto [in0, in1] = getIns(op); + /// Release. + const ValuePair ins = getIns(op); + const ValuePair outs = getOuts(op); + layers.back().emplace_back(layout.lookupProgramIndex(ins.first), + layout.lookupProgramIndex(ins.second)); + layout.remapQubitValue(ins.first, outs.first); + layout.remapQubitValue(ins.second, outs.second); + + /// Advance two-qubit block. + std::array gates; + std::array heads{outs.first, outs.second}; + + while (true) { + bool stop = false; + for (const auto [i, q] : llvm::enumerate(heads)) { + const auto opt = advanceToTwoQubitGate(q, region, layout); + if (!opt) { + heads[i] = nullptr; + stop = true; + break; + } - layers.back().emplace_back(layout.lookupProgramIndex(in0), - layout.lookupProgramIndex(in1)); + const auto& [qNext, gate] = opt.value(); + + if (q != qNext) { + layout.remapQubitValue(q, qNext); + } - const auto [out0, out1] = - advanceTwoQubitBlock(getOuts(op), layout, region); + heads[i] = qNext; + gates[i] = gate; + } - layout.remapQubitValue(in0, out0); - layout.remapQubitValue(in1, out1); + if (stop || gates[0] != gates[1]) { + break; + } - if (!out0.use_empty()) { - nextWl.push_back(out0); + const ValuePair ins = getIns(gates[0]); + const ValuePair outs = getOuts(gates[0]); + layout.remapQubitValue(ins.first, outs.first); + layout.remapQubitValue(ins.second, outs.second); + heads = {outs.first, outs.second}; } - if (!out1.use_empty()) { - nextWl.push_back(out1); + /// Initialize next worklist. + for (const auto q : heads) { + if (q != nullptr && !q.use_empty()) { + nextWl.push_back(q); + } } } @@ -161,30 +201,25 @@ struct ParallelOpScheduler final : SchedulerBase { } private: - using ValuePair = std::pair; - /** * @returns Next two-qubit gate on qubit wire, or std::nullopt if none exists. */ static std::optional> advanceToTwoQubitGate(const Value q, Region* region, const Layout& layout) { Value head = q; - UnitaryInterface twoQubitOp = nullptr; while (true) { if (head.use_empty()) { // No two-qubit gate found. return std::nullopt; } - if (twoQubitOp != nullptr) { // Two-qubit gate found. - return std::make_pair(head, twoQubitOp); - } - Operation* user = getUserInRegion(head, region); if (user == nullptr) { // No two-qubit gate found. return std::nullopt; } bool endOfRegion = false; + std::optional twoQubitOp; + TypeSwitch(user) /// MQT /// BarrierOp is a UnitaryInterface, however, requires special care. @@ -201,17 +236,15 @@ struct ParallelOpScheduler final : SchedulerBase { .Case([&](UnitaryInterface op) { if (isTwoQubitGate(op)) { twoQubitOp = op; - return; + return; // Found a two-qubit gate, stop advancing head. } - + // Otherwise, advance head. head = op.getOutQubits().front(); }) .Case([&](ResetOp op) { head = op.getOutQubit(); }) .Case([&](MeasureOp op) { head = op.getOutQubit(); }) /// SCF - /// The scf functions assume that the first n results are the - /// hardw. qubits. We can use 'q' to get the hardware index - /// because the def-use chain keeps the index constant. + /// The scf funcs assume that the first n results are the hw qubits. .Case([&](scf::ForOp op) { head = op->getResult(layout.lookupHardwareIndex(q)); }) @@ -227,6 +260,10 @@ struct ParallelOpScheduler final : SchedulerBase { llvm_unreachable("unknown operation in def-use chain"); }); + if (twoQubitOp) { // Two-qubit gate found. + return std::make_pair(head, *twoQubitOp); + } + if (endOfRegion) { return std::nullopt; } @@ -235,41 +272,6 @@ struct ParallelOpScheduler final : SchedulerBase { return std::nullopt; } - /** - * @returns Pair of Values after two-qubit block. - */ - static ValuePair advanceTwoQubitBlock(const ValuePair outs, Layout& layout, - Region* region) { - std::array heads{outs.first, outs.second}; - std::array gates{}; - - while (true) { - /// Advance both input qubits to a two-qubit gate. - /// Exit: If none is found. - /// If the two-qubit gates are not the same. - /// Otherwise, advance two-qubit gate and repeat process. - bool exit = false; - for (const auto [i, q] : llvm::enumerate(heads)) { - const auto opt = advanceToTwoQubitGate(q, region, layout); - if (!opt) { - exit = true; - break; - } - heads[i] = opt->first; - gates[i] = opt->second; - } - - if (exit || gates[0] != gates[1]) { - break; - } - - const auto [out0, out1] = getOuts(gates[0]); - heads = {out0, out1}; - } - - return {heads[0], heads[1]}; - } - std::size_t nlayers_; }; } // namespace mqt::ir::opt From 0d5f5fd316e8fefce2c8dab533dfc71d14a141c9 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 14:40:32 +0100 Subject: [PATCH 21/27] Fix SWAP bug in handleUnitary --- .../Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp index 45173314b0..a5d3ac7167 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/sc/RoutingPass.cpp @@ -377,6 +377,9 @@ WalkResult handleUnitary(UnitaryInterface op, Mapper& mapper, if (isa(op)) { mapper.stack().top().swap(execIn0, execIn1); + mapper.historyStack().top().push_back( + {mapper.stack().top().lookupHardwareIndex(execIn0), + mapper.stack().top().lookupHardwareIndex(execIn1)}); } mapper.stack().top().remapQubitValue(execIn0, execOut0); From b83571cf97373dd81a12fcb2172e8b0ba0bb2336 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 14:40:47 +0100 Subject: [PATCH 22/27] Remove left-over debug print --- .../mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h index a4f9826d1c..e64b729d9b 100644 --- a/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h +++ b/mlir/include/mlir/Dialect/MQTOpt/Transforms/Transpilation/Scheduler.h @@ -102,7 +102,6 @@ struct ParallelOpScheduler final : SchedulerBase { const auto& [qNext, gate] = opt.value(); if (q != qNext) { - LLVM_DEBUG(llvm::dbgs() << "remap!\n"); layout.remapQubitValue(q, qNext); } From 0cfdb7eb0e8aec44a69640d99f4cd908519e2fe5 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 14:41:09 +0100 Subject: [PATCH 23/27] Update tests for coverage --- mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp | 1 - .../MQTOpt/Transforms/Transpilation/astar-routing.mlir | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp index 36174506af..c0432a7639 100644 --- a/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp +++ b/mlir/lib/Dialect/MQTOpt/Transforms/Transpilation/Common.cpp @@ -54,7 +54,6 @@ bool isTwoQubitGate(UnitaryInterface op) { [[nodiscard]] ValuePair getIns(UnitaryInterface op) { assert(isTwoQubitGate(op)); - const auto target = op.getInQubits(); const auto targetSize = target.size(); diff --git a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir index 02e12a7602..d82e53b418 100644 --- a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir +++ b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir @@ -345,12 +345,12 @@ module { %q0_3_branch, %q1_2_branch = scf.if %m -> (!mqtopt.Qubit, !mqtopt.Qubit) { %q1_1_branch = mqtopt.x() %q1_0_branch : !mqtopt.Qubit - %q1_2_branch, %q0_3_branch = mqtopt.x() %q1_1_branch ctrl %q0_2_branch : !mqtopt.Qubit ctrl !mqtopt.Qubit + %q1_2_branch, %q0_3_branch = mqtopt.x() %q1_1_branch nctrl %q0_2_branch : !mqtopt.Qubit nctrl !mqtopt.Qubit scf.yield %q0_3_branch, %q1_2_branch : !mqtopt.Qubit, !mqtopt.Qubit } else { %q1_1_branch = mqtopt.i() %q1_0_branch : !mqtopt.Qubit - %q1_2_branch, %q0_3_branch = mqtopt.x() %q1_1_branch ctrl %q0_2_branch : !mqtopt.Qubit ctrl !mqtopt.Qubit + %q0_3_branch, %q1_2_branch = mqtopt.swap() %q1_1_branch, %q0_2_branch : !mqtopt.Qubit, !mqtopt.Qubit scf.yield %q0_3_branch, %q1_2_branch : !mqtopt.Qubit, !mqtopt.Qubit } From ab98a40a1b984bf1950c565072abee9785953b7a Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 16:00:51 +0100 Subject: [PATCH 24/27] Add grover_5 test --- .../Transforms/Transpilation/grover_5.mlir | 684 ++++++++++++++++++ 1 file changed, 684 insertions(+) create mode 100644 mlir/test/Dialect/MQTOpt/Transforms/Transpilation/grover_5.mlir diff --git a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/grover_5.mlir b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/grover_5.mlir new file mode 100644 index 0000000000..c13da9e03d --- /dev/null +++ b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/grover_5.mlir @@ -0,0 +1,684 @@ +// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM +// Copyright (c) 2025 Munich Quantum Software Company GmbH +// All rights reserved. +// +// SPDX-License-Identifier: MIT +// +// Licensed under the MIT License + +// Instead of applying checks, the routing verifier pass ensures the validity of this program. + +// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=identity}, route-sc{method=astar},verify-routing-sc)" -verify-diagnostics | FileCheck %s + +module { + // CHECK-LABEL: func.func @main + func.func @main() attributes {passthrough = ["entry_point"]} { + %0 = mqtopt.allocQubit + %1 = mqtopt.allocQubit + %2 = mqtopt.allocQubit + %3 = mqtopt.allocQubit + %4 = mqtopt.allocQubit + + %alloca = memref.alloca() : memref<5xi1> + %out_qubits = mqtopt.rz(static [1.570796e+00]) %0 : !mqtopt.Qubit + %out_qubits_2 = mqtopt.sx() %out_qubits : !mqtopt.Qubit + %out_qubits_3 = mqtopt.rz(static [1.570796e+00]) %out_qubits_2 : !mqtopt.Qubit + %out_qubits_4 = mqtopt.rz(static [1.570796e+00]) %1 : !mqtopt.Qubit + %out_qubits_5 = mqtopt.sx() %out_qubits_4 : !mqtopt.Qubit + %out_qubits_6 = mqtopt.rz(static [1.570796e+00]) %out_qubits_5 : !mqtopt.Qubit + %out_qubits_7 = mqtopt.rz(static [1.570796e+00]) %2 : !mqtopt.Qubit + %out_qubits_8 = mqtopt.sx() %out_qubits_7 : !mqtopt.Qubit + %out_qubits_9 = mqtopt.rz(static [1.570796e+00]) %out_qubits_8 : !mqtopt.Qubit + %out_qubits_10 = mqtopt.rz(static [1.570796e+00]) %3 : !mqtopt.Qubit + %out_qubits_11 = mqtopt.sx() %out_qubits_10 : !mqtopt.Qubit + %out_qubits_12 = mqtopt.rz(static [1.570796e+00]) %out_qubits_11 : !mqtopt.Qubit + %out_qubits_13 = mqtopt.x() %4 : !mqtopt.Qubit + %out_qubits_14 = mqtopt.rz(static [1.570796e+00]) %out_qubits_13 : !mqtopt.Qubit + %out_qubits_15 = mqtopt.sx() %out_qubits_14 : !mqtopt.Qubit + %out_qubits_16 = mqtopt.rz(static [1.570796e+00]) %out_qubits_15 : !mqtopt.Qubit + %out_qubits_17, %pos_ctrl_out_qubits = mqtopt.x() %out_qubits_16 ctrl %out_qubits_6 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_18 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_17 : !mqtopt.Qubit + %out_qubits_19, %pos_ctrl_out_qubits_20 = mqtopt.x() %out_qubits_18 ctrl %out_qubits_3 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_21 = mqtopt.rz(static [7.853982e-01]) %out_qubits_19 : !mqtopt.Qubit + %out_qubits_22, %pos_ctrl_out_qubits_23 = mqtopt.x() %out_qubits_21 ctrl %pos_ctrl_out_qubits : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_24 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_23 : !mqtopt.Qubit + %out_qubits_25 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_22 : !mqtopt.Qubit + %out_qubits_26, %pos_ctrl_out_qubits_27 = mqtopt.x() %out_qubits_25 ctrl %pos_ctrl_out_qubits_20 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_28, %pos_ctrl_out_qubits_29 = mqtopt.x() %out_qubits_24 ctrl %pos_ctrl_out_qubits_27 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_30 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_29 : !mqtopt.Qubit + %out_qubits_31 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_28 : !mqtopt.Qubit + %out_qubits_32, %pos_ctrl_out_qubits_33 = mqtopt.x() %out_qubits_31 ctrl %out_qubits_30 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_34 = mqtopt.rz(static [7.853982e-01]) %out_qubits_26 : !mqtopt.Qubit + %out_qubits_35 = mqtopt.rz(static [1.570796e+00]) %out_qubits_34 : !mqtopt.Qubit + %out_qubits_36 = mqtopt.sx() %out_qubits_35 : !mqtopt.Qubit + %out_qubits_37 = mqtopt.rz(static [1.570796e+00]) %out_qubits_36 : !mqtopt.Qubit + %out_qubits_38 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_37 : !mqtopt.Qubit + %out_qubits_39 = mqtopt.rz(static [1.570796e+00]) %out_qubits_38 : !mqtopt.Qubit + %out_qubits_40 = mqtopt.sx() %out_qubits_39 : !mqtopt.Qubit + %out_qubits_41 = mqtopt.rz(static [1.570796e+00]) %out_qubits_40 : !mqtopt.Qubit + %out_qubits_42, %pos_ctrl_out_qubits_43 = mqtopt.x() %out_qubits_41 ctrl %out_qubits_12 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_44 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_42 : !mqtopt.Qubit + %out_qubits_45, %pos_ctrl_out_qubits_46 = mqtopt.x() %out_qubits_44 ctrl %out_qubits_9 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_47 = mqtopt.rz(static [7.853982e-01]) %out_qubits_45 : !mqtopt.Qubit + %out_qubits_48, %pos_ctrl_out_qubits_49 = mqtopt.x() %out_qubits_47 ctrl %pos_ctrl_out_qubits_43 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_50 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_49 : !mqtopt.Qubit + %out_qubits_51 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_48 : !mqtopt.Qubit + %out_qubits_52, %pos_ctrl_out_qubits_53 = mqtopt.x() %out_qubits_51 ctrl %pos_ctrl_out_qubits_46 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_54, %pos_ctrl_out_qubits_55 = mqtopt.x() %out_qubits_50 ctrl %pos_ctrl_out_qubits_53 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_56 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_55 : !mqtopt.Qubit + %out_qubits_57 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_54 : !mqtopt.Qubit + %out_qubits_58, %pos_ctrl_out_qubits_59 = mqtopt.x() %out_qubits_57 ctrl %out_qubits_56 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_60 = mqtopt.rz(static [7.853982e-01]) %out_qubits_52 : !mqtopt.Qubit + %out_qubits_61 = mqtopt.rz(static [1.570796e+00]) %out_qubits_60 : !mqtopt.Qubit + %out_qubits_62 = mqtopt.sx() %out_qubits_61 : !mqtopt.Qubit + %out_qubits_63 = mqtopt.rz(static [1.570796e+00]) %out_qubits_62 : !mqtopt.Qubit + %out_qubits_64 = mqtopt.rz(static [7.853982e-01]) %out_qubits_63 : !mqtopt.Qubit + %out_qubits_65 = mqtopt.rz(static [1.570796e+00]) %out_qubits_64 : !mqtopt.Qubit + %out_qubits_66 = mqtopt.sx() %out_qubits_65 : !mqtopt.Qubit + %out_qubits_67 = mqtopt.rz(static [1.570796e+00]) %out_qubits_66 : !mqtopt.Qubit + %out_qubits_68, %pos_ctrl_out_qubits_69 = mqtopt.x() %out_qubits_67 ctrl %out_qubits_32 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_70 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_68 : !mqtopt.Qubit + %out_qubits_71, %pos_ctrl_out_qubits_72 = mqtopt.x() %out_qubits_70 ctrl %pos_ctrl_out_qubits_33 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_73 = mqtopt.rz(static [7.853982e-01]) %out_qubits_71 : !mqtopt.Qubit + %out_qubits_74, %pos_ctrl_out_qubits_75 = mqtopt.x() %out_qubits_73 ctrl %pos_ctrl_out_qubits_69 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_76 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_75 : !mqtopt.Qubit + %out_qubits_77 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_74 : !mqtopt.Qubit + %out_qubits_78, %pos_ctrl_out_qubits_79 = mqtopt.x() %out_qubits_77 ctrl %pos_ctrl_out_qubits_72 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_80, %pos_ctrl_out_qubits_81 = mqtopt.x() %out_qubits_76 ctrl %pos_ctrl_out_qubits_79 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_82 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_81 : !mqtopt.Qubit + %out_qubits_83 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_80 : !mqtopt.Qubit + %out_qubits_84, %pos_ctrl_out_qubits_85 = mqtopt.x() %out_qubits_83 ctrl %out_qubits_82 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_86 = mqtopt.rz(static [7.853982e-01]) %out_qubits_78 : !mqtopt.Qubit + %out_qubits_87 = mqtopt.rz(static [1.570796e+00]) %out_qubits_86 : !mqtopt.Qubit + %out_qubits_88 = mqtopt.sx() %out_qubits_87 : !mqtopt.Qubit + %out_qubits_89 = mqtopt.rz(static [1.570796e+00]) %out_qubits_88 : !mqtopt.Qubit + %out_qubits_90 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_89 : !mqtopt.Qubit + %out_qubits_91 = mqtopt.rz(static [1.570796e+00]) %out_qubits_90 : !mqtopt.Qubit + %out_qubits_92 = mqtopt.sx() %out_qubits_91 : !mqtopt.Qubit + %out_qubits_93 = mqtopt.rz(static [1.570796e+00]) %out_qubits_92 : !mqtopt.Qubit + %out_qubits_94, %pos_ctrl_out_qubits_95 = mqtopt.x() %out_qubits_93 ctrl %out_qubits_58 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_96 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_94 : !mqtopt.Qubit + %out_qubits_97, %pos_ctrl_out_qubits_98 = mqtopt.x() %out_qubits_96 ctrl %pos_ctrl_out_qubits_59 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_99 = mqtopt.rz(static [7.853982e-01]) %out_qubits_97 : !mqtopt.Qubit + %out_qubits_100, %pos_ctrl_out_qubits_101 = mqtopt.x() %out_qubits_99 ctrl %pos_ctrl_out_qubits_95 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_102 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_101 : !mqtopt.Qubit + %out_qubits_103 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_100 : !mqtopt.Qubit + %out_qubits_104, %pos_ctrl_out_qubits_105 = mqtopt.x() %out_qubits_103 ctrl %pos_ctrl_out_qubits_98 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_106, %pos_ctrl_out_qubits_107 = mqtopt.x() %out_qubits_102 ctrl %pos_ctrl_out_qubits_105 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_108 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_107 : !mqtopt.Qubit + %out_qubits_109 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_106 : !mqtopt.Qubit + %out_qubits_110, %pos_ctrl_out_qubits_111 = mqtopt.x() %out_qubits_109 ctrl %out_qubits_108 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_112 = mqtopt.rz(static [1.570796e+00]) %out_qubits_110 : !mqtopt.Qubit + %out_qubits_113 = mqtopt.sx() %out_qubits_112 : !mqtopt.Qubit + %out_qubits_114 = mqtopt.rz(static [1.570796e+00]) %out_qubits_113 : !mqtopt.Qubit + %out_qubits_115, %pos_ctrl_out_qubits_116 = mqtopt.x() %out_qubits_114 ctrl %out_qubits_84 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_117 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_115 : !mqtopt.Qubit + %out_qubits_118, %pos_ctrl_out_qubits_119 = mqtopt.x() %out_qubits_117 ctrl %pos_ctrl_out_qubits_85 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_120 = mqtopt.rz(static [7.853982e-01]) %out_qubits_118 : !mqtopt.Qubit + %out_qubits_121, %pos_ctrl_out_qubits_122 = mqtopt.x() %out_qubits_120 ctrl %pos_ctrl_out_qubits_116 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_123 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_122 : !mqtopt.Qubit + %out_qubits_124 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_121 : !mqtopt.Qubit + %out_qubits_125, %pos_ctrl_out_qubits_126 = mqtopt.x() %out_qubits_124 ctrl %pos_ctrl_out_qubits_119 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_127, %pos_ctrl_out_qubits_128 = mqtopt.x() %out_qubits_123 ctrl %pos_ctrl_out_qubits_126 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_129 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_128 : !mqtopt.Qubit + %out_qubits_130 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_127 : !mqtopt.Qubit + %out_qubits_131, %pos_ctrl_out_qubits_132 = mqtopt.x() %out_qubits_130 ctrl %out_qubits_129 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_133 = mqtopt.rz(static [7.853982e-01]) %out_qubits_125 : !mqtopt.Qubit + %out_qubits_134 = mqtopt.rz(static [1.570796e+00]) %out_qubits_133 : !mqtopt.Qubit + %out_qubits_135 = mqtopt.sx() %out_qubits_134 : !mqtopt.Qubit + %out_qubits_136 = mqtopt.rz(static [1.570796e+00]) %out_qubits_135 : !mqtopt.Qubit + %out_qubits_137 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_136 : !mqtopt.Qubit + %out_qubits_138, %pos_ctrl_out_qubits_139 = mqtopt.x() %out_qubits_137 ctrl %pos_ctrl_out_qubits_111 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_140 = mqtopt.rz(static [3.926991e-01]) %out_qubits_138 : !mqtopt.Qubit + %out_qubits_141 = mqtopt.rz(static [1.570796e+00]) %out_qubits_140 : !mqtopt.Qubit + %out_qubits_142 = mqtopt.sx() %out_qubits_141 : !mqtopt.Qubit + %out_qubits_143 = mqtopt.rz(static [1.570796e+00]) %out_qubits_142 : !mqtopt.Qubit + %out_qubits_144, %pos_ctrl_out_qubits_145 = mqtopt.x() %out_qubits_143 ctrl %out_qubits_131 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_146 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_144 : !mqtopt.Qubit + %out_qubits_147, %pos_ctrl_out_qubits_148 = mqtopt.x() %out_qubits_146 ctrl %pos_ctrl_out_qubits_132 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_149 = mqtopt.rz(static [7.853982e-01]) %out_qubits_147 : !mqtopt.Qubit + %out_qubits_150, %pos_ctrl_out_qubits_151 = mqtopt.x() %out_qubits_149 ctrl %pos_ctrl_out_qubits_145 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_152 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_151 : !mqtopt.Qubit + %out_qubits_153 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_150 : !mqtopt.Qubit + %out_qubits_154, %pos_ctrl_out_qubits_155 = mqtopt.x() %out_qubits_153 ctrl %pos_ctrl_out_qubits_148 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_156, %pos_ctrl_out_qubits_157 = mqtopt.x() %out_qubits_152 ctrl %pos_ctrl_out_qubits_155 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_158 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_157 : !mqtopt.Qubit + %out_qubits_159 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_156 : !mqtopt.Qubit + %out_qubits_160, %pos_ctrl_out_qubits_161 = mqtopt.x() %out_qubits_159 ctrl %out_qubits_158 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_162 = mqtopt.rz(static [7.853982e-01]) %out_qubits_154 : !mqtopt.Qubit + %out_qubits_163 = mqtopt.rz(static [1.570796e+00]) %out_qubits_162 : !mqtopt.Qubit + %out_qubits_164 = mqtopt.sx() %out_qubits_163 : !mqtopt.Qubit + %out_qubits_165 = mqtopt.rz(static [1.570796e+00]) %out_qubits_164 : !mqtopt.Qubit + %out_qubits_166 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_165 : !mqtopt.Qubit + %out_qubits_167, %pos_ctrl_out_qubits_168 = mqtopt.x() %out_qubits_166 ctrl %pos_ctrl_out_qubits_139 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_169, %pos_ctrl_out_qubits_170 = mqtopt.x() %pos_ctrl_out_qubits_168 ctrl %pos_ctrl_out_qubits_161 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_171 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_169 : !mqtopt.Qubit + %out_qubits_172, %pos_ctrl_out_qubits_173 = mqtopt.x() %out_qubits_171 ctrl %out_qubits_160 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_174 = mqtopt.rz(static [1.963495e-01]) %out_qubits_172 : !mqtopt.Qubit + %out_qubits_175, %pos_ctrl_out_qubits_176 = mqtopt.x() %out_qubits_174 ctrl %pos_ctrl_out_qubits_170 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_177 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_175 : !mqtopt.Qubit + %out_qubits_178, %pos_ctrl_out_qubits_179 = mqtopt.x() %out_qubits_177 ctrl %pos_ctrl_out_qubits_173 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_180 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_179 : !mqtopt.Qubit + %out_qubits_181, %pos_ctrl_out_qubits_182 = mqtopt.x() %out_qubits_180 ctrl %pos_ctrl_out_qubits_176 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_183 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_181 : !mqtopt.Qubit + %out_qubits_184, %pos_ctrl_out_qubits_185 = mqtopt.x() %out_qubits_183 ctrl %pos_ctrl_out_qubits_182 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_186 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_185 : !mqtopt.Qubit + %out_qubits_187 = mqtopt.rz(static [1.570796e+00]) %out_qubits_186 : !mqtopt.Qubit + %out_qubits_188 = mqtopt.sx() %out_qubits_187 : !mqtopt.Qubit + %out_qubits_189 = mqtopt.rz(static [1.570796e+00]) %out_qubits_188 : !mqtopt.Qubit + %out_qubits_190 = mqtopt.x() %out_qubits_189 : !mqtopt.Qubit + %out_qubits_191 = mqtopt.rz(static [3.926991e-01]) %out_qubits_190 : !mqtopt.Qubit + %out_qubits_192 = mqtopt.rz(static [1.570796e+00]) %out_qubits_184 : !mqtopt.Qubit + %out_qubits_193 = mqtopt.sx() %out_qubits_192 : !mqtopt.Qubit + %out_qubits_194 = mqtopt.rz(static [1.570796e+00]) %out_qubits_193 : !mqtopt.Qubit + %out_qubits_195 = mqtopt.x() %out_qubits_194 : !mqtopt.Qubit + %out_qubits_196 = mqtopt.rz(static [3.926991e-01]) %out_qubits_195 : !mqtopt.Qubit + %out_qubits_197, %pos_ctrl_out_qubits_198 = mqtopt.x() %out_qubits_196 ctrl %out_qubits_191 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_199 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_197 : !mqtopt.Qubit + %out_qubits_200, %pos_ctrl_out_qubits_201 = mqtopt.x() %out_qubits_199 ctrl %pos_ctrl_out_qubits_198 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_202 = mqtopt.rz(static [1.963495e-01]) %out_qubits_178 : !mqtopt.Qubit + %out_qubits_203 = mqtopt.rz(static [1.570796e+00]) %out_qubits_202 : !mqtopt.Qubit + %out_qubits_204 = mqtopt.sx() %out_qubits_203 : !mqtopt.Qubit + %out_qubits_205 = mqtopt.rz(static [1.570796e+00]) %out_qubits_204 : !mqtopt.Qubit + %out_qubits_206 = mqtopt.x() %out_qubits_205 : !mqtopt.Qubit + %out_qubits_207 = mqtopt.rz(static [3.926991e-01]) %out_qubits_206 : !mqtopt.Qubit + %out_qubits_208, %pos_ctrl_out_qubits_209 = mqtopt.x() %out_qubits_207 ctrl %out_qubits_200 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_210 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_208 : !mqtopt.Qubit + %out_qubits_211, %pos_ctrl_out_qubits_212 = mqtopt.x() %out_qubits_210 ctrl %pos_ctrl_out_qubits_201 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_213 = mqtopt.rz(static [3.926991e-01]) %out_qubits_211 : !mqtopt.Qubit + %out_qubits_214, %pos_ctrl_out_qubits_215 = mqtopt.x() %out_qubits_213 ctrl %pos_ctrl_out_qubits_209 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_216 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_214 : !mqtopt.Qubit + %out_qubits_217, %pos_ctrl_out_qubits_218 = mqtopt.x() %out_qubits_216 ctrl %pos_ctrl_out_qubits_212 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_219 = mqtopt.rz(static [3.926991e-01]) %out_qubits_167 : !mqtopt.Qubit + %out_qubits_220 = mqtopt.rz(static [1.570796e+00]) %out_qubits_219 : !mqtopt.Qubit + %out_qubits_221 = mqtopt.sx() %out_qubits_220 : !mqtopt.Qubit + %out_qubits_222 = mqtopt.rz(static [1.570796e+00]) %out_qubits_221 : !mqtopt.Qubit + %out_qubits_223 = mqtopt.x() %out_qubits_222 : !mqtopt.Qubit + %out_qubits_224 = mqtopt.rz(static [1.570796e+00]) %out_qubits_223 : !mqtopt.Qubit + %out_qubits_225 = mqtopt.sx() %out_qubits_224 : !mqtopt.Qubit + %out_qubits_226 = mqtopt.rz(static [1.570796e+00]) %out_qubits_225 : !mqtopt.Qubit + %out_qubits_227 = mqtopt.rz(static [1.570796e+00]) %out_qubits_226 : !mqtopt.Qubit + %out_qubits_228 = mqtopt.sx() %out_qubits_227 : !mqtopt.Qubit + %out_qubits_229 = mqtopt.rz(static [1.570796e+00]) %out_qubits_228 : !mqtopt.Qubit + %out_qubits_230 = mqtopt.rz(static [3.926991e-01]) %out_qubits_229 : !mqtopt.Qubit + %out_qubits_231, %pos_ctrl_out_qubits_232 = mqtopt.x() %out_qubits_230 ctrl %out_qubits_217 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_233 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_231 : !mqtopt.Qubit + %out_qubits_234, %pos_ctrl_out_qubits_235 = mqtopt.x() %out_qubits_233 ctrl %pos_ctrl_out_qubits_215 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_236 = mqtopt.rz(static [3.926991e-01]) %out_qubits_234 : !mqtopt.Qubit + %out_qubits_237, %pos_ctrl_out_qubits_238 = mqtopt.x() %out_qubits_236 ctrl %pos_ctrl_out_qubits_232 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_239 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_237 : !mqtopt.Qubit + %out_qubits_240, %pos_ctrl_out_qubits_241 = mqtopt.x() %out_qubits_239 ctrl %pos_ctrl_out_qubits_218 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_242 = mqtopt.rz(static [3.926991e-01]) %out_qubits_240 : !mqtopt.Qubit + %out_qubits_243, %pos_ctrl_out_qubits_244 = mqtopt.x() %out_qubits_242 ctrl %pos_ctrl_out_qubits_238 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_245 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_243 : !mqtopt.Qubit + %out_qubits_246, %pos_ctrl_out_qubits_247 = mqtopt.x() %out_qubits_245 ctrl %pos_ctrl_out_qubits_235 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_248 = mqtopt.x() %pos_ctrl_out_qubits_247 : !mqtopt.Qubit + %out_qubits_249 = mqtopt.rz(static [1.570796e+00]) %out_qubits_248 : !mqtopt.Qubit + %out_qubits_250 = mqtopt.sx() %out_qubits_249 : !mqtopt.Qubit + %out_qubits_251 = mqtopt.rz(static [1.570796e+00]) %out_qubits_250 : !mqtopt.Qubit + %out_qubits_252 = mqtopt.rz(static [3.926991e-01]) %out_qubits_246 : !mqtopt.Qubit + %out_qubits_253, %pos_ctrl_out_qubits_254 = mqtopt.x() %out_qubits_252 ctrl %pos_ctrl_out_qubits_244 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_255 = mqtopt.x() %pos_ctrl_out_qubits_254 : !mqtopt.Qubit + %out_qubits_256 = mqtopt.rz(static [1.570796e+00]) %out_qubits_255 : !mqtopt.Qubit + %out_qubits_257 = mqtopt.sx() %out_qubits_256 : !mqtopt.Qubit + %out_qubits_258 = mqtopt.rz(static [1.570796e+00]) %out_qubits_257 : !mqtopt.Qubit + %out_qubits_259 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_253 : !mqtopt.Qubit + %out_qubits_260, %pos_ctrl_out_qubits_261 = mqtopt.x() %out_qubits_259 ctrl %pos_ctrl_out_qubits_241 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_262 = mqtopt.x() %pos_ctrl_out_qubits_261 : !mqtopt.Qubit + %out_qubits_263 = mqtopt.rz(static [1.570796e+00]) %out_qubits_262 : !mqtopt.Qubit + %out_qubits_264 = mqtopt.sx() %out_qubits_263 : !mqtopt.Qubit + %out_qubits_265 = mqtopt.rz(static [1.570796e+00]) %out_qubits_264 : !mqtopt.Qubit + %out_qubits_266 = mqtopt.rz(static [1.570796e+00]) %out_qubits_260 : !mqtopt.Qubit + %out_qubits_267 = mqtopt.sx() %out_qubits_266 : !mqtopt.Qubit + %out_qubits_268 = mqtopt.rz(static [1.570796e+00]) %out_qubits_267 : !mqtopt.Qubit + %out_qubits_269 = mqtopt.rz(static [1.570796e+00]) %out_qubits_268 : !mqtopt.Qubit + %out_qubits_270 = mqtopt.sx() %out_qubits_269 : !mqtopt.Qubit + %out_qubits_271 = mqtopt.rz(static [1.570796e+00]) %out_qubits_270 : !mqtopt.Qubit + %out_qubits_272 = mqtopt.x() %out_qubits_271 : !mqtopt.Qubit + %out_qubits_273 = mqtopt.rz(static [1.570796e+00]) %out_qubits_272 : !mqtopt.Qubit + %out_qubits_274 = mqtopt.sx() %out_qubits_273 : !mqtopt.Qubit + %out_qubits_275 = mqtopt.rz(static [1.570796e+00]) %out_qubits_274 : !mqtopt.Qubit + %out_qubits_276 = mqtopt.rz(static [7.853982e-01]) %out_qubits_104 : !mqtopt.Qubit + %out_qubits_277 = mqtopt.rz(static [1.570796e+00]) %out_qubits_276 : !mqtopt.Qubit + %out_qubits_278 = mqtopt.sx() %out_qubits_277 : !mqtopt.Qubit + %out_qubits_279 = mqtopt.rz(static [1.570796e+00]) %out_qubits_278 : !mqtopt.Qubit + %out_qubits_280 = mqtopt.rz(static [7.853982e-01]) %out_qubits_279 : !mqtopt.Qubit + %out_qubits_281 = mqtopt.rz(static [1.570796e+00]) %out_qubits_280 : !mqtopt.Qubit + %out_qubits_282 = mqtopt.sx() %out_qubits_281 : !mqtopt.Qubit + %out_qubits_283 = mqtopt.rz(static [1.570796e+00]) %out_qubits_282 : !mqtopt.Qubit + %out_qubits_284, %pos_ctrl_out_qubits_285 = mqtopt.x() %out_qubits_283 ctrl %out_qubits_251 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_286 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_284 : !mqtopt.Qubit + %out_qubits_287, %pos_ctrl_out_qubits_288 = mqtopt.x() %out_qubits_286 ctrl %out_qubits_265 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_289 = mqtopt.rz(static [7.853982e-01]) %out_qubits_287 : !mqtopt.Qubit + %out_qubits_290, %pos_ctrl_out_qubits_291 = mqtopt.x() %out_qubits_289 ctrl %pos_ctrl_out_qubits_285 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_292 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_291 : !mqtopt.Qubit + %out_qubits_293 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_290 : !mqtopt.Qubit + %out_qubits_294, %pos_ctrl_out_qubits_295 = mqtopt.x() %out_qubits_293 ctrl %pos_ctrl_out_qubits_288 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_296, %pos_ctrl_out_qubits_297 = mqtopt.x() %out_qubits_292 ctrl %pos_ctrl_out_qubits_295 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_298 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_297 : !mqtopt.Qubit + %out_qubits_299 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_296 : !mqtopt.Qubit + %out_qubits_300, %pos_ctrl_out_qubits_301 = mqtopt.x() %out_qubits_299 ctrl %out_qubits_298 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_302 = mqtopt.rz(static [7.853982e-01]) %out_qubits_294 : !mqtopt.Qubit + %out_qubits_303 = mqtopt.rz(static [1.570796e+00]) %out_qubits_302 : !mqtopt.Qubit + %out_qubits_304 = mqtopt.sx() %out_qubits_303 : !mqtopt.Qubit + %out_qubits_305 = mqtopt.rz(static [1.570796e+00]) %out_qubits_304 : !mqtopt.Qubit + %out_qubits_306 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_305 : !mqtopt.Qubit + %out_qubits_307 = mqtopt.rz(static [1.570796e+00]) %out_qubits_306 : !mqtopt.Qubit + %out_qubits_308 = mqtopt.sx() %out_qubits_307 : !mqtopt.Qubit + %out_qubits_309 = mqtopt.rz(static [1.570796e+00]) %out_qubits_308 : !mqtopt.Qubit + %out_qubits_310, %pos_ctrl_out_qubits_311 = mqtopt.x() %out_qubits_309 ctrl %out_qubits_275 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_312 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_310 : !mqtopt.Qubit + %out_qubits_313, %pos_ctrl_out_qubits_314 = mqtopt.x() %out_qubits_312 ctrl %out_qubits_258 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_315 = mqtopt.rz(static [7.853982e-01]) %out_qubits_313 : !mqtopt.Qubit + %out_qubits_316, %pos_ctrl_out_qubits_317 = mqtopt.x() %out_qubits_315 ctrl %pos_ctrl_out_qubits_311 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_318 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_317 : !mqtopt.Qubit + %out_qubits_319 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_316 : !mqtopt.Qubit + %out_qubits_320, %pos_ctrl_out_qubits_321 = mqtopt.x() %out_qubits_319 ctrl %pos_ctrl_out_qubits_314 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_322, %pos_ctrl_out_qubits_323 = mqtopt.x() %out_qubits_318 ctrl %pos_ctrl_out_qubits_321 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_324 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_323 : !mqtopt.Qubit + %out_qubits_325 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_322 : !mqtopt.Qubit + %out_qubits_326, %pos_ctrl_out_qubits_327 = mqtopt.x() %out_qubits_325 ctrl %out_qubits_324 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_328 = mqtopt.rz(static [7.853982e-01]) %out_qubits_320 : !mqtopt.Qubit + %out_qubits_329 = mqtopt.rz(static [1.570796e+00]) %out_qubits_328 : !mqtopt.Qubit + %out_qubits_330 = mqtopt.sx() %out_qubits_329 : !mqtopt.Qubit + %out_qubits_331 = mqtopt.rz(static [1.570796e+00]) %out_qubits_330 : !mqtopt.Qubit + %out_qubits_332 = mqtopt.rz(static [7.853982e-01]) %out_qubits_331 : !mqtopt.Qubit + %out_qubits_333 = mqtopt.rz(static [1.570796e+00]) %out_qubits_332 : !mqtopt.Qubit + %out_qubits_334 = mqtopt.sx() %out_qubits_333 : !mqtopt.Qubit + %out_qubits_335 = mqtopt.rz(static [1.570796e+00]) %out_qubits_334 : !mqtopt.Qubit + %out_qubits_336, %pos_ctrl_out_qubits_337 = mqtopt.x() %out_qubits_335 ctrl %out_qubits_300 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_338 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_336 : !mqtopt.Qubit + %out_qubits_339, %pos_ctrl_out_qubits_340 = mqtopt.x() %out_qubits_338 ctrl %pos_ctrl_out_qubits_301 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_341 = mqtopt.rz(static [7.853982e-01]) %out_qubits_339 : !mqtopt.Qubit + %out_qubits_342, %pos_ctrl_out_qubits_343 = mqtopt.x() %out_qubits_341 ctrl %pos_ctrl_out_qubits_337 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_344 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_343 : !mqtopt.Qubit + %out_qubits_345 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_342 : !mqtopt.Qubit + %out_qubits_346, %pos_ctrl_out_qubits_347 = mqtopt.x() %out_qubits_345 ctrl %pos_ctrl_out_qubits_340 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_348, %pos_ctrl_out_qubits_349 = mqtopt.x() %out_qubits_344 ctrl %pos_ctrl_out_qubits_347 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_350 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_349 : !mqtopt.Qubit + %out_qubits_351 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_348 : !mqtopt.Qubit + %out_qubits_352, %pos_ctrl_out_qubits_353 = mqtopt.x() %out_qubits_351 ctrl %out_qubits_350 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_354 = mqtopt.rz(static [7.853982e-01]) %out_qubits_346 : !mqtopt.Qubit + %out_qubits_355 = mqtopt.rz(static [1.570796e+00]) %out_qubits_354 : !mqtopt.Qubit + %out_qubits_356 = mqtopt.sx() %out_qubits_355 : !mqtopt.Qubit + %out_qubits_357 = mqtopt.rz(static [1.570796e+00]) %out_qubits_356 : !mqtopt.Qubit + %out_qubits_358 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_357 : !mqtopt.Qubit + %out_qubits_359 = mqtopt.rz(static [1.570796e+00]) %out_qubits_358 : !mqtopt.Qubit + %out_qubits_360 = mqtopt.sx() %out_qubits_359 : !mqtopt.Qubit + %out_qubits_361 = mqtopt.rz(static [1.570796e+00]) %out_qubits_360 : !mqtopt.Qubit + %out_qubits_362, %pos_ctrl_out_qubits_363 = mqtopt.x() %out_qubits_361 ctrl %out_qubits_326 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_364 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_362 : !mqtopt.Qubit + %out_qubits_365, %pos_ctrl_out_qubits_366 = mqtopt.x() %out_qubits_364 ctrl %pos_ctrl_out_qubits_327 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_367 = mqtopt.rz(static [7.853982e-01]) %out_qubits_365 : !mqtopt.Qubit + %out_qubits_368, %pos_ctrl_out_qubits_369 = mqtopt.x() %out_qubits_367 ctrl %pos_ctrl_out_qubits_363 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_370 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_369 : !mqtopt.Qubit + %out_qubits_371 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_368 : !mqtopt.Qubit + %out_qubits_372, %pos_ctrl_out_qubits_373 = mqtopt.x() %out_qubits_371 ctrl %pos_ctrl_out_qubits_366 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_374, %pos_ctrl_out_qubits_375 = mqtopt.x() %out_qubits_370 ctrl %pos_ctrl_out_qubits_373 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_376 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_375 : !mqtopt.Qubit + %out_qubits_377 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_374 : !mqtopt.Qubit + %out_qubits_378, %pos_ctrl_out_qubits_379 = mqtopt.x() %out_qubits_377 ctrl %out_qubits_376 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_380 = mqtopt.rz(static [1.570796e+00]) %out_qubits_378 : !mqtopt.Qubit + %out_qubits_381 = mqtopt.sx() %out_qubits_380 : !mqtopt.Qubit + %out_qubits_382 = mqtopt.rz(static [1.570796e+00]) %out_qubits_381 : !mqtopt.Qubit + %out_qubits_383, %pos_ctrl_out_qubits_384 = mqtopt.x() %out_qubits_382 ctrl %out_qubits_352 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_385 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_383 : !mqtopt.Qubit + %out_qubits_386, %pos_ctrl_out_qubits_387 = mqtopt.x() %out_qubits_385 ctrl %pos_ctrl_out_qubits_353 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_388 = mqtopt.rz(static [7.853982e-01]) %out_qubits_386 : !mqtopt.Qubit + %out_qubits_389, %pos_ctrl_out_qubits_390 = mqtopt.x() %out_qubits_388 ctrl %pos_ctrl_out_qubits_384 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_391 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_390 : !mqtopt.Qubit + %out_qubits_392 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_389 : !mqtopt.Qubit + %out_qubits_393, %pos_ctrl_out_qubits_394 = mqtopt.x() %out_qubits_392 ctrl %pos_ctrl_out_qubits_387 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_395, %pos_ctrl_out_qubits_396 = mqtopt.x() %out_qubits_391 ctrl %pos_ctrl_out_qubits_394 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_397 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_396 : !mqtopt.Qubit + %out_qubits_398 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_395 : !mqtopt.Qubit + %out_qubits_399, %pos_ctrl_out_qubits_400 = mqtopt.x() %out_qubits_398 ctrl %out_qubits_397 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_401 = mqtopt.rz(static [7.853982e-01]) %out_qubits_393 : !mqtopt.Qubit + %out_qubits_402 = mqtopt.rz(static [1.570796e+00]) %out_qubits_401 : !mqtopt.Qubit + %out_qubits_403 = mqtopt.sx() %out_qubits_402 : !mqtopt.Qubit + %out_qubits_404 = mqtopt.rz(static [1.570796e+00]) %out_qubits_403 : !mqtopt.Qubit + %out_qubits_405 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_404 : !mqtopt.Qubit + %out_qubits_406, %pos_ctrl_out_qubits_407 = mqtopt.x() %out_qubits_405 ctrl %pos_ctrl_out_qubits_379 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_408 = mqtopt.rz(static [3.926991e-01]) %out_qubits_406 : !mqtopt.Qubit + %out_qubits_409 = mqtopt.rz(static [1.570796e+00]) %out_qubits_408 : !mqtopt.Qubit + %out_qubits_410 = mqtopt.sx() %out_qubits_409 : !mqtopt.Qubit + %out_qubits_411 = mqtopt.rz(static [1.570796e+00]) %out_qubits_410 : !mqtopt.Qubit + %out_qubits_412, %pos_ctrl_out_qubits_413 = mqtopt.x() %out_qubits_411 ctrl %out_qubits_399 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_414 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_412 : !mqtopt.Qubit + %out_qubits_415, %pos_ctrl_out_qubits_416 = mqtopt.x() %out_qubits_414 ctrl %pos_ctrl_out_qubits_400 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_417 = mqtopt.rz(static [7.853982e-01]) %out_qubits_415 : !mqtopt.Qubit + %out_qubits_418, %pos_ctrl_out_qubits_419 = mqtopt.x() %out_qubits_417 ctrl %pos_ctrl_out_qubits_413 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_420 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_419 : !mqtopt.Qubit + %out_qubits_421 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_418 : !mqtopt.Qubit + %out_qubits_422, %pos_ctrl_out_qubits_423 = mqtopt.x() %out_qubits_421 ctrl %pos_ctrl_out_qubits_416 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_424, %pos_ctrl_out_qubits_425 = mqtopt.x() %out_qubits_420 ctrl %pos_ctrl_out_qubits_423 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_426 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_425 : !mqtopt.Qubit + %out_qubits_427 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_424 : !mqtopt.Qubit + %out_qubits_428, %pos_ctrl_out_qubits_429 = mqtopt.x() %out_qubits_427 ctrl %out_qubits_426 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_430 = mqtopt.rz(static [7.853982e-01]) %out_qubits_422 : !mqtopt.Qubit + %out_qubits_431 = mqtopt.rz(static [1.570796e+00]) %out_qubits_430 : !mqtopt.Qubit + %out_qubits_432 = mqtopt.sx() %out_qubits_431 : !mqtopt.Qubit + %out_qubits_433 = mqtopt.rz(static [1.570796e+00]) %out_qubits_432 : !mqtopt.Qubit + %out_qubits_434 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_433 : !mqtopt.Qubit + %out_qubits_435, %pos_ctrl_out_qubits_436 = mqtopt.x() %out_qubits_434 ctrl %pos_ctrl_out_qubits_407 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_437, %pos_ctrl_out_qubits_438 = mqtopt.x() %pos_ctrl_out_qubits_436 ctrl %pos_ctrl_out_qubits_429 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_439 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_437 : !mqtopt.Qubit + %out_qubits_440, %pos_ctrl_out_qubits_441 = mqtopt.x() %out_qubits_439 ctrl %out_qubits_428 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_442 = mqtopt.rz(static [1.963495e-01]) %out_qubits_440 : !mqtopt.Qubit + %out_qubits_443, %pos_ctrl_out_qubits_444 = mqtopt.x() %out_qubits_442 ctrl %pos_ctrl_out_qubits_438 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_445 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_443 : !mqtopt.Qubit + %out_qubits_446, %pos_ctrl_out_qubits_447 = mqtopt.x() %out_qubits_445 ctrl %pos_ctrl_out_qubits_441 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_448 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_447 : !mqtopt.Qubit + %out_qubits_449, %pos_ctrl_out_qubits_450 = mqtopt.x() %out_qubits_448 ctrl %pos_ctrl_out_qubits_444 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_451 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_449 : !mqtopt.Qubit + %out_qubits_452, %pos_ctrl_out_qubits_453 = mqtopt.x() %out_qubits_451 ctrl %pos_ctrl_out_qubits_450 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_454 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_453 : !mqtopt.Qubit + %out_qubits_455 = mqtopt.rz(static [1.570796e+00]) %out_qubits_454 : !mqtopt.Qubit + %out_qubits_456 = mqtopt.sx() %out_qubits_455 : !mqtopt.Qubit + %out_qubits_457 = mqtopt.rz(static [1.570796e+00]) %out_qubits_456 : !mqtopt.Qubit + %out_qubits_458 = mqtopt.x() %out_qubits_457 : !mqtopt.Qubit + %out_qubits_459 = mqtopt.rz(static [3.926991e-01]) %out_qubits_458 : !mqtopt.Qubit + %out_qubits_460 = mqtopt.rz(static [1.570796e+00]) %out_qubits_452 : !mqtopt.Qubit + %out_qubits_461 = mqtopt.sx() %out_qubits_460 : !mqtopt.Qubit + %out_qubits_462 = mqtopt.rz(static [1.570796e+00]) %out_qubits_461 : !mqtopt.Qubit + %out_qubits_463 = mqtopt.x() %out_qubits_462 : !mqtopt.Qubit + %out_qubits_464 = mqtopt.rz(static [3.926991e-01]) %out_qubits_463 : !mqtopt.Qubit + %out_qubits_465, %pos_ctrl_out_qubits_466 = mqtopt.x() %out_qubits_464 ctrl %out_qubits_459 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_467 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_465 : !mqtopt.Qubit + %out_qubits_468, %pos_ctrl_out_qubits_469 = mqtopt.x() %out_qubits_467 ctrl %pos_ctrl_out_qubits_466 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_470 = mqtopt.rz(static [1.963495e-01]) %out_qubits_446 : !mqtopt.Qubit + %out_qubits_471 = mqtopt.rz(static [1.570796e+00]) %out_qubits_470 : !mqtopt.Qubit + %out_qubits_472 = mqtopt.sx() %out_qubits_471 : !mqtopt.Qubit + %out_qubits_473 = mqtopt.rz(static [1.570796e+00]) %out_qubits_472 : !mqtopt.Qubit + %out_qubits_474 = mqtopt.x() %out_qubits_473 : !mqtopt.Qubit + %out_qubits_475 = mqtopt.rz(static [3.926991e-01]) %out_qubits_474 : !mqtopt.Qubit + %out_qubits_476, %pos_ctrl_out_qubits_477 = mqtopt.x() %out_qubits_475 ctrl %out_qubits_468 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_478 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_476 : !mqtopt.Qubit + %out_qubits_479, %pos_ctrl_out_qubits_480 = mqtopt.x() %out_qubits_478 ctrl %pos_ctrl_out_qubits_469 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_481 = mqtopt.rz(static [3.926991e-01]) %out_qubits_479 : !mqtopt.Qubit + %out_qubits_482, %pos_ctrl_out_qubits_483 = mqtopt.x() %out_qubits_481 ctrl %pos_ctrl_out_qubits_477 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_484 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_482 : !mqtopt.Qubit + %out_qubits_485, %pos_ctrl_out_qubits_486 = mqtopt.x() %out_qubits_484 ctrl %pos_ctrl_out_qubits_480 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_487 = mqtopt.rz(static [3.926991e-01]) %out_qubits_435 : !mqtopt.Qubit + %out_qubits_488 = mqtopt.rz(static [1.570796e+00]) %out_qubits_487 : !mqtopt.Qubit + %out_qubits_489 = mqtopt.sx() %out_qubits_488 : !mqtopt.Qubit + %out_qubits_490 = mqtopt.rz(static [1.570796e+00]) %out_qubits_489 : !mqtopt.Qubit + %out_qubits_491 = mqtopt.x() %out_qubits_490 : !mqtopt.Qubit + %out_qubits_492 = mqtopt.rz(static [1.570796e+00]) %out_qubits_491 : !mqtopt.Qubit + %out_qubits_493 = mqtopt.sx() %out_qubits_492 : !mqtopt.Qubit + %out_qubits_494 = mqtopt.rz(static [1.570796e+00]) %out_qubits_493 : !mqtopt.Qubit + %out_qubits_495 = mqtopt.rz(static [1.570796e+00]) %out_qubits_494 : !mqtopt.Qubit + %out_qubits_496 = mqtopt.sx() %out_qubits_495 : !mqtopt.Qubit + %out_qubits_497 = mqtopt.rz(static [1.570796e+00]) %out_qubits_496 : !mqtopt.Qubit + %out_qubits_498 = mqtopt.rz(static [3.926991e-01]) %out_qubits_497 : !mqtopt.Qubit + %out_qubits_499, %pos_ctrl_out_qubits_500 = mqtopt.x() %out_qubits_498 ctrl %out_qubits_485 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_501 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_499 : !mqtopt.Qubit + %out_qubits_502, %pos_ctrl_out_qubits_503 = mqtopt.x() %out_qubits_501 ctrl %pos_ctrl_out_qubits_483 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_504 = mqtopt.rz(static [3.926991e-01]) %out_qubits_502 : !mqtopt.Qubit + %out_qubits_505, %pos_ctrl_out_qubits_506 = mqtopt.x() %out_qubits_504 ctrl %pos_ctrl_out_qubits_500 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_507 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_505 : !mqtopt.Qubit + %out_qubits_508, %pos_ctrl_out_qubits_509 = mqtopt.x() %out_qubits_507 ctrl %pos_ctrl_out_qubits_486 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_510 = mqtopt.rz(static [3.926991e-01]) %out_qubits_508 : !mqtopt.Qubit + %out_qubits_511, %pos_ctrl_out_qubits_512 = mqtopt.x() %out_qubits_510 ctrl %pos_ctrl_out_qubits_506 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_513 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_511 : !mqtopt.Qubit + %out_qubits_514, %pos_ctrl_out_qubits_515 = mqtopt.x() %out_qubits_513 ctrl %pos_ctrl_out_qubits_503 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_516 = mqtopt.x() %pos_ctrl_out_qubits_515 : !mqtopt.Qubit + %out_qubits_517 = mqtopt.rz(static [1.570796e+00]) %out_qubits_516 : !mqtopt.Qubit + %out_qubits_518 = mqtopt.sx() %out_qubits_517 : !mqtopt.Qubit + %out_qubits_519 = mqtopt.rz(static [1.570796e+00]) %out_qubits_518 : !mqtopt.Qubit + %out_qubits_520 = mqtopt.rz(static [3.926991e-01]) %out_qubits_514 : !mqtopt.Qubit + %out_qubits_521, %pos_ctrl_out_qubits_522 = mqtopt.x() %out_qubits_520 ctrl %pos_ctrl_out_qubits_512 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_523 = mqtopt.x() %pos_ctrl_out_qubits_522 : !mqtopt.Qubit + %out_qubits_524 = mqtopt.rz(static [1.570796e+00]) %out_qubits_523 : !mqtopt.Qubit + %out_qubits_525 = mqtopt.sx() %out_qubits_524 : !mqtopt.Qubit + %out_qubits_526 = mqtopt.rz(static [1.570796e+00]) %out_qubits_525 : !mqtopt.Qubit + %out_qubits_527 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_521 : !mqtopt.Qubit + %out_qubits_528, %pos_ctrl_out_qubits_529 = mqtopt.x() %out_qubits_527 ctrl %pos_ctrl_out_qubits_509 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_530 = mqtopt.x() %pos_ctrl_out_qubits_529 : !mqtopt.Qubit + %out_qubits_531 = mqtopt.rz(static [1.570796e+00]) %out_qubits_530 : !mqtopt.Qubit + %out_qubits_532 = mqtopt.sx() %out_qubits_531 : !mqtopt.Qubit + %out_qubits_533 = mqtopt.rz(static [1.570796e+00]) %out_qubits_532 : !mqtopt.Qubit + %out_qubits_534 = mqtopt.rz(static [1.570796e+00]) %out_qubits_528 : !mqtopt.Qubit + %out_qubits_535 = mqtopt.sx() %out_qubits_534 : !mqtopt.Qubit + %out_qubits_536 = mqtopt.rz(static [1.570796e+00]) %out_qubits_535 : !mqtopt.Qubit + %out_qubits_537 = mqtopt.rz(static [1.570796e+00]) %out_qubits_536 : !mqtopt.Qubit + %out_qubits_538 = mqtopt.sx() %out_qubits_537 : !mqtopt.Qubit + %out_qubits_539 = mqtopt.rz(static [1.570796e+00]) %out_qubits_538 : !mqtopt.Qubit + %out_qubits_540 = mqtopt.x() %out_qubits_539 : !mqtopt.Qubit + %out_qubits_541 = mqtopt.rz(static [1.570796e+00]) %out_qubits_540 : !mqtopt.Qubit + %out_qubits_542 = mqtopt.sx() %out_qubits_541 : !mqtopt.Qubit + %out_qubits_543 = mqtopt.rz(static [1.570796e+00]) %out_qubits_542 : !mqtopt.Qubit + %out_qubits_544 = mqtopt.rz(static [7.853982e-01]) %out_qubits_372 : !mqtopt.Qubit + %out_qubits_545 = mqtopt.rz(static [1.570796e+00]) %out_qubits_544 : !mqtopt.Qubit + %out_qubits_546 = mqtopt.sx() %out_qubits_545 : !mqtopt.Qubit + %out_qubits_547 = mqtopt.rz(static [1.570796e+00]) %out_qubits_546 : !mqtopt.Qubit + %out_qubits_548 = mqtopt.rz(static [7.853982e-01]) %out_qubits_547 : !mqtopt.Qubit + %out_qubits_549 = mqtopt.rz(static [1.570796e+00]) %out_qubits_548 : !mqtopt.Qubit + %out_qubits_550 = mqtopt.sx() %out_qubits_549 : !mqtopt.Qubit + %out_qubits_551 = mqtopt.rz(static [1.570796e+00]) %out_qubits_550 : !mqtopt.Qubit + %out_qubits_552, %pos_ctrl_out_qubits_553 = mqtopt.x() %out_qubits_551 ctrl %out_qubits_519 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_554 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_552 : !mqtopt.Qubit + %out_qubits_555, %pos_ctrl_out_qubits_556 = mqtopt.x() %out_qubits_554 ctrl %out_qubits_533 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_557 = mqtopt.rz(static [7.853982e-01]) %out_qubits_555 : !mqtopt.Qubit + %out_qubits_558, %pos_ctrl_out_qubits_559 = mqtopt.x() %out_qubits_557 ctrl %pos_ctrl_out_qubits_553 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_560 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_559 : !mqtopt.Qubit + %out_qubits_561 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_558 : !mqtopt.Qubit + %out_qubits_562, %pos_ctrl_out_qubits_563 = mqtopt.x() %out_qubits_561 ctrl %pos_ctrl_out_qubits_556 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_564, %pos_ctrl_out_qubits_565 = mqtopt.x() %out_qubits_560 ctrl %pos_ctrl_out_qubits_563 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_566 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_565 : !mqtopt.Qubit + %out_qubits_567 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_564 : !mqtopt.Qubit + %out_qubits_568, %pos_ctrl_out_qubits_569 = mqtopt.x() %out_qubits_567 ctrl %out_qubits_566 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_570 = mqtopt.rz(static [7.853982e-01]) %out_qubits_562 : !mqtopt.Qubit + %out_qubits_571 = mqtopt.rz(static [1.570796e+00]) %out_qubits_570 : !mqtopt.Qubit + %out_qubits_572 = mqtopt.sx() %out_qubits_571 : !mqtopt.Qubit + %out_qubits_573 = mqtopt.rz(static [1.570796e+00]) %out_qubits_572 : !mqtopt.Qubit + %out_qubits_574 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_573 : !mqtopt.Qubit + %out_qubits_575 = mqtopt.rz(static [1.570796e+00]) %out_qubits_574 : !mqtopt.Qubit + %out_qubits_576 = mqtopt.sx() %out_qubits_575 : !mqtopt.Qubit + %out_qubits_577 = mqtopt.rz(static [1.570796e+00]) %out_qubits_576 : !mqtopt.Qubit + %out_qubits_578, %pos_ctrl_out_qubits_579 = mqtopt.x() %out_qubits_577 ctrl %out_qubits_543 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_580 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_578 : !mqtopt.Qubit + %out_qubits_581, %pos_ctrl_out_qubits_582 = mqtopt.x() %out_qubits_580 ctrl %out_qubits_526 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_583 = mqtopt.rz(static [7.853982e-01]) %out_qubits_581 : !mqtopt.Qubit + %out_qubits_584, %pos_ctrl_out_qubits_585 = mqtopt.x() %out_qubits_583 ctrl %pos_ctrl_out_qubits_579 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_586 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_585 : !mqtopt.Qubit + %out_qubits_587 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_584 : !mqtopt.Qubit + %out_qubits_588, %pos_ctrl_out_qubits_589 = mqtopt.x() %out_qubits_587 ctrl %pos_ctrl_out_qubits_582 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_590, %pos_ctrl_out_qubits_591 = mqtopt.x() %out_qubits_586 ctrl %pos_ctrl_out_qubits_589 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_592 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_591 : !mqtopt.Qubit + %out_qubits_593 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_590 : !mqtopt.Qubit + %out_qubits_594, %pos_ctrl_out_qubits_595 = mqtopt.x() %out_qubits_593 ctrl %out_qubits_592 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_596 = mqtopt.rz(static [7.853982e-01]) %out_qubits_588 : !mqtopt.Qubit + %out_qubits_597 = mqtopt.rz(static [1.570796e+00]) %out_qubits_596 : !mqtopt.Qubit + %out_qubits_598 = mqtopt.sx() %out_qubits_597 : !mqtopt.Qubit + %out_qubits_599 = mqtopt.rz(static [1.570796e+00]) %out_qubits_598 : !mqtopt.Qubit + %out_qubits_600 = mqtopt.rz(static [7.853982e-01]) %out_qubits_599 : !mqtopt.Qubit + %out_qubits_601 = mqtopt.rz(static [1.570796e+00]) %out_qubits_600 : !mqtopt.Qubit + %out_qubits_602 = mqtopt.sx() %out_qubits_601 : !mqtopt.Qubit + %out_qubits_603 = mqtopt.rz(static [1.570796e+00]) %out_qubits_602 : !mqtopt.Qubit + %out_qubits_604, %pos_ctrl_out_qubits_605 = mqtopt.x() %out_qubits_603 ctrl %out_qubits_568 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_606 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_604 : !mqtopt.Qubit + %out_qubits_607, %pos_ctrl_out_qubits_608 = mqtopt.x() %out_qubits_606 ctrl %pos_ctrl_out_qubits_569 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_609 = mqtopt.rz(static [7.853982e-01]) %out_qubits_607 : !mqtopt.Qubit + %out_qubits_610, %pos_ctrl_out_qubits_611 = mqtopt.x() %out_qubits_609 ctrl %pos_ctrl_out_qubits_605 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_612 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_611 : !mqtopt.Qubit + %out_qubits_613 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_610 : !mqtopt.Qubit + %out_qubits_614, %pos_ctrl_out_qubits_615 = mqtopt.x() %out_qubits_613 ctrl %pos_ctrl_out_qubits_608 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_616, %pos_ctrl_out_qubits_617 = mqtopt.x() %out_qubits_612 ctrl %pos_ctrl_out_qubits_615 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_618 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_617 : !mqtopt.Qubit + %out_qubits_619 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_616 : !mqtopt.Qubit + %out_qubits_620, %pos_ctrl_out_qubits_621 = mqtopt.x() %out_qubits_619 ctrl %out_qubits_618 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_622 = mqtopt.rz(static [7.853982e-01]) %out_qubits_614 : !mqtopt.Qubit + %out_qubits_623 = mqtopt.rz(static [1.570796e+00]) %out_qubits_622 : !mqtopt.Qubit + %out_qubits_624 = mqtopt.sx() %out_qubits_623 : !mqtopt.Qubit + %out_qubits_625 = mqtopt.rz(static [1.570796e+00]) %out_qubits_624 : !mqtopt.Qubit + %out_qubits_626 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_625 : !mqtopt.Qubit + %out_qubits_627 = mqtopt.rz(static [1.570796e+00]) %out_qubits_626 : !mqtopt.Qubit + %out_qubits_628 = mqtopt.sx() %out_qubits_627 : !mqtopt.Qubit + %out_qubits_629 = mqtopt.rz(static [1.570796e+00]) %out_qubits_628 : !mqtopt.Qubit + %out_qubits_630, %pos_ctrl_out_qubits_631 = mqtopt.x() %out_qubits_629 ctrl %out_qubits_594 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_632 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_630 : !mqtopt.Qubit + %out_qubits_633, %pos_ctrl_out_qubits_634 = mqtopt.x() %out_qubits_632 ctrl %pos_ctrl_out_qubits_595 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_635 = mqtopt.rz(static [7.853982e-01]) %out_qubits_633 : !mqtopt.Qubit + %out_qubits_636, %pos_ctrl_out_qubits_637 = mqtopt.x() %out_qubits_635 ctrl %pos_ctrl_out_qubits_631 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_638 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_637 : !mqtopt.Qubit + %out_qubits_639 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_636 : !mqtopt.Qubit + %out_qubits_640, %pos_ctrl_out_qubits_641 = mqtopt.x() %out_qubits_639 ctrl %pos_ctrl_out_qubits_634 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_642, %pos_ctrl_out_qubits_643 = mqtopt.x() %out_qubits_638 ctrl %pos_ctrl_out_qubits_641 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_644 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_643 : !mqtopt.Qubit + %out_qubits_645 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_642 : !mqtopt.Qubit + %out_qubits_646, %pos_ctrl_out_qubits_647 = mqtopt.x() %out_qubits_645 ctrl %out_qubits_644 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_648 = mqtopt.rz(static [1.570796e+00]) %out_qubits_646 : !mqtopt.Qubit + %out_qubits_649 = mqtopt.sx() %out_qubits_648 : !mqtopt.Qubit + %out_qubits_650 = mqtopt.rz(static [1.570796e+00]) %out_qubits_649 : !mqtopt.Qubit + %out_qubits_651, %pos_ctrl_out_qubits_652 = mqtopt.x() %out_qubits_650 ctrl %out_qubits_620 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_653 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_651 : !mqtopt.Qubit + %out_qubits_654, %pos_ctrl_out_qubits_655 = mqtopt.x() %out_qubits_653 ctrl %pos_ctrl_out_qubits_621 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_656 = mqtopt.rz(static [7.853982e-01]) %out_qubits_654 : !mqtopt.Qubit + %out_qubits_657, %pos_ctrl_out_qubits_658 = mqtopt.x() %out_qubits_656 ctrl %pos_ctrl_out_qubits_652 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_659 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_658 : !mqtopt.Qubit + %out_qubits_660 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_657 : !mqtopt.Qubit + %out_qubits_661, %pos_ctrl_out_qubits_662 = mqtopt.x() %out_qubits_660 ctrl %pos_ctrl_out_qubits_655 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_663, %pos_ctrl_out_qubits_664 = mqtopt.x() %out_qubits_659 ctrl %pos_ctrl_out_qubits_662 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_665 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_664 : !mqtopt.Qubit + %out_qubits_666 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_663 : !mqtopt.Qubit + %out_qubits_667, %pos_ctrl_out_qubits_668 = mqtopt.x() %out_qubits_666 ctrl %out_qubits_665 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_669 = mqtopt.rz(static [7.853982e-01]) %out_qubits_661 : !mqtopt.Qubit + %out_qubits_670 = mqtopt.rz(static [1.570796e+00]) %out_qubits_669 : !mqtopt.Qubit + %out_qubits_671 = mqtopt.sx() %out_qubits_670 : !mqtopt.Qubit + %out_qubits_672 = mqtopt.rz(static [1.570796e+00]) %out_qubits_671 : !mqtopt.Qubit + %out_qubits_673 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_672 : !mqtopt.Qubit + %out_qubits_674, %pos_ctrl_out_qubits_675 = mqtopt.x() %out_qubits_673 ctrl %pos_ctrl_out_qubits_647 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_676 = mqtopt.rz(static [3.926991e-01]) %out_qubits_674 : !mqtopt.Qubit + %out_qubits_677 = mqtopt.rz(static [1.570796e+00]) %out_qubits_676 : !mqtopt.Qubit + %out_qubits_678 = mqtopt.sx() %out_qubits_677 : !mqtopt.Qubit + %out_qubits_679 = mqtopt.rz(static [1.570796e+00]) %out_qubits_678 : !mqtopt.Qubit + %out_qubits_680, %pos_ctrl_out_qubits_681 = mqtopt.x() %out_qubits_679 ctrl %out_qubits_667 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_682 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_680 : !mqtopt.Qubit + %out_qubits_683, %pos_ctrl_out_qubits_684 = mqtopt.x() %out_qubits_682 ctrl %pos_ctrl_out_qubits_668 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_685 = mqtopt.rz(static [7.853982e-01]) %out_qubits_683 : !mqtopt.Qubit + %out_qubits_686, %pos_ctrl_out_qubits_687 = mqtopt.x() %out_qubits_685 ctrl %pos_ctrl_out_qubits_681 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_688 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_687 : !mqtopt.Qubit + %out_qubits_689 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_686 : !mqtopt.Qubit + %out_qubits_690, %pos_ctrl_out_qubits_691 = mqtopt.x() %out_qubits_689 ctrl %pos_ctrl_out_qubits_684 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_692, %pos_ctrl_out_qubits_693 = mqtopt.x() %out_qubits_688 ctrl %pos_ctrl_out_qubits_691 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_694 = mqtopt.rz(static [7.853982e-01]) %pos_ctrl_out_qubits_693 : !mqtopt.Qubit + %out_qubits_695 = mqtopt.rz(static [-7.853982e-01]) %out_qubits_692 : !mqtopt.Qubit + %out_qubits_696, %pos_ctrl_out_qubits_697 = mqtopt.x() %out_qubits_695 ctrl %out_qubits_694 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_698 = mqtopt.rz(static [7.853982e-01]) %out_qubits_690 : !mqtopt.Qubit + %out_qubits_699 = mqtopt.rz(static [1.570796e+00]) %out_qubits_698 : !mqtopt.Qubit + %out_qubits_700 = mqtopt.sx() %out_qubits_699 : !mqtopt.Qubit + %out_qubits_701 = mqtopt.rz(static [1.570796e+00]) %out_qubits_700 : !mqtopt.Qubit + %out_qubits_702 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_701 : !mqtopt.Qubit + %out_qubits_703, %pos_ctrl_out_qubits_704 = mqtopt.x() %out_qubits_702 ctrl %pos_ctrl_out_qubits_675 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_705, %pos_ctrl_out_qubits_706 = mqtopt.x() %pos_ctrl_out_qubits_704 ctrl %pos_ctrl_out_qubits_697 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_707 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_705 : !mqtopt.Qubit + %out_qubits_708, %pos_ctrl_out_qubits_709 = mqtopt.x() %out_qubits_707 ctrl %out_qubits_696 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_710 = mqtopt.rz(static [1.963495e-01]) %out_qubits_708 : !mqtopt.Qubit + %out_qubits_711, %pos_ctrl_out_qubits_712 = mqtopt.x() %out_qubits_710 ctrl %pos_ctrl_out_qubits_706 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_713 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_711 : !mqtopt.Qubit + %out_qubits_714, %pos_ctrl_out_qubits_715 = mqtopt.x() %out_qubits_713 ctrl %pos_ctrl_out_qubits_709 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_716 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_715 : !mqtopt.Qubit + %out_qubits_717, %pos_ctrl_out_qubits_718 = mqtopt.x() %out_qubits_716 ctrl %pos_ctrl_out_qubits_712 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_719 = mqtopt.rz(static [-1.963495e-01]) %out_qubits_717 : !mqtopt.Qubit + %out_qubits_720, %pos_ctrl_out_qubits_721 = mqtopt.x() %out_qubits_719 ctrl %pos_ctrl_out_qubits_718 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_722 = mqtopt.rz(static [1.963495e-01]) %pos_ctrl_out_qubits_721 : !mqtopt.Qubit + %out_qubits_723 = mqtopt.rz(static [1.570796e+00]) %out_qubits_722 : !mqtopt.Qubit + %out_qubits_724 = mqtopt.sx() %out_qubits_723 : !mqtopt.Qubit + %out_qubits_725 = mqtopt.rz(static [1.570796e+00]) %out_qubits_724 : !mqtopt.Qubit + %out_qubits_726 = mqtopt.x() %out_qubits_725 : !mqtopt.Qubit + %out_qubits_727 = mqtopt.rz(static [3.926991e-01]) %out_qubits_726 : !mqtopt.Qubit + %out_qubits_728 = mqtopt.rz(static [1.570796e+00]) %out_qubits_720 : !mqtopt.Qubit + %out_qubits_729 = mqtopt.sx() %out_qubits_728 : !mqtopt.Qubit + %out_qubits_730 = mqtopt.rz(static [1.570796e+00]) %out_qubits_729 : !mqtopt.Qubit + %out_qubits_731 = mqtopt.x() %out_qubits_730 : !mqtopt.Qubit + %out_qubits_732 = mqtopt.rz(static [3.926991e-01]) %out_qubits_731 : !mqtopt.Qubit + %out_qubits_733, %pos_ctrl_out_qubits_734 = mqtopt.x() %out_qubits_732 ctrl %out_qubits_727 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_735 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_733 : !mqtopt.Qubit + %out_qubits_736, %pos_ctrl_out_qubits_737 = mqtopt.x() %out_qubits_735 ctrl %pos_ctrl_out_qubits_734 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_738 = mqtopt.rz(static [1.963495e-01]) %out_qubits_714 : !mqtopt.Qubit + %out_qubits_739 = mqtopt.rz(static [1.570796e+00]) %out_qubits_738 : !mqtopt.Qubit + %out_qubits_740 = mqtopt.sx() %out_qubits_739 : !mqtopt.Qubit + %out_qubits_741 = mqtopt.rz(static [1.570796e+00]) %out_qubits_740 : !mqtopt.Qubit + %out_qubits_742 = mqtopt.x() %out_qubits_741 : !mqtopt.Qubit + %out_qubits_743 = mqtopt.rz(static [3.926991e-01]) %out_qubits_742 : !mqtopt.Qubit + %out_qubits_744, %pos_ctrl_out_qubits_745 = mqtopt.x() %out_qubits_743 ctrl %out_qubits_736 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_746 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_744 : !mqtopt.Qubit + %out_qubits_747, %pos_ctrl_out_qubits_748 = mqtopt.x() %out_qubits_746 ctrl %pos_ctrl_out_qubits_737 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_749 = mqtopt.rz(static [3.926991e-01]) %out_qubits_747 : !mqtopt.Qubit + %out_qubits_750, %pos_ctrl_out_qubits_751 = mqtopt.x() %out_qubits_749 ctrl %pos_ctrl_out_qubits_745 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_752 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_750 : !mqtopt.Qubit + %out_qubits_753, %pos_ctrl_out_qubits_754 = mqtopt.x() %out_qubits_752 ctrl %pos_ctrl_out_qubits_748 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_755 = mqtopt.rz(static [3.926991e-01]) %out_qubits_703 : !mqtopt.Qubit + %out_qubits_756 = mqtopt.rz(static [1.570796e+00]) %out_qubits_755 : !mqtopt.Qubit + %out_qubits_757 = mqtopt.sx() %out_qubits_756 : !mqtopt.Qubit + %out_qubits_758 = mqtopt.rz(static [1.570796e+00]) %out_qubits_757 : !mqtopt.Qubit + %out_qubits_759 = mqtopt.x() %out_qubits_758 : !mqtopt.Qubit + %out_qubits_760 = mqtopt.rz(static [1.570796e+00]) %out_qubits_759 : !mqtopt.Qubit + %out_qubits_761 = mqtopt.sx() %out_qubits_760 : !mqtopt.Qubit + %out_qubits_762 = mqtopt.rz(static [1.570796e+00]) %out_qubits_761 : !mqtopt.Qubit + %out_qubits_763 = mqtopt.rz(static [1.570796e+00]) %out_qubits_762 : !mqtopt.Qubit + %out_qubits_764 = mqtopt.sx() %out_qubits_763 : !mqtopt.Qubit + %out_qubits_765 = mqtopt.rz(static [1.570796e+00]) %out_qubits_764 : !mqtopt.Qubit + %out_qubits_766 = mqtopt.rz(static [3.926991e-01]) %out_qubits_765 : !mqtopt.Qubit + %out_qubits_767, %pos_ctrl_out_qubits_768 = mqtopt.x() %out_qubits_766 ctrl %out_qubits_753 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_769 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_767 : !mqtopt.Qubit + %out_qubits_770, %pos_ctrl_out_qubits_771 = mqtopt.x() %out_qubits_769 ctrl %pos_ctrl_out_qubits_751 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_772 = mqtopt.rz(static [3.926991e-01]) %out_qubits_770 : !mqtopt.Qubit + %out_qubits_773, %pos_ctrl_out_qubits_774 = mqtopt.x() %out_qubits_772 ctrl %pos_ctrl_out_qubits_768 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_775 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_773 : !mqtopt.Qubit + %out_qubits_776, %pos_ctrl_out_qubits_777 = mqtopt.x() %out_qubits_775 ctrl %pos_ctrl_out_qubits_754 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_778 = mqtopt.rz(static [3.926991e-01]) %out_qubits_776 : !mqtopt.Qubit + %out_qubits_779, %pos_ctrl_out_qubits_780 = mqtopt.x() %out_qubits_778 ctrl %pos_ctrl_out_qubits_774 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_781 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_779 : !mqtopt.Qubit + %out_qubits_782, %pos_ctrl_out_qubits_783 = mqtopt.x() %out_qubits_781 ctrl %pos_ctrl_out_qubits_771 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_784 = mqtopt.x() %pos_ctrl_out_qubits_783 : !mqtopt.Qubit + %out_qubits_785 = mqtopt.rz(static [1.570796e+00]) %out_qubits_784 : !mqtopt.Qubit + %out_qubits_786 = mqtopt.sx() %out_qubits_785 : !mqtopt.Qubit + %out_qubits_787 = mqtopt.rz(static [1.570796e+00]) %out_qubits_786 : !mqtopt.Qubit + %out_qubits_788 = mqtopt.rz(static [3.926991e-01]) %out_qubits_782 : !mqtopt.Qubit + %out_qubits_789, %pos_ctrl_out_qubits_790 = mqtopt.x() %out_qubits_788 ctrl %pos_ctrl_out_qubits_780 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_791 = mqtopt.x() %pos_ctrl_out_qubits_790 : !mqtopt.Qubit + %out_qubits_792 = mqtopt.rz(static [1.570796e+00]) %out_qubits_791 : !mqtopt.Qubit + %out_qubits_793 = mqtopt.sx() %out_qubits_792 : !mqtopt.Qubit + %out_qubits_794 = mqtopt.rz(static [1.570796e+00]) %out_qubits_793 : !mqtopt.Qubit + %out_qubits_795 = mqtopt.rz(static [-3.926991e-01]) %out_qubits_789 : !mqtopt.Qubit + %out_qubits_796, %pos_ctrl_out_qubits_797 = mqtopt.x() %out_qubits_795 ctrl %pos_ctrl_out_qubits_777 : !mqtopt.Qubit ctrl !mqtopt.Qubit + %out_qubits_798 = mqtopt.x() %pos_ctrl_out_qubits_797 : !mqtopt.Qubit + %out_qubits_799 = mqtopt.rz(static [1.570796e+00]) %out_qubits_798 : !mqtopt.Qubit + %out_qubits_800 = mqtopt.sx() %out_qubits_799 : !mqtopt.Qubit + %out_qubits_801 = mqtopt.rz(static [1.570796e+00]) %out_qubits_800 : !mqtopt.Qubit + %out_qubits_802 = mqtopt.rz(static [1.570796e+00]) %out_qubits_796 : !mqtopt.Qubit + %out_qubits_803 = mqtopt.sx() %out_qubits_802 : !mqtopt.Qubit + %out_qubits_804 = mqtopt.rz(static [1.570796e+00]) %out_qubits_803 : !mqtopt.Qubit + %out_qubits_805 = mqtopt.rz(static [1.570796e+00]) %out_qubits_804 : !mqtopt.Qubit + %out_qubits_806 = mqtopt.sx() %out_qubits_805 : !mqtopt.Qubit + %out_qubits_807 = mqtopt.rz(static [1.570796e+00]) %out_qubits_806 : !mqtopt.Qubit + %out_qubits_808 = mqtopt.x() %out_qubits_807 : !mqtopt.Qubit + %out_qubits_809 = mqtopt.rz(static [1.570796e+00]) %out_qubits_808 : !mqtopt.Qubit + %out_qubits_810 = mqtopt.sx() %out_qubits_809 : !mqtopt.Qubit + %out_qubits_811 = mqtopt.rz(static [1.570796e+00]) %out_qubits_810 : !mqtopt.Qubit + %out_qubits_812 = mqtopt.rz(static [7.853982e-01]) %out_qubits_640 : !mqtopt.Qubit + %out_qubits_813 = mqtopt.rz(static [1.570796e+00]) %out_qubits_812 : !mqtopt.Qubit + %out_qubits_814 = mqtopt.sx() %out_qubits_813 : !mqtopt.Qubit + %out_qubits_815 = mqtopt.rz(static [1.570796e+00]) %out_qubits_814 : !mqtopt.Qubit + %out_qubits_816 = mqtopt.rz(static [7.853982e-01]) %out_qubits_815 : !mqtopt.Qubit + %out_qubits_817:5 = mqtopt.barrier() %out_qubits_801, %out_qubits_787, %out_qubits_794, %out_qubits_811, %out_qubits_816 : !mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit + %out_qubit, %out_bit = mqtopt.measure %out_qubits_817#0 + %c0_818 = arith.constant 0 : index + memref.store %out_bit, %alloca[%c0_818] : memref<5xi1> + %out_qubit_819, %out_bit_820 = mqtopt.measure %out_qubits_817#1 + %c1_821 = arith.constant 1 : index + memref.store %out_bit_820, %alloca[%c1_821] : memref<5xi1> + %out_qubit_822, %out_bit_823 = mqtopt.measure %out_qubits_817#2 + %c2_824 = arith.constant 2 : index + memref.store %out_bit_823, %alloca[%c2_824] : memref<5xi1> + %out_qubit_825, %out_bit_826 = mqtopt.measure %out_qubits_817#3 + %c3_827 = arith.constant 3 : index + memref.store %out_bit_826, %alloca[%c3_827] : memref<5xi1> + %out_qubit_828, %out_bit_829 = mqtopt.measure %out_qubits_817#4 + %c4 = arith.constant 4 : index + memref.store %out_bit_829, %alloca[%c4] : memref<5xi1> + return + } +} From e719864a7e466d8a2dc542f925149655619ed025 Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Thu, 30 Oct 2025 16:01:08 +0100 Subject: [PATCH 25/27] Merge test files (Add multiple RUNs) --- .../{astar-routing.mlir => basics.mlir} | 23 +- .../Transpilation/naive-routing.mlir | 368 ------------------ ...ing-errors.mlir => routing-placement.mlir} | 2 +- 3 files changed, 17 insertions(+), 376 deletions(-) rename mlir/test/Dialect/MQTOpt/Transforms/Transpilation/{astar-routing.mlir => basics.mlir} (94%) delete mode 100644 mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing.mlir rename mlir/test/Dialect/MQTOpt/Transforms/Transpilation/{naive-routing-errors.mlir => routing-placement.mlir} (84%) diff --git a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/basics.mlir similarity index 94% rename from mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir rename to mlir/test/Dialect/MQTOpt/Transforms/Transpilation/basics.mlir index d82e53b418..93f72f8ddd 100644 --- a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/astar-routing.mlir +++ b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/basics.mlir @@ -8,10 +8,12 @@ // Instead of applying checks, the routing verifier pass ensures the validity of this program. -// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=identity}, route-sc{method=astar},verify-routing-sc)" -verify-diagnostics | FileCheck %s +// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=identity}, route-sc{method=naive},verify-routing-sc)" -verify-diagnostics | FileCheck --check-prefix=NAIVE %s +// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=identity}, route-sc{method=astar},verify-routing-sc)" -verify-diagnostics | FileCheck --check-prefix=ASTAR %s module { - // CHECK-LABEL: func.func @entrySABRE + // NAIVE-LABEL: func.func @entrySABRE + // ASTAR-LABEL: func.func @entrySABRE func.func @entrySABRE() attributes {passthrough = ["entry_point"]} { // @@ -71,7 +73,8 @@ module { return } - // CHECK-LABEL: func.func @entryBell + // NAIVE-LABEL: func.func @entryBell + // ASTAR-LABEL: func.func @entryBell func.func @entryBell() attributes {passthrough = ["entry_point"]} { // @@ -102,7 +105,8 @@ module { return } - // CHECK-LABEL: func.func @entryBellLoop + // NAIVE-LABEL: func.func @entryBellLoop + // ASTAR-LABEL: func.func @entryBellLoop func.func @entryBellLoop() attributes {passthrough = ["entry_point"]} { // @@ -138,7 +142,8 @@ module { return } - // CHECK-LABEL: func.func @entryGHZ + // NAIVE-LABEL: func.func @entryGHZ + // ASTAR-LABEL: func.func @entryGHZ func.func @entryGHZ() attributes {passthrough = ["entry_point"]} { // @@ -187,6 +192,8 @@ module { return } + // NAIVE-LABEL: func.func @entryBranching + // ASTAR-LABEL: func.func @entryBranching func.func @entryBranching() attributes {passthrough = ["entry_point"]} { // @@ -225,7 +232,8 @@ module { return } - // CHECK-LABEL: func.func @entryAll + // NAIVE-LABEL: func.func @entryAll + // ASTAR-LABEL: func.func @entryAll func.func @entryAll() attributes {passthrough = ["entry_point"]} { // @@ -361,7 +369,8 @@ module { return } - // CHECK-LABEL: func.func @noEntryPoint + // NAIVE-LABEL: func.func @noEntryPoint + // ASTAR-LABEL: func.func @noEntryPoint func.func @noEntryPoint() { // CHECK: %[[ANY:.*]] = mqtopt.allocQubit %q0 = mqtopt.allocQubit diff --git a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing.mlir b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing.mlir deleted file mode 100644 index adab5c1dcf..0000000000 --- a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing.mlir +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright (c) 2023 - 2025 Chair for Design Automation, TUM -// Copyright (c) 2025 Munich Quantum Software Company GmbH -// All rights reserved. -// -// SPDX-License-Identifier: MIT -// -// Licensed under the MIT License - -// Instead of applying checks, the routing verifier pass ensures the validity of this program. - -// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=random}, route-sc{method=naive},verify-routing-sc)" -verify-diagnostics | FileCheck %s - -module { - // CHECK-LABEL: func.func @entrySABRE - func.func @entrySABRE() attributes {passthrough = ["entry_point"]} { - - // - // Figure 4 in SABRE Paper "Tackling the Qubit Mapping Problem for NISQ-Era Quantum Devices". - // - // ┌───┐ - // 0: ───────■────────────┤ 8 ├ - // ┌─┴─┐ └─┬─┘ - // 1: ──■──┤ 3 ├──■─────────┼── - // ┌─┴─┐└───┘┌─┴─┐ │ - // 2: ┤ 1 ├──■──┤ 5 ├───────┼── - // └───┘┌─┴─┐└───┘ │ - // 3: ─────┤ 4 ├──■────■────■── - // └───┘ │ ┌─┴─┐ - // 4: ──■─────────┼──┤ 7 ├───── - // ┌─┴─┐ ┌─┴─┐└───┘ - // 5: ┤ 2 ├─────┤ 6 ├────────── - // └───┘ └───┘ - - %q0_0 = mqtopt.allocQubit - %q1_0 = mqtopt.allocQubit - %q2_0 = mqtopt.allocQubit - %q3_0 = mqtopt.allocQubit - %q4_0 = mqtopt.allocQubit - %q5_0 = mqtopt.allocQubit - - %q0_1 = mqtopt.h() %q0_0 : !mqtopt.Qubit - %q1_1 = mqtopt.h() %q1_0 : !mqtopt.Qubit - %q4_1 = mqtopt.h() %q4_0 : !mqtopt.Qubit - - %q0_2 = mqtopt.z() %q0_1 : !mqtopt.Qubit - %q2_1, %q1_2 = mqtopt.x() %q2_0 ctrl %q1_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g1 - %q5_1, %q4_2 = mqtopt.x() %q5_0 ctrl %q4_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g2 - - %q1_3, %q0_3 = mqtopt.x() %q1_2 ctrl %q0_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g3 - %q3_1, %q2_2 = mqtopt.x() %q3_0 ctrl %q2_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g4 - - %q2_3 = mqtopt.h() %q2_2 : !mqtopt.Qubit - %q3_2 = mqtopt.h() %q3_1 : !mqtopt.Qubit - - %q2_4, %q1_4 = mqtopt.x() %q2_3 ctrl %q1_3 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g5 - %q5_2, %q3_3 = mqtopt.x() %q5_1 ctrl %q3_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g6 - - %q3_4 = mqtopt.z() %q3_3 : !mqtopt.Qubit - - %q3_5, %q4_3 = mqtopt.x() %q3_4 ctrl %q4_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g7 - - %q0_4, %q3_6 = mqtopt.x() %q0_3 ctrl %q3_5 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g8 - - mqtopt.deallocQubit %q0_4 - mqtopt.deallocQubit %q1_4 - mqtopt.deallocQubit %q2_4 - mqtopt.deallocQubit %q3_6 - mqtopt.deallocQubit %q4_3 - mqtopt.deallocQubit %q5_2 - - return - } - - // CHECK-LABEL: func.func @entryBell - func.func @entryBell() attributes {passthrough = ["entry_point"]} { - - // - // The bell state. - // - // This test shows that alloc's don't have to be grouped. - // - // ┌───┐ - // 0:─┤ H ├────■─── - // └───┘ ┌─┴─┐ - // 1:────────┤ X ├─ - // └───┘ - - %q0_0 = mqtopt.allocQubit - %q0_1 = mqtopt.h() %q0_0 : !mqtopt.Qubit - - %q1_0 = mqtopt.allocQubit - %q1_1, %q0_2 = mqtopt.x() %q1_0 ctrl %q0_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_3, %m0_0 = "mqtopt.measure"(%q0_2) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_2, %m1_0 = "mqtopt.measure"(%q1_1) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - mqtopt.deallocQubit %q0_3 - mqtopt.deallocQubit %q1_2 - - return - } - - // CHECK-LABEL: func.func @entryBellLoop - func.func @entryBellLoop() attributes {passthrough = ["entry_point"]} { - - // - // Bell in a loop. - // - // This test shows that the routing algorithm can handle - // alloc statements inside the loop body. - // - // ┌ ┌───┐ ┐^1000 - // │ 0:─┤ H ├────■─── │ - // │ └───┘ ┌─┴─┐ │ - // │ 1:────────┤ X ├─ │ - // └ └───┘ ┘ - - %lb = index.constant 0 - %ub = index.constant 1000 - %step = index.constant 1 - - scf.for %iv = %lb to %ub step %step { - %q0_0 = mqtopt.allocQubit - %q1_0 = mqtopt.allocQubit - - %q0_1 = mqtopt.h() %q0_0 : !mqtopt.Qubit - %q1_1, %q0_2 = mqtopt.x() %q1_0 ctrl %q0_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_3, %m0_0 = "mqtopt.measure"(%q0_2) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_2, %m1_0 = "mqtopt.measure"(%q1_1) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - mqtopt.deallocQubit %q0_3 - mqtopt.deallocQubit %q1_2 - } - - return - } - - // CHECK-LABEL: func.func @entryGHZ - func.func @entryGHZ() attributes {passthrough = ["entry_point"]} { - - // - // GHZ in a loop. - // - // This test shows that the routing algorithm can handle - // loop-carried qubit values. - // - // ┌ ┌───┐ ┐^1000 - // │ 0:─┤ H ├────■─────────── │ - // │ └───┘ ┌─┴─┐ │ - // │ 1:────────┤ X ├────■──── │ - // │ └───┘ ┌─┴─┐ │ - // │ 2:───────────────┤ X ├── │ - // └ └───┘ ┘ - - %lb = index.constant 0 - %ub = index.constant 1000 - %step = index.constant 1 - - %q0_0 = mqtopt.allocQubit - %q1_0 = mqtopt.allocQubit - %q2_0 = mqtopt.allocQubit - - %q0_1, %q1_1, %q2_1 = scf.for %iv = %lb to %ub step %step - iter_args(%q0_i_0 = %q0_0, %q1_i_0 = %q1_0, %q2_i_0 = %q2_0) -> (!mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit) { - %q0_i_1 = "mqtopt.reset"(%q0_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - %q1_i_1 = "mqtopt.reset"(%q1_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - %q2_i_1 = "mqtopt.reset"(%q2_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - - %q0_i_2 = mqtopt.h() %q0_i_1 : !mqtopt.Qubit - %q1_i_2, %q0_i_3 = mqtopt.x() %q1_i_1 ctrl %q0_i_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - %q2_i_2, %q1_i_3 = mqtopt.x() %q2_i_1 ctrl %q1_i_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_i_4, %m0 = "mqtopt.measure"(%q0_i_3) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_i_4, %m1 = "mqtopt.measure"(%q1_i_3) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q2_i_3, %m2 = "mqtopt.measure"(%q2_i_2) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - scf.yield %q0_i_4, %q1_i_4, %q2_i_3 : !mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit - } - - mqtopt.deallocQubit %q0_1 - mqtopt.deallocQubit %q1_1 - mqtopt.deallocQubit %q2_1 - - return - } - - func.func @entryBranching() attributes {passthrough = ["entry_point"]} { - - // - // This test shows that the routing algorithm can handle - // classical feedforward and control flow. - // - // ┌───┐ ┌───┐ - // 0:─┤ H ├──┤ M ├─────────■─── - // └───┘ └─╦─┘ ┌───┐ ┌─┴─┐ - // 1:──────────║───┤ X ├─┤ X ├─ - // ║ └─┬─┘ └───┘ - // m:══════════▼═════●═════════ - // - - %q0_0 = mqtopt.allocQubit - %q1_0 = mqtopt.allocQubit - - %q0_1 = mqtopt.h() %q0_0 : !mqtopt.Qubit - %q0_2, %m = "mqtopt.measure"(%q0_1) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - %q0_3, %q1_2 = scf.if %m -> (!mqtopt.Qubit, !mqtopt.Qubit) { - %q1_1 = mqtopt.x() %q1_0 : !mqtopt.Qubit - %q1_2, %q0_3 = mqtopt.x() %q1_1 ctrl %q0_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - scf.yield %q0_3, %q1_2 : !mqtopt.Qubit, !mqtopt.Qubit - } else { - %q1_1 = mqtopt.i() %q1_0 : !mqtopt.Qubit - %q1_2, %q0_3 = mqtopt.x() %q1_1 ctrl %q0_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - scf.yield %q0_3, %q1_2 : !mqtopt.Qubit, !mqtopt.Qubit - } - - mqtopt.deallocQubit %q0_3 - mqtopt.deallocQubit %q1_2 - - return - } - - // CHECK-LABEL: func.func @entryAll - func.func @entryAll() attributes {passthrough = ["entry_point"]} { - - // - // All of the above quantum computations in a single entry point. - // This test shows that the algorithm can handle multiple computations - // in a single function. - - // - // SABRE - - %q0_0 = mqtopt.allocQubit - %q1_0 = mqtopt.allocQubit - %q2_0 = mqtopt.allocQubit - %q3_0 = mqtopt.allocQubit - %q4_0 = mqtopt.allocQubit - %q5_0 = mqtopt.allocQubit - - %q0_1 = mqtopt.h() %q0_0 : !mqtopt.Qubit - %q1_1 = mqtopt.h() %q1_0 : !mqtopt.Qubit - %q4_1 = mqtopt.h() %q4_0 : !mqtopt.Qubit - - %q0_2 = mqtopt.z() %q0_1 : !mqtopt.Qubit - %q2_1, %q1_2 = mqtopt.x() %q2_0 ctrl %q1_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g1 - %q5_1, %q4_2 = mqtopt.x() %q5_0 ctrl %q4_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g2 - - %q1_3, %q0_3 = mqtopt.x() %q1_2 ctrl %q0_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g3 - %q3_1, %q2_2 = mqtopt.x() %q3_0 ctrl %q2_1 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g4 - - %q2_3 = mqtopt.h() %q2_2 : !mqtopt.Qubit - %q3_2 = mqtopt.h() %q3_1 : !mqtopt.Qubit - - %q2_4, %q1_4 = mqtopt.x() %q2_3 ctrl %q1_3 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g5 - %q5_2, %q3_3 = mqtopt.x() %q5_1 ctrl %q3_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g6 - - %q3_4 = mqtopt.z() %q3_3 : !mqtopt.Qubit - - %q3_5, %q4_3 = mqtopt.x() %q3_4 ctrl %q4_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g7 - - %q0_4, %q3_6 = mqtopt.x() %q0_3 ctrl %q3_5 : !mqtopt.Qubit ctrl !mqtopt.Qubit // g8 - - mqtopt.deallocQubit %q0_4 - mqtopt.deallocQubit %q1_4 - mqtopt.deallocQubit %q2_4 - mqtopt.deallocQubit %q3_6 - mqtopt.deallocQubit %q4_3 - mqtopt.deallocQubit %q5_2 - - // - // The bell state. - - %q0_0_bell = mqtopt.allocQubit - %q0_1_bell = mqtopt.h() %q0_0_bell : !mqtopt.Qubit - - %q1_0_bell = mqtopt.allocQubit - %q1_1_bell, %q0_2_bell = mqtopt.x() %q1_0_bell ctrl %q0_1_bell : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_3_bell, %m0_0_bell = "mqtopt.measure"(%q0_2_bell) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_2_bell, %m1_0_bell = "mqtopt.measure"(%q1_1_bell) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - mqtopt.deallocQubit %q0_3_bell - mqtopt.deallocQubit %q1_2_bell - - // - // Bell in a loop. - - %lb = index.constant 0 - %ub = index.constant 1000 - %step = index.constant 1 - - scf.for %iv = %lb to %ub step %step { - %q0_0_bell1000 = mqtopt.allocQubit - %q1_0_bell1000 = mqtopt.allocQubit - - %q0_1_bell1000 = mqtopt.h() %q0_0_bell1000 : !mqtopt.Qubit - %q1_1_bell1000, %q0_2_bell1000 = mqtopt.x() %q1_0_bell1000 ctrl %q0_1_bell1000 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_3_bell1000, %m0_0_bell1000 = "mqtopt.measure"(%q0_2_bell1000) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_2_bell1000, %m1_0_bell1000 = "mqtopt.measure"(%q1_1_bell1000) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - mqtopt.deallocQubit %q0_3_bell1000 - mqtopt.deallocQubit %q1_2_bell1000 - } - - // - // GHZ in a loop. - - %q0_0_ghz1000 = mqtopt.allocQubit - %q1_0_ghz1000 = mqtopt.allocQubit - %q2_0_ghz1000 = mqtopt.allocQubit - - %q0_1_ghz1000, %q1_1_ghz1000, %q2_1_ghz1000 = scf.for %iv = %lb to %ub step %step - iter_args(%q0_i_0 = %q0_0_ghz1000, %q1_i_0 = %q1_0_ghz1000, %q2_i_0 = %q2_0_ghz1000) -> (!mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit) { - %q0_i_1 = "mqtopt.reset"(%q0_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - %q1_i_1 = "mqtopt.reset"(%q1_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - %q2_i_1 = "mqtopt.reset"(%q2_i_0) : (!mqtopt.Qubit) -> !mqtopt.Qubit - - %q0_i_2 = mqtopt.h() %q0_i_1 : !mqtopt.Qubit - %q1_i_2, %q0_i_3 = mqtopt.x() %q1_i_1 ctrl %q0_i_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - %q2_i_2, %q1_i_3 = mqtopt.x() %q2_i_1 ctrl %q1_i_2 : !mqtopt.Qubit ctrl !mqtopt.Qubit - - %q0_i_4, %m0 = "mqtopt.measure"(%q0_i_3) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q1_i_4, %m1 = "mqtopt.measure"(%q1_i_3) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - %q2_i_3, %m2 = "mqtopt.measure"(%q2_i_2) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - scf.yield %q0_i_4, %q1_i_4, %q2_i_3 : !mqtopt.Qubit, !mqtopt.Qubit, !mqtopt.Qubit - } - - mqtopt.deallocQubit %q0_1_ghz1000 - mqtopt.deallocQubit %q1_1_ghz1000 - mqtopt.deallocQubit %q2_1_ghz1000 - - %q0_0_branch = mqtopt.allocQubit - %q1_0_branch = mqtopt.allocQubit - - %q0_1_branch = mqtopt.h() %q0_0_branch : !mqtopt.Qubit - %q0_2_branch, %m = "mqtopt.measure"(%q0_1_branch) : (!mqtopt.Qubit) -> (!mqtopt.Qubit, i1) - - %q0_3_branch, %q1_2_branch = scf.if %m -> (!mqtopt.Qubit, !mqtopt.Qubit) { - %q1_1_branch = mqtopt.x() %q1_0_branch : !mqtopt.Qubit - %q1_2_branch, %q0_3_branch = mqtopt.x() %q1_1_branch ctrl %q0_2_branch : !mqtopt.Qubit ctrl !mqtopt.Qubit - - scf.yield %q0_3_branch, %q1_2_branch : !mqtopt.Qubit, !mqtopt.Qubit - } else { - %q1_1_branch = mqtopt.i() %q1_0_branch: !mqtopt.Qubit - %q1_2_branch, %q0_3_branch = mqtopt.x() %q1_1_branch ctrl %q0_2_branch : !mqtopt.Qubit ctrl !mqtopt.Qubit - - scf.yield %q0_3_branch, %q1_2_branch : !mqtopt.Qubit, !mqtopt.Qubit - } - - mqtopt.deallocQubit %q0_3_branch - mqtopt.deallocQubit %q1_2_branch - - return - } - - // CHECK-LABEL: func.func @noEntryPoint - func.func @noEntryPoint() { - // CHECK: %[[ANY:.*]] = mqtopt.allocQubit - %q0 = mqtopt.allocQubit - return - } -} diff --git a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing-errors.mlir b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/routing-placement.mlir similarity index 84% rename from mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing-errors.mlir rename to mlir/test/Dialect/MQTOpt/Transforms/Transpilation/routing-placement.mlir index 6c8b150a78..7246163a76 100644 --- a/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/naive-routing-errors.mlir +++ b/mlir/test/Dialect/MQTOpt/Transforms/Transpilation/routing-placement.mlir @@ -6,7 +6,7 @@ // // Licensed under the MIT License -// RUN: quantum-opt %s -split-input-file --pass-pipeline="builtin.module(placement-sc{strategy=identity},route-sc{method=naive},verify-routing-sc)" -verify-diagnostics +// RUN: quantum-opt %s -split-input-file --placement-sc="strategy=identity" -verify-diagnostics module { From 1c8fd844ee9264f0682b815a23154589bc81940b Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Fri, 31 Oct 2025 08:12:58 +0100 Subject: [PATCH 26/27] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 672b4a3eb9..e55cb8f02b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Added -- ✨ Add A\*-search-based routing algorithm to MLIR transpilation routines ([#1237]) ([**@MatthiasReumann**]) +- ✨ Add A\*-search-based routing algorithm to MLIR transpilation routines ([#1237], [#1271]) ([**@MatthiasReumann**]) ### Fixed @@ -219,6 +219,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#1271]: https://github.com/munich-quantum-toolkit/core/pull/1271 [#1237]: https://github.com/munich-quantum-toolkit/core/pull/1237 [#1269]: https://github.com/munich-quantum-toolkit/core/pull/1269 [#1263]: https://github.com/munich-quantum-toolkit/core/pull/1263 From 2db8b1dc6029cb74116a799c4fc1dc0356fbaace Mon Sep 17 00:00:00 2001 From: Matthias Reumann Date: Fri, 31 Oct 2025 08:20:05 +0100 Subject: [PATCH 27/27] Sort CHANGELOG.md PR links --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac27748abc..b6d395c645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -220,13 +220,13 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool -[#1271]: https://github.com/munich-quantum-toolkit/core/pull/1271 [#1276]: https://github.com/munich-quantum-toolkit/core/pull/1276 -[#1237]: https://github.com/munich-quantum-toolkit/core/pull/1237 +[#1271]: https://github.com/munich-quantum-toolkit/core/pull/1271 [#1269]: https://github.com/munich-quantum-toolkit/core/pull/1269 [#1263]: https://github.com/munich-quantum-toolkit/core/pull/1263 [#1247]: https://github.com/munich-quantum-toolkit/core/pull/1247 [#1246]: https://github.com/munich-quantum-toolkit/core/pull/1246 +[#1237]: https://github.com/munich-quantum-toolkit/core/pull/1237 [#1236]: https://github.com/munich-quantum-toolkit/core/pull/1236 [#1235]: https://github.com/munich-quantum-toolkit/core/pull/1235 [#1232]: https://github.com/munich-quantum-toolkit/core/pull/1232 @@ -234,8 +234,8 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool [#1223]: https://github.com/munich-quantum-toolkit/core/pull/1223 [#1211]: https://github.com/munich-quantum-toolkit/core/pull/1211 [#1210]: https://github.com/munich-quantum-toolkit/core/pull/1210 -[#1207]: https://github.com/munich-quantum-toolkit/core/pull/1207 [#1209]: https://github.com/munich-quantum-toolkit/core/pull/1209 +[#1207]: https://github.com/munich-quantum-toolkit/core/pull/1207 [#1186]: https://github.com/munich-quantum-toolkit/core/pull/1186 [#1181]: https://github.com/munich-quantum-toolkit/core/pull/1181 [#1180]: https://github.com/munich-quantum-toolkit/core/pull/1180