Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f1140e1
Add "Layer" data structure
MatthiasReumann Mar 30, 2026
2fad455
Add split layer logic
MatthiasReumann Mar 30, 2026
391a27b
Add "fit" initial layout strategy
MatthiasReumann Mar 31, 2026
336f4dc
Add partitioning
MatthiasReumann Apr 1, 2026
f646661
Add fullLayers to unit test
MatthiasReumann Apr 1, 2026
43c5cd0
Fix Pass Option Description
MatthiasReumann Apr 1, 2026
6b06f38
Update CHANGELOG..md
MatthiasReumann Apr 1, 2026
15c3862
Fix linting issues
MatthiasReumann Apr 1, 2026
2e2b290
Apply bunny suggestions
MatthiasReumann Apr 1, 2026
d1a03c0
Merge branch 'main' into enh/improved-layering
MatthiasReumann Apr 1, 2026
820d9ff
Remove unused imports
MatthiasReumann Apr 1, 2026
6623145
Update pass option descriptions
MatthiasReumann Apr 1, 2026
dfdb923
Use entry point for executability check
MatthiasReumann Apr 1, 2026
eaab159
Update function description
MatthiasReumann Apr 1, 2026
c262d5f
Merge branch 'refs/heads/main' into enh/improved-layering
burgholzer Apr 1, 2026
ab899f3
🎨 Reduce includes through forward declaration
burgholzer Apr 1, 2026
7252d16
🔀 Fixes after merge
burgholzer Apr 1, 2026
c0300a0
🎨 Miscelaneous code quality optimizations
burgholzer Apr 1, 2026
8f08084
Add first walkLayer draft
MatthiasReumann Apr 2, 2026
ad49626
Improve naming
MatthiasReumann Apr 2, 2026
806fe1a
Improve walkLayer API
MatthiasReumann Apr 3, 2026
54415f3
Add convienience method
MatthiasReumann Apr 3, 2026
9db964d
Add function signature
MatthiasReumann Apr 3, 2026
726a69b
Improve API
MatthiasReumann Apr 3, 2026
bce9979
Add walkCircuitGraph driver
MatthiasReumann Apr 8, 2026
fe191e2
Clean up functions
MatthiasReumann Apr 8, 2026
d3ea059
Merge branch 'main' into enh/improved-layering
MatthiasReumann Apr 8, 2026
ef56ec9
Use llvm::priority_queue
MatthiasReumann Apr 8, 2026
3c620d4
Make tensors "work"
MatthiasReumann Apr 8, 2026
1132b30
Fix tests
MatthiasReumann Apr 8, 2026
8132ff7
Add walkQubitBlock and clean up a bit
MatthiasReumann Apr 8, 2026
f028b0a
Fix segmentation fault
MatthiasReumann Apr 9, 2026
6dd34df
Fix another segmentation fault
MatthiasReumann Apr 9, 2026
25ca7a3
Fix linting
MatthiasReumann Apr 9, 2026
a87443a
Remove mapping pass from compiler pipeline
MatthiasReumann Apr 9, 2026
46e36fe
Remove layout info
MatthiasReumann Apr 9, 2026
fded839
Fix linting
MatthiasReumann Apr 9, 2026
972fc9e
Implement partial solution A*
MatthiasReumann Apr 9, 2026
b1c5eb8
Final linting issues
MatthiasReumann Apr 9, 2026
0cccb05
Remove enumerations
MatthiasReumann Apr 10, 2026
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], [#1588]) ([**@MatthiasReumann**])
- ✨ Add a `place-and-route` pass for mapping circuits to architectures with restricted topologies ([#1537], [#1547], [#1568], [#1581], [#1583], [#1588], [#1600]) ([**@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], [#1567], [#1569], [#1570], [#1572], [#1573], [#1580], [#1602], [#1623])
([**@burgholzer**], [**@denialhaag**], [**@taminob**], [**@DRovara**], [**@li-mingbao**], [**@Ectras**], [**@MatthiasReumann**], [**@simon1hofmann**])
Expand Down Expand Up @@ -337,6 +337,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool

[#1623]: https://github.com/munich-quantum-toolkit/core/pull/1623
[#1602]: https://github.com/munich-quantum-toolkit/core/pull/1602
[#1600]: https://github.com/munich-quantum-toolkit/core/pull/1600
[#1596]: https://github.com/munich-quantum-toolkit/core/pull/1596
[#1593]: https://github.com/munich-quantum-toolkit/core/pull/1593
[#1588]: https://github.com/munich-quantum-toolkit/core/pull/1588
Expand Down
27 changes: 27 additions & 0 deletions mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
* All rights reserved.
*
* SPDX-License-Identifier: MIT
*
* Licensed under the MIT License
*/

#pragma once

#include <llvm/Support/LogicalResult.h>
#include <mlir/IR/Region.h>

namespace mlir::qco {

// Forward declaration
class Architecture;

/**
* @brief Verifies if all two-qubit gates within the region are executable on
* the targeted architecture. Expects static qubits only.
* @returns llvm::success() if executable, llvm::failure() otherwise.
*/
LogicalResult isExecutable(Region& region, const Architecture& arch);
} // namespace mlir::qco
2 changes: 1 addition & 1 deletion mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def MappingPass : Pass<"place-and-route", "mlir::ModuleOp"> {
Option<"niterations", "niterations", "std::size_t", "2",
"The number of forwards and backwards traversal to "
"improve the initial layout.">,
Option<"ntrials", "ntrials", "std::size_t", "4",
Option<"ntrials", "ntrials", "std::size_t", "1",
"The number of (possibly parallel) random trials of "
"the forwards and backwards mechanism. Must be > 0.">,
Option<"seed", "seed", "std::size_t", "42",
Expand Down
132 changes: 82 additions & 50 deletions mlir/include/mlir/Dialect/QCO/Utils/Drivers.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,101 +11,133 @@
#pragma once

#include "mlir/Dialect/QCO/IR/QCODialect.h"
#include "mlir/Dialect/QCO/IR/QCOOps.h"
#include "mlir/Dialect/QCO/IR/QCOInterfaces.h"
#include "mlir/Dialect/QCO/Utils/WireIterator.h"

#include <llvm/ADT/ADL.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/TypeSwitch.h>
#include <llvm/Support/Debug.h>
#include <mlir/IR/Region.h>
#include <mlir/IR/Value.h>
#include <mlir/Support/LLVM.h>
#include <mlir/Support/WalkResult.h>

#include <cstddef>
#include <utility>

namespace mlir::qco {

/**
* @brief Specifies the layering direction.
*/
enum class WalkDirection : bool { Forward, Backward };

class Qubits {
public:
/**
* @brief Specifies the qubit "location" (hardware or program).
* @brief Add qubit with automatically assigned index.
*/
enum class QubitLocation : std::uint8_t { Hardware, Program };
void add(TypedValue<QubitType> q);

public:
/**
* @brief Add qubit with automatically assigned dynamic index.
* @brief Add qubit with index.
*/
[[maybe_unused]] void add(TypedValue<QubitType> q);
void add(TypedValue<QubitType> q, std::size_t index);

/**
* @brief Add qubit with static index.
* @brief Remap the qubit value from prev to next.
*/
void add(TypedValue<QubitType> q, std::size_t hw);
void remap(TypedValue<QubitType> prev, TypedValue<QubitType> next,
const WalkDirection& direction);

/**
* @brief Remap the qubit value from prev to next.
* @brief Remap all input qubits of the unitary to its outputs.
*/
void remap(TypedValue<QubitType> prev, TypedValue<QubitType> next);
void remap(UnitaryOpInterface op, const WalkDirection& direction);

/**
* @brief Remove the qubit value.
*/
void remove(TypedValue<QubitType> q);

/**
* @returns the qubit value assigned to a program index.
* @returns the qubit value assigned to a index.
*/
[[maybe_unused]] TypedValue<QubitType> getProgramQubit(std::size_t index);
[[nodiscard]] TypedValue<QubitType> getQubit(std::size_t index) const;

/**
* @returns the qubit value assigned to a hardware index.
* @returns the index assigned to the given qubit value.
*/
TypedValue<QubitType> getHardwareQubit(std::size_t index);
[[nodiscard]] std::size_t getIndex(TypedValue<QubitType> q) const;

private:
DenseMap<std::size_t, TypedValue<QubitType>> programToValue_;
DenseMap<std::size_t, TypedValue<QubitType>> hardwareToValue_;
DenseMap<TypedValue<QubitType>, std::pair<QubitLocation, std::size_t>>
valueToIndex_;
DenseMap<std::size_t, TypedValue<QubitType>> indexToValue_;
DenseMap<TypedValue<QubitType>, std::size_t> valueToIndex_;
};

using WalkUnitFn = function_ref<WalkResult(Operation*, const Qubits&)>;

/**
* @brief Perform top-down non-recursive walk of all operations within a
* region and apply callback function.
* @details The signature of the callback function is:
* @details
* The signature of the callback function is:
*
* (Operation*, Qubits& q) -> WalkResult
*
* where the Qubits object tracks the front of qubit SSA values.
*
* @param region The targeted region.
* @param fn The callback function.
*/
template <typename Fn> void walkUnit(Region& region, Fn&& fn) {
const auto ffn = std::forward<Fn>(fn);

Qubits qubits;
for (Operation& curr : region.getOps()) {
if (ffn(&curr, qubits).wasInterrupted()) {
break;
};

TypeSwitch<Operation*>(&curr)
.template Case<StaticOp>(
[&](StaticOp op) { qubits.add(op.getQubit(), op.getIndex()); })
.template Case<AllocOp>([&](AllocOp op) { qubits.add(op.getResult()); })
.template Case<UnitaryOpInterface>([&](UnitaryOpInterface op) {
for (const auto& [prevV, nextV] :
llvm::zip(op.getInputQubits(), op.getOutputQubits())) {
const auto prevQ = cast<TypedValue<QubitType>>(prevV);
const auto nextQ = cast<TypedValue<QubitType>>(nextV);
qubits.remap(prevQ, nextQ);
}
})
.template Case<ResetOp>([&](ResetOp op) {
qubits.remap(op.getQubitIn(), op.getQubitOut());
})
.template Case<MeasureOp>([&](MeasureOp op) {
qubits.remap(op.getQubitIn(), op.getQubitOut());
})
.template Case<SinkOp>(
[&](SinkOp op) { qubits.remove(op.getQubit()); });
}
}
void walkUnit(Region& region, WalkUnitFn fn);

using WalkQubitPairBlockFn =
function_ref<void(const WireIterator&, const WireIterator&)>;

/**
* @brief Walk the block spanned by a pair of qubit 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.
*
* Expects wires.size() == 2.
*/
void walkQubitPairBlock(MutableArrayRef<WireIterator> wires,
WalkDirection direction, WalkQubitPairBlockFn fn);

using ReleasedIterators = SmallVector<WireIterator*, 8>;
using FrontArrayRef = ArrayRef<SmallVector<WireIterator*>>;
using WalkCircuitGraphFn =
function_ref<WalkResult(FrontArrayRef, ReleasedIterators&)>;

/**
* @brief Walk the graph-like circuit IR of QCO dialect programs.
* @details
* Depending on the template parameter, the function collects the
* layers in forward or backward direction, respectively. Towards that end,
* the function traverses the def-use chain of each qubit until a two-qubit
* gate is found. If a two-qubit gate is visited twice, it is considered ready
* and inserted into the layer. This process is repeated until no more
* two-qubit are found anymore.
*
* The signature of the callback function is:
*
* (FrontArrayRef, ReleasedIterator&) -> WalkResult
*
* The wire iterators inserted into the parameter "released" determine which
* two-qubit gates are released in next iteration.
*
* @param wires A mutable array-ref of circuit wires (wire iterators).
* @param direction The traversal direction.
* @param fn The callback function.
*
* @returns
* failure(), if the callback returns WalkResult::interrupt()
* failure(), if the callback returns WalkResult::skipped()
* success(), otherwise.
*/
LogicalResult walkCircuitGraph(MutableArrayRef<WireIterator> wires,
WalkDirection direction, WalkCircuitGraphFn fn);
} // namespace mlir::qco
Loading
Loading