Skip to content

Commit 4db69da

Browse files
ystadeCopilotpre-commit-ci[bot]
authored
✨ [NA] Add New Relaxed Router (#859)
## Description This Pull Request adds a new RelaxedIndependentSetRouter and implements corresponding functionality to support relaxed routing within the layout synthesizer for the zoned neutral atom compiler. It includes updates to related classes and introduces new tests for the added functionality. ### Main Changes - New Router Class: - Added RelaxedIndependentSetRouter in layout_synthesizer. Implements a router focusing on relaxed independent sets for routing optimization. - Includes documentation for methods like conflict graph creation, movement compatibility checks, and relaxed conflict resolution. - Compiler Updates: - Introduced RelaxedRoutingAwareSynthesizer and RelaxedRoutingAwareCompiler classes using the new router. - Refactored scheduling, analysis, and logging for better structured debug output and timing metrics segmentation. - Test Suite Enhancements: - Added test case for RelaxedRoutingAwareCompiler. - Included corresponding JSON configuration for new routing functionality. ## Checklist: <!--- This checklist serves as a reminder of a couple of things that ensure your pull request will be merged swiftly. --> - [x] The pull request only contains commits that are focused and relevant to this change. - [x] I have added appropriate tests that cover the new/changed functionality. - [x] I have updated the documentation to reflect these changes. - [x] I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals. - [ ] I have added migration instructions to the upgrade guide (if needed). - [x] The changes follow the project's style guidelines and introduce no new warnings. - [ ] The changes are fully tested and pass the CI checks. - [x] I have reviewed my own code changes. --------- Signed-off-by: Yannick Stade <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent fb01402 commit 4db69da

File tree

13 files changed

+772
-123
lines changed

13 files changed

+772
-123
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ This project adheres to [Semantic Versioning], with the exception that minor rel
1111

1212
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md#unreleased)._
1313

14+
### Added
15+
16+
- ✨ Add relaxed routing method to the zoned neutral atom compiler ([#859]) ([**@ystade**])
17+
1418
### Changed
1519

1620
- 👷 Stop testing on `ubuntu-22.04` and `ubuntu-22.04-arm` runners ([#874]) ([**@denialhaag**])
@@ -169,6 +173,7 @@ _📚 Refer to the [GitHub Release Notes] for previous changelogs._
169173
<!-- PR links -->
170174

171175
[#874]: https://github.com/munich-quantum-toolkit/qmap/pull/874
176+
[#859]: https://github.com/munich-quantum-toolkit/qmap/pull/859
172177
[#848]: https://github.com/munich-quantum-toolkit/qmap/pull/848
173178
[#847]: https://github.com/munich-quantum-toolkit/qmap/pull/847
174179
[#832]: https://github.com/munich-quantum-toolkit/qmap/pull/832

bindings/na/zoned/zoned.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "na/zoned/layout_synthesizer/PlaceAndRouteSynthesizer.hpp"
1616
#include "na/zoned/layout_synthesizer/placer/AStarPlacer.hpp"
1717
#include "na/zoned/layout_synthesizer/placer/VertexMatchingPlacer.hpp"
18+
#include "na/zoned/layout_synthesizer/router/IndependentSetRouter.hpp"
1819

1920
#include <cstddef>
2021
// The header <nlohmann/json.hpp> is used, but clang-tidy confuses it with the
@@ -24,6 +25,7 @@
2425
#include <pybind11/attr.h>
2526
#include <pybind11/cast.h>
2627
#include <pybind11/detail/common.h>
28+
#include <pybind11/native_enum.h>
2729
#include <pybind11/pybind11.h>
2830
// NOLINTNEXTLINE(misc-include-cleaner)
2931
#include <pybind11_json/pybind11_json.hpp>
@@ -51,6 +53,17 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
5153
return self.exportNAVizMachine();
5254
});
5355

56+
//===--------------------------------------------------------------------===//
57+
// Routing Method Enum
58+
//===--------------------------------------------------------------------===//
59+
py::native_enum<na::zoned::IndependentSetRouter::Config::Method>(
60+
m, "RoutingMethod", "enum.Enum")
61+
.value("strict", na::zoned::IndependentSetRouter::Config::Method::STRICT)
62+
.value("relaxed",
63+
na::zoned::IndependentSetRouter::Config::Method::RELAXED)
64+
.export_values()
65+
.finalize();
66+
5467
//===--------------------------------------------------------------------===//
5568
// Routing-agnostic Compiler
5669
//===--------------------------------------------------------------------===//
@@ -63,7 +76,9 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
6376
const std::string& logLevel, const double maxFillingFactor,
6477
const bool useWindow, const size_t windowSize,
6578
const bool dynamicPlacement,
66-
const bool warnUnsupportedGates)
79+
const na::zoned::IndependentSetRouter::Config::Method
80+
routingMethod,
81+
const double preferSplit, const bool warnUnsupportedGates)
6782
-> na::zoned::RoutingAgnosticCompiler {
6883
na::zoned::RoutingAgnosticCompiler::Config config;
6984
config.logLevel = spdlog::level::from_str(logLevel);
@@ -72,6 +87,8 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
7287
.useWindow = useWindow,
7388
.windowSize = windowSize,
7489
.dynamicPlacement = dynamicPlacement};
90+
config.layoutSynthesizerConfig.routerConfig = {
91+
.method = routingMethod, .preferSplit = preferSplit};
7592
config.codeGeneratorConfig = {.warnUnsupportedGates =
7693
warnUnsupportedGates};
7794
return {arch, config};
@@ -85,6 +102,10 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
85102
defaultConfig.layoutSynthesizerConfig.placerConfig.windowSize,
86103
"dynamic_placement"_a =
87104
defaultConfig.layoutSynthesizerConfig.placerConfig.dynamicPlacement,
105+
"routing_method"_a =
106+
defaultConfig.layoutSynthesizerConfig.routerConfig.method,
107+
"prefer_split"_a =
108+
defaultConfig.layoutSynthesizerConfig.routerConfig.preferSplit,
88109
"warn_unsupported_gates"_a =
89110
defaultConfig.codeGeneratorConfig.warnUnsupportedGates);
90111
}
@@ -125,7 +146,10 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
125146
const double windowRatio, const double windowShare,
126147
const float deepeningFactor, const float deepeningValue,
127148
const float lookaheadFactor, const float reuseLevel,
128-
const size_t maxNodes, const bool warnUnsupportedGates)
149+
const size_t maxNodes,
150+
const na::zoned::IndependentSetRouter::Config::Method
151+
routingMethod,
152+
const double preferSplit, const bool warnUnsupportedGates)
129153
-> na::zoned::RoutingAwareCompiler {
130154
na::zoned::RoutingAwareCompiler::Config config;
131155
config.logLevel = spdlog::level::from_str(logLevel);
@@ -139,7 +163,10 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
139163
.deepeningValue = deepeningValue,
140164
.lookaheadFactor = lookaheadFactor,
141165
.reuseLevel = reuseLevel,
142-
.maxNodes = maxNodes};
166+
.maxNodes = maxNodes,
167+
};
168+
config.layoutSynthesizerConfig.routerConfig = {
169+
.method = routingMethod, .preferSplit = preferSplit};
143170
config.codeGeneratorConfig = {.warnUnsupportedGates =
144171
warnUnsupportedGates};
145172
return {arch, config};
@@ -165,6 +192,10 @@ PYBIND11_MODULE(MQT_QMAP_MODULE_NAME, m, py::mod_gil_not_used()) {
165192
defaultConfig.layoutSynthesizerConfig.placerConfig.reuseLevel,
166193
"max_nodes"_a =
167194
defaultConfig.layoutSynthesizerConfig.placerConfig.maxNodes,
195+
"routing_method"_a =
196+
defaultConfig.layoutSynthesizerConfig.routerConfig.method,
197+
"prefer_split"_a =
198+
defaultConfig.layoutSynthesizerConfig.routerConfig.preferSplit,
168199
"warn_unsupported_gates"_a =
169200
defaultConfig.codeGeneratorConfig.warnUnsupportedGates);
170201
}

