diff --git a/CHANGELOG.md b/CHANGELOG.md index a5d03dfcfb..87cc4592aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,8 +91,8 @@ releases may include breaking changes. circuits to compiler-target topologies while preserving target site IDs and materializing routing workspace on demand ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588], [#1600], [#1664], [#1709], [#1716], [#1748], [#1805], - [#1870], [#1904], [#1911], [#1951], [#1997], [#2016]) ([**@MatthiasReumann**], - [**@burgholzer**]) + [#1870], [#1904], [#1911], [#1951], [#1997], [#2016], [#2060]) + ([**@MatthiasReumann**], [**@burgholzer**]) - ✨ Add a pass for qubit reuse in quantum programs, as well as related auxiliary passes and patterns ([#1705], [#1755], [#1756], [#1923], [#1924]) ([**@DRovara**], [**@burgholzer**]) @@ -737,6 +737,7 @@ for previous changelogs._ +[#2060]: https://github.com/munich-quantum-toolkit/core/pull/2060 [#2058]: https://github.com/munich-quantum-toolkit/core/pull/2058 [#2030]: https://github.com/munich-quantum-toolkit/core/pull/2030 [#2042]: https://github.com/munich-quantum-toolkit/core/pull/2042 diff --git a/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp b/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp index b258c5b1ec..bf3a8c10e7 100644 --- a/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp +++ b/mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp @@ -979,28 +979,36 @@ struct MappingPass : impl::MappingPassBase { return {layouts[0], std::move(swaps[0]), std::move(swaps[1])}; } - /// Return the "average" layout by computing the borda count, where each - /// layout is a voter and each hardware index counts as a candidate. One vote - /// is the order (the permutation) of program-to-hardware indices. - template static Layout vote(Range layouts) { + /// Compute a routing-friendly layout compromise between a range of layouts. + /// Using the first layout of the range as an anchor, the function repeatedly + /// nudges the current layout towards the next one using happy SWAP chains. + /// Inspired by SABRE and to reduce ordering bias, the function performs an + /// additional backward pass. + template + Layout driveby(Range layouts, const size_t niterations = 1) { assert(!layouts.empty() && "expected at least one layout"); - const auto ncandidates = (*layouts.begin()).nqubits(); - SmallVector scores(ncandidates, 0); - for (const Layout& layout : layouts) { - for (const auto [rank, hw] : enumerate(layout.getProgramToHardware())) { - scores[hw] += ncandidates - rank - 1; + FGraph f(*target); + Layout curr(*(layouts.begin())); + + // Nudge curr towards target by applying a happy SWAP chain. + const auto merge = [&](const Layout& target) { + f.reset(); + f.construct(curr, target); + if (const auto happy = f.findHappySWAPChain()) { + for (const auto& swap : *happy) { + curr.swap(swap.first, swap.second); + } } - } + }; - auto mapping = llvm::to_vector(llvm::seq(ncandidates)); - llvm::sort(mapping, [&](const size_t lhs, const size_t rhs) { - return scores[lhs] != scores[rhs] - ? scores[lhs] > scores[rhs] - : lhs < rhs; // Ensure order on borda equality. - }); + // Perform multiple rounds of forward and backward drive-by's. + for (size_t i = 0; i < niterations; ++i) { + for_each(drop_begin(layouts), merge); + for_each(drop_begin(reverse(layouts)), merge); + } - return Layout::fromMapping(mapping); + return curr; } /// Skip to the end of the two-qubit block for both wire iterators, where @@ -1466,15 +1474,15 @@ struct MappingPass : impl::MappingPassBase { return convergedLayout; }) .template Case([&](IndexSwitchOp) { - auto winner = vote(map_range( + auto compromise = driveby(map_range( children, [](const RoutingBundle& b) -> const Layout& { return b.layout; })); for (RoutingBundle& child : children) { - const auto swaps = restore(child.layout, winner); + const auto swaps = restore(child.layout, compromise); insertSWAPs(swaps, child, totalStats, rewriter); } - return winner; + return compromise; }); if constexpr (Mode == RoutingMode::Hot) { diff --git a/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp b/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp index 76a797190c..ffce533474 100644 --- a/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp +++ b/mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp @@ -1663,7 +1663,7 @@ TEST_P(MappingPassTest, MapIndexSwitchUsesVotedLayout) { m->walk([&](SWAPOp) { ++numSwaps; }); // The three routed cases agree on the voted exit layout; only the default // case must be restored to it. Restoring every case to the parent needs 12. - EXPECT_EQ(numSwaps, 4UL); + EXPECT_EQ(numSwaps, 6UL); } TEST_P(MappingPassTest, MapPaddedCXCZGrid) {