Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel

- ✨ Add Sampler and Estimator Primitives to the QDMI-Qiskit Interface ([#1507]) ([**@marcelwa**])
- ✨ Add conversions between Jeff and QCO ([#1479], [#1548], [#1565]) ([**@denialhaag**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583]) ([**@MatthiasReumann**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588]) ([**@MatthiasReumann**])
- ✨ Add initial infrastructure for new QC and QCO MLIR dialects
([#1264], [#1330], [#1402], [#1428], [#1430], [#1436], [#1443], [#1446], [#1464], [#1465], [#1470], [#1471], [#1472], [#1474], [#1475], [#1506], [#1510], [#1513], [#1521], [#1542], [#1548], [#1550], [#1554], [#1570], [#1572], [#1573])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])
Expand Down Expand Up @@ -333,6 +333,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

<!-- PR links -->

[#1588]: https://github.com/munich-quantum-toolkit/core/pull/1588
[#1583]: https://github.com/munich-quantum-toolkit/core/pull/1583
[#1581]: https://github.com/munich-quantum-toolkit/core/pull/1581
[#1573]: https://github.com/munich-quantum-toolkit/core/pull/1573
Expand Down
5 changes: 2 additions & 3 deletions mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ def MappingPass : Pass<"place-and-route", "mlir::ModuleOp"> {
made during that traversal. By performing multiple traversals, the pass can iteratively refine the mapping and
potentially find a more optimal solution. This is behavior is controlled by the `niterations` parameter.

The pass option `ntrials` determines how many random initial layouts the pass explores. Per default, the pass always
explores the identity layout. If compiled with multi-threading on, these trials will be executed in parallel.
The pass option `ntrials` determines how many random initial layouts the pass explores. If compiled with multi-threading on, these trials will be executed in parallel.
}];
let options = [Option<"nlookahead", "nlookahead", "std::size_t", "1",
"The number of lookahead steps.">,
Expand All @@ -66,7 +65,7 @@ def MappingPass : Pass<"place-and-route", "mlir::ModuleOp"> {
"improve the initial layout.">,
Option<"ntrials", "ntrials", "std::size_t", "4",
"The number of (possibly parallel) random trials of "
"the forwards and backwards mechanism.">,
"the forwards and backwards mechanism. Must be > 0.">,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Option<"seed", "seed", "std::size_t", "42",
"A seed used for randomization.">];
let statistics = [Statistic<"numSwaps", "num-inserted-swaps",
Expand Down
72 changes: 57 additions & 15 deletions mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {
*/
enum class Direction : std::uint8_t { Forward, Backward };

struct LayoutInfo;
class LayoutInfo;

/**
* @brief A qubit layout that maps program and hardware indices without
Expand Down Expand Up @@ -207,7 +207,7 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {
SmallVector<IndexType> hardwareToProgram_;

private:
friend struct MappingPass::LayoutInfo;
friend class MappingPass::LayoutInfo;

Layout() = default;
explicit Layout(const std::size_t nqubits)
Expand Down Expand Up @@ -388,12 +388,10 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {

const auto [ltr, rtl] = computeBidirectionalLayers(dynQubits);

// Create trials. Currently this includes the identity layout and
// `ntrials` many random layouts.
// Create trials. Currently this includes `ntrials` many random layouts.

SmallVector<Layout> trials;
trials.reserve(1 + this->ntrials);
trials.emplace_back(Layout::identity(arch.nqubits()));
trials.reserve(this->ntrials);
for (std::size_t i = 0; i < this->ntrials; ++i) {
trials.emplace_back(Layout::random(arch.nqubits(), rng()));
Comment thread
MatthiasReumann marked this conversation as resolved.
}
Expand Down Expand Up @@ -609,6 +607,56 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {
map_range(qubits, [](auto q) { return WireIterator(q); }));
}

/**
* @returns true if the wire iterator has not reached the end (Forward) or the
* start (Backward) of the wire.
*/
template <Direction d> static bool proceedOnWire(const WireIterator& it) {
if constexpr (d == Direction::Forward) {
return it != std::default_sentinel;
} else {
return !isa<AllocOp>(it.operation());
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/**
* @brief Skip the next two-qubit block of two wires.
* @details Advances each of the two wire iterators until a two-qubit op is
* found. If the ops match, repeat this process. Otherwise, stop.
*/
template <Direction d>
static void skipTwoQubitBlock(WireIterator& first, WireIterator& second) {
constexpr auto step = d == Direction::Forward ? 1 : -1;

const auto advanceUntilTwoQubitOp = [&](WireIterator& it) {
while (proceedOnWire<d>(it)) {
if (auto op = dyn_cast<UnitaryOpInterface>(it.operation())) {
if (op.getNumQubits() > 1) {
break;
}
}

std::ranges::advance(it, step);
}
};

while (true) {
advanceUntilTwoQubitOp(first);
advanceUntilTwoQubitOp(second);

if (!proceedOnWire<d>(first) || !proceedOnWire<d>(second)) {
break;
}

if (first.operation() != second.operation()) {
break;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

std::ranges::advance(first, step);
std::ranges::advance(second, step);
}
}

/**
* @brief Collect the layers of independently executable two-qubit gates of a
* circuit.
Expand All @@ -623,22 +671,14 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {
template <Direction d>
static LayeringResult collectLayers(MutableArrayRef<WireIterator> wires) {
constexpr auto step = d == Direction::Forward ? 1 : -1;
const auto shouldContinue = [](const WireIterator& it) {
if constexpr (d == Direction::Forward) {
return it != std::default_sentinel;
} else {
return !isa<AllocOp>(it.operation());
}
};

LayeringResult result;

DenseMap<UnitaryOpInterface, std::size_t> visited;
while (true) {
Layer layer{};
Operation* anchor = nullptr;
for (const auto [index, it] : enumerate(wires)) {
while (shouldContinue(it)) {
while (proceedOnWire<d>(it)) {
const auto res =
TypeSwitch<Operation*, WalkResult>(it.operation())
.Case<BarrierOp>([&](auto) {
Expand All @@ -661,6 +701,8 @@ struct MappingPass : impl::MappingPassBase<MappingPass> {
std::ranges::advance(wires[index], step);
std::ranges::advance(wires[otherIndex], step);

skipTwoQubitBlock<d>(wires[index], wires[otherIndex]);

if (anchor == nullptr ||
op->isBeforeInBlock(anchor)) {
anchor = op;
Expand Down
Comment thread
burgholzer marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ TEST_P(MappingPassTest, Sabre) {
builder.cx(q4, q5);

builder.cx(q0, q1);

builder.h(q0);
builder.y(q1);
builder.cx(q0, q1);

builder.cx(q2, q3);

builder.h(q2);
Expand Down
Loading