include/na/zoned/Compiler.hpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,14 @@ class Compiler : protected Scheduler,
159159
}
160160
#endif // SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
161161

162-
const auto& schedulingStart = std::chrono::system_clock::now();
163162
// CodeQL was not very happy about the structural binding here, hence I
164163
// removed it.
164+
SPDLOG_DEBUG("Scheduling...");
165+
const auto schedulingStart = std::chrono::system_clock::now();
165166
const auto& schedule = SELF.schedule(qComp);
167+
const auto schedulingEnd = std::chrono::system_clock::now();
166168
const auto& singleQubitGateLayers = schedule.first;
167169
const auto& twoQubitGateLayers = schedule.second;
168-
const auto& schedulingEnd = std::chrono::system_clock::now();
169-
const auto& reuseQubits = SELF.analyzeReuse(twoQubitGateLayers);
170-
const auto& reuseAnalysisEnd = std::chrono::system_clock::now();
171-
const auto& [placement, routing] = LayoutSynthesizer::synthesize(
172-
qComp.getNqubits(), twoQubitGateLayers, reuseQubits);
173-
const auto& layoutSynthesisEnd = std::chrono::system_clock::now();
174-
NAComputation code =
175-
SELF.generate(singleQubitGateLayers, placement, routing);
176-
const auto& codeGenerationEnd = std::chrono::system_clock::now();
177-
assert(code.validate().first);
178-
179170
statistics_.schedulingTime =
180171
std::chrono::duration_cast<std::chrono::microseconds>(schedulingEnd -
181172
schedulingStart)
@@ -203,25 +194,44 @@ class Compiler : protected Scheduler,
203194
avg, max);
204195
}
205196
#endif // SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
197+
198+
SPDLOG_DEBUG("Analyzing reuse...");
199+
const auto reuseAnalysisStart = std::chrono::system_clock::now();
200+
const auto& reuseQubits = SELF.analyzeReuse(twoQubitGateLayers);
201+
const auto reuseAnalysisEnd = std::chrono::system_clock::now();
206202
statistics_.reuseAnalysisTime =
207-
std::chrono::duration_cast<std::chrono::microseconds>(reuseAnalysisEnd -
208-
schedulingEnd)
203+
std::chrono::duration_cast<std::chrono::microseconds>(
204+
reuseAnalysisEnd - reuseAnalysisStart)
209205
.count();
210206
SPDLOG_INFO("Time for reuse analysis: {}us", statistics_.reuseAnalysisTime);
207+
208+
SPDLOG_DEBUG("Synthesizing layout...");
209+
const auto layoutSynthesisStart = std::chrono::system_clock::now();
210+
const auto& [placement, routing] = LayoutSynthesizer::synthesize(
211+
qComp.getNqubits(), twoQubitGateLayers, reuseQubits);
212+
const auto layoutSynthesisEnd = std::chrono::system_clock::now();
211213
statistics_.layoutSynthesisTime =
212214
std::chrono::duration_cast<std::chrono::microseconds>(
213-
layoutSynthesisEnd - reuseAnalysisEnd)
215+
layoutSynthesisEnd - layoutSynthesisStart)
214216
.count();
215217
statistics_.layoutSynthesizerStatistics =
216218
SELF.getLayoutSynthesisStatistics();
217219
SPDLOG_INFO("Time for layout synthesis: {}us",
218220
statistics_.layoutSynthesisTime);
221+
222+
SPDLOG_DEBUG("Generating code...");
223+
const auto codeGenerationStart = std::chrono::system_clock::now();
224+
NAComputation code =
225+
SELF.generate(singleQubitGateLayers, placement, routing);
226+
const auto codeGenerationEnd = std::chrono::system_clock::now();
227+
assert(code.validate().first);
219228
statistics_.codeGenerationTime =
220229
std::chrono::duration_cast<std::chrono::microseconds>(
221-
codeGenerationEnd - layoutSynthesisEnd)
230+
codeGenerationEnd - codeGenerationStart)
222231
.count();
223232
SPDLOG_INFO("Time for code generation: {}us",
224233
statistics_.codeGenerationTime);
234+
225235
statistics_.totalTime =
226236
std::chrono::duration_cast<std::chrono::microseconds>(
227237
codeGenerationEnd - schedulingStart)
@@ -254,7 +264,7 @@ class RoutingAgnosticCompiler final
254264
RoutingAgnosticCompiler(const Architecture& architecture,
255265
const Config& config)
256266
: Compiler(architecture, config) {}
257-
RoutingAgnosticCompiler(const Architecture& architecture)
267+
explicit RoutingAgnosticCompiler(const Architecture& architecture)
258268
: Compiler(architecture) {}
259269
};
260270

@@ -275,7 +285,7 @@ class RoutingAwareCompiler final
275285
public:
276286
RoutingAwareCompiler(const Architecture& architecture, const Config& config)
277287
: Compiler(architecture, config) {}
278-
RoutingAwareCompiler(const Architecture& architecture)
288+
explicit RoutingAwareCompiler(const Architecture& architecture)
279289
: Compiler(architecture) {}
280290
};
281291
} // namespace na::zoned

include/na/zoned/layout_synthesizer/PlaceAndRouteSynthesizer.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ class PlaceAndRouteSynthesizer : public LayoutSynthesizerBase,
9797
: PlaceAndRouteSynthesizer(architecture, Config{}) {}
9898

9999
public:
100-
[[nodiscard]] auto synthesize(
101-
size_t nQubits, const std::vector<TwoQubitGateLayer>& twoQubitGateLayers,
102-
const std::vector<std::unordered_set<qc::Qubit>>& reuseQubits) -> Layout {
100+
[[nodiscard]] auto
101+
synthesize(size_t nQubits,
102+
const std::vector<TwoQubitGateLayer>& twoQubitGateLayers,
103+
const std::vector<std::unordered_set<qc::Qubit>>& reuseQubits)
104+
-> Layout override {
103105
const auto& placementStart = std::chrono::system_clock::now();
104106
const auto& placement =
105107
SELF.place(nQubits, twoQubitGateLayers, reuseQubits);

include/na/zoned/layout_synthesizer/placer/AStarPlacer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ class AStarPlacer : public PlacerBase {
303303
place(size_t nQubits,
304304
const std::vector<TwoQubitGateLayer>& twoQubitGateLayers,
305305
const std::vector<std::unordered_set<qc::Qubit>>& reuseQubits)
306-
-> std::vector<Placement>;
306+
-> std::vector<Placement> override;
307307

308308
private:
309309
/**

include/na/zoned/layout_synthesizer/placer/VertexMatchingPlacer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class VertexMatchingPlacer : public PlacerBase {
9999
place(size_t nQubits,
100100
const std::vector<TwoQubitGateLayer>& twoQubitGateLayers,
101101
const std::vector<std::unordered_set<qc::Qubit>>& reuseQubits)
102-
-> std::vector<Placement>;
102+
-> std::vector<Placement> override;
103103

104104
private:
105105
/// Generate qubit initial layout

0 commit comments

Comments
 (0)