diff --git a/include/na/zoned/Compiler.hpp b/include/na/zoned/Compiler.hpp index 4f1b013b0..658dd22e9 100644 --- a/include/na/zoned/Compiler.hpp +++ b/include/na/zoned/Compiler.hpp @@ -12,6 +12,7 @@ #include "Architecture.hpp" #include "code_generator/CodeGenerator.hpp" +#include "decomposer/NoOpDecomposer.hpp" #include "ir/QuantumComputation.hpp" #include "ir/operations/Operation.hpp" #include "layout_synthesizer/PlaceAndRouteSynthesizer.hpp" @@ -43,9 +44,10 @@ namespace na::zoned { * allowing for better performance than having the components as members of the * compiler and setting them at runtime. */ -template +template class Compiler : protected Scheduler, + protected Decomposer, protected ReuseAnalyzer, protected LayoutSynthesizer, protected CodeGenerator { @@ -59,6 +61,8 @@ class Compiler : protected Scheduler, struct Config { /// Configuration for the scheduler typename Scheduler::Config schedulerConfig{}; + /// Configuration for the decomposer + typename Decomposer::Config decomposerConfig{}; /// Configuration for the reuse analyzer typename ReuseAnalyzer::Config reuseAnalyzerConfig{}; /// Configuration for the layout synthesizer @@ -68,6 +72,7 @@ class Compiler : protected Scheduler, /// Log level for the compiler spdlog::level::level_enum logLevel = spdlog::level::info; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Config, schedulerConfig, + decomposerConfig, reuseAnalyzerConfig, layoutSynthesizerConfig, codeGeneratorConfig, logLevel); @@ -78,6 +83,7 @@ class Compiler : protected Scheduler, */ struct Statistics { int64_t schedulingTime; ///< Time taken for scheduling in us + int64_t decomposingTime; ///< Time taken for decomposing in us int64_t reuseAnalysisTime; ///< Time taken for reuse analysis in us /// Statistics collected during layout synthesis. typename LayoutSynthesizer::Statistics layoutSynthesizerStatistics; @@ -106,6 +112,7 @@ class Compiler : protected Scheduler, */ Compiler(const Architecture& architecture, const Config& config) : Scheduler(architecture, config.schedulerConfig), + Decomposer(architecture, config.decomposerConfig), ReuseAnalyzer(architecture, config.reuseAnalyzerConfig), LayoutSynthesizer(architecture, config.layoutSynthesizerConfig), CodeGenerator(architecture, config.codeGeneratorConfig), @@ -195,6 +202,17 @@ class Compiler : protected Scheduler, } #endif // SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG + SPDLOG_DEBUG("Decomposing..."); + const auto decomposingStart = std::chrono::system_clock::now(); + const auto& decomposedSingleQubitGateLayers = + SELF.decompose(singleQubitGateLayers); + const auto decomposingEnd = std::chrono::system_clock::now(); + statistics_.decomposingTime = + std::chrono::duration_cast(decomposingEnd - + decomposingStart) + .count(); + SPDLOG_INFO("Time for decomposing: {}us", statistics_.decomposingTime); + SPDLOG_DEBUG("Analyzing reuse..."); const auto reuseAnalysisStart = std::chrono::system_clock::now(); const auto& reuseQubits = SELF.analyzeReuse(twoQubitGateLayers); @@ -222,7 +240,7 @@ class Compiler : protected Scheduler, SPDLOG_DEBUG("Generating code..."); const auto codeGenerationStart = std::chrono::system_clock::now(); NAComputation code = - SELF.generate(singleQubitGateLayers, placement, routing); + SELF.generate(decomposedSingleQubitGateLayers, placement, routing); const auto codeGenerationEnd = std::chrono::system_clock::now(); assert(code.validate().first); statistics_.codeGenerationTime = @@ -257,7 +275,7 @@ class RoutingAgnosticSynthesizer : PlaceAndRouteSynthesizer(architecture) {} }; class RoutingAgnosticCompiler final - : public Compiler { public: @@ -279,7 +297,7 @@ class RoutingAwareSynthesizer : PlaceAndRouteSynthesizer(architecture) {} }; class RoutingAwareCompiler final - : public Compiler { public: diff --git a/include/na/zoned/Types.hpp b/include/na/zoned/Types.hpp index c30560aeb..1a00ea171 100644 --- a/include/na/zoned/Types.hpp +++ b/include/na/zoned/Types.hpp @@ -20,8 +20,10 @@ namespace na::zoned { /// A list of single-qubit gates representing a single-qubit gate layer. -using SingleQubitGateLayer = +using SingleQubitGateRefLayer = std::vector>; +/// A list of single-qubit gates representing a single-qubit gate layer. +using SingleQubitGateLayer = std::vector>; /// A pair of qubits as an array that allows iterating over the qubits. using QubitPair = std::array; /// A list of two-qubit gates representing a two-qubit gate layer. diff --git a/include/na/zoned/decomposer/DecomposerBase.hpp b/include/na/zoned/decomposer/DecomposerBase.hpp new file mode 100644 index 000000000..773b0e85f --- /dev/null +++ b/include/na/zoned/decomposer/DecomposerBase.hpp @@ -0,0 +1,35 @@ +/* + * 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 "na/zoned/Types.hpp" + +#include + +namespace na::zoned { +/** + * The Abstract Base Class for the Decomposer of the MQT's Zoned Neutral Atom + * Compiler. + */ +class DecomposerBase { +public: + virtual ~DecomposerBase() = default; + /** + * This function defines the interface of the decomposer. + * @param singleQubitGateLayers are the layers of single-qubit gates that are + * meant to be first decomposed into the native gate set. + * @return the new single-qubit gate layers + */ + [[nodiscard]] virtual auto decompose( + const std::vector& singleQubitGateLayers) const + -> std::vector = 0; +}; +} // namespace na::zoned diff --git a/include/na/zoned/decomposer/NoOpDecomposer.hpp b/include/na/zoned/decomposer/NoOpDecomposer.hpp new file mode 100644 index 000000000..340b2a7a3 --- /dev/null +++ b/include/na/zoned/decomposer/NoOpDecomposer.hpp @@ -0,0 +1,54 @@ +/* + * 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 "na/zoned/Architecture.hpp" +#include "na/zoned/Types.hpp" +#include "na/zoned/decomposer/DecomposerBase.hpp" + +#include + +namespace na::zoned { +/** + * The class NoOpDecomposer implements a dummy no-op decomposer that just copies + * every operation. + */ +class NoOpDecomposer : public DecomposerBase { + +public: + /// The configuration of the NoOpDecomposer + struct Config { + template < + typename BasicJsonType, + nlohmann::detail::enable_if_t< + nlohmann::detail::is_basic_json::value, int> = 0> + friend void to_json(BasicJsonType& /* unused */, + const Config& /* unused */) {} + + template < + typename BasicJsonType, + nlohmann::detail::enable_if_t< + nlohmann::detail::is_basic_json::value, int> = 0> + friend void from_json(const BasicJsonType& /* unused */, + Config& /* unused */) {}; + }; + + /** + * Create a new NoOpDecomposer. + */ + NoOpDecomposer(const Architecture& /* unused */, const Config& /* unused */) { + } + + [[nodiscard]] auto decompose( + const std::vector& singleQubitGateLayers) const + -> std::vector override; +}; +} // namespace na::zoned diff --git a/include/na/zoned/scheduler/ASAPScheduler.hpp b/include/na/zoned/scheduler/ASAPScheduler.hpp index ed4c3052b..38884dbbb 100644 --- a/include/na/zoned/scheduler/ASAPScheduler.hpp +++ b/include/na/zoned/scheduler/ASAPScheduler.hpp @@ -67,7 +67,7 @@ class ASAPScheduler : public SchedulerBase { * operations. A pair of qubits represents every two-qubit operation. */ [[nodiscard]] auto schedule(const qc::QuantumComputation& qc) const - -> std::pair, + -> std::pair, std::vector>; }; } // namespace na::zoned diff --git a/include/na/zoned/scheduler/SchedulerBase.hpp b/include/na/zoned/scheduler/SchedulerBase.hpp index 95b6c7fb9..74c0bbaac 100644 --- a/include/na/zoned/scheduler/SchedulerBase.hpp +++ b/include/na/zoned/scheduler/SchedulerBase.hpp @@ -32,7 +32,7 @@ class SchedulerBase { * operations. A pair of qubits represents every two-qubit operation. */ [[nodiscard]] virtual auto schedule(const qc::QuantumComputation& qc) const - -> std::pair, + -> std::pair, std::vector> = 0; }; } // namespace na::zoned diff --git a/src/na/zoned/code_generator/CodeGenerator.cpp b/src/na/zoned/code_generator/CodeGenerator.cpp index 5b5eebc65..0cc00751d 100644 --- a/src/na/zoned/code_generator/CodeGenerator.cpp +++ b/src/na/zoned/code_generator/CodeGenerator.cpp @@ -62,12 +62,11 @@ auto CodeGenerator::appendSingleQubitGates( // This flag is used for circuit consisting of only one qubit since in this // case, global and local gates are the same. bool singleQubitGate = false; - if (op.get().isGlobal(nQubits)) { + if (op->isGlobal(nQubits)) { // a global operation can be wrapped in a compound operation or a standard // operation acting on all qubits - if (op.get().isCompoundOperation()) { - const auto& compOp = - dynamic_cast(op.get()); + if (op->isCompoundOperation()) { + const auto& compOp = dynamic_cast(*op); const auto opType = compOp.front()->getType(); if (opType == qc::RY) { code.emplaceBack(globalZone, @@ -80,9 +79,8 @@ auto CodeGenerator::appendSingleQubitGates( assert(false); } } else { - if (const auto opType = op.get().getType(); opType == qc::RY) { - code.emplaceBack(globalZone, - op.get().getParameter().front()); + if (const auto opType = op->getType(); opType == qc::RY) { + code.emplaceBack(globalZone, op->getParameter().front()); } else if (opType == qc::Y) { code.emplaceBack(globalZone, qc::PI); } else if (nQubits == 1) { @@ -101,21 +99,20 @@ auto CodeGenerator::appendSingleQubitGates( if (singleQubitGate) { // one qubit gates act exactly on one qubit and are converted to local // gates - assert(op.get().getNqubits() == 1); - const qc::Qubit qubit = op.get().getTargets().front(); + assert(op->getNqubits() == 1); + const qc::Qubit qubit = op->getTargets().front(); // By default, all variants of rotational z-gates are supported - if (op.get().getType() == qc::RZ || op.get().getType() == qc::P) { - code.emplaceBack(atoms[qubit], - op.get().getParameter().front()); - } else if (op.get().getType() == qc::Z) { + if (op->getType() == qc::RZ || op->getType() == qc::P) { + code.emplaceBack(atoms[qubit], op->getParameter().front()); + } else if (op->getType() == qc::Z) { code.emplaceBack(atoms[qubit], qc::PI); - } else if (op.get().getType() == qc::S) { + } else if (op->getType() == qc::S) { code.emplaceBack(atoms[qubit], qc::PI_2); - } else if (op.get().getType() == qc::Sdg) { + } else if (op->getType() == qc::Sdg) { code.emplaceBack(atoms[qubit], -qc::PI_2); - } else if (op.get().getType() == qc::T) { + } else if (op->getType() == qc::T) { code.emplaceBack(atoms[qubit], qc::PI_4); - } else if (op.get().getType() == qc::Tdg) { + } else if (op->getType() == qc::Tdg) { code.emplaceBack(atoms[qubit], -qc::PI_4); } else { // in this case, the gate is not any variant of a rotational z-gate. @@ -123,37 +120,35 @@ auto CodeGenerator::appendSingleQubitGates( if (config_.warnUnsupportedGates) { SPDLOG_WARN( "Gate not part of basis gates will be inserted as U3 gate: {}", - qc::toString(op.get().getType())); + qc::toString(op->getType())); } - if (op.get().getType() == qc::U) { - code.emplaceBack( - atoms[qubit], op.get().getParameter().front(), - op.get().getParameter().at(1), op.get().getParameter().at(2)); - } else if (op.get().getType() == qc::U2) { + if (op->getType() == qc::U) { + code.emplaceBack(atoms[qubit], op->getParameter().front(), + op->getParameter().at(1), + op->getParameter().at(2)); + } else if (op->getType() == qc::U2) { code.emplaceBack(atoms[qubit], qc::PI_2, - op.get().getParameter().front(), - op.get().getParameter().at(1)); - } else if (op.get().getType() == qc::RX) { - code.emplaceBack(atoms[qubit], - op.get().getParameter().front(), -qc::PI_2, - qc::PI_2); - } else if (op.get().getType() == qc::RY) { - code.emplaceBack(atoms[qubit], - op.get().getParameter().front(), 0, 0); - } else if (op.get().getType() == qc::H) { + op->getParameter().front(), + op->getParameter().at(1)); + } else if (op->getType() == qc::RX) { + code.emplaceBack(atoms[qubit], op->getParameter().front(), + -qc::PI_2, qc::PI_2); + } else if (op->getType() == qc::RY) { + code.emplaceBack(atoms[qubit], op->getParameter().front(), + 0, 0); + } else if (op->getType() == qc::H) { code.emplaceBack(atoms[qubit], qc::PI_2, 0, qc::PI); - } else if (op.get().getType() == qc::X) { + } else if (op->getType() == qc::X) { code.emplaceBack(atoms[qubit], qc::PI, 0, qc::PI); - } else if (op.get().getType() == qc::Y) { + } else if (op->getType() == qc::Y) { code.emplaceBack(atoms[qubit], qc::PI, qc::PI_2, qc::PI_2); - } else if (op.get().getType() == qc::Vdg) { + } else if (op->getType() == qc::Vdg) { code.emplaceBack(atoms[qubit], -qc::PI_2, qc::PI_2, -qc::PI_2); - } else if (op.get().getType() == qc::SX) { + } else if (op->getType() == qc::SX) { code.emplaceBack(atoms[qubit], qc::PI_2, -qc::PI_2, qc::PI_2); - } else if (op.get().getType() == qc::SXdg || - op.get().getType() == qc::V) { + } else if (op->getType() == qc::SXdg || op->getType() == qc::V) { code.emplaceBack(atoms[qubit], -qc::PI_2, -qc::PI_2, qc::PI_2); } else { @@ -161,7 +156,7 @@ auto CodeGenerator::appendSingleQubitGates( // gate is not included in the output. std::ostringstream oss; oss << "\033[1;31m[ERROR]\033[0m Unsupported single-qubit gate: " - << op.get().getType() << "\n"; + << op->getType() << "\n"; throw std::invalid_argument(oss.str()); } } diff --git a/src/na/zoned/decomposer/NoOpDecomposer.cpp b/src/na/zoned/decomposer/NoOpDecomposer.cpp new file mode 100644 index 000000000..6c8ae3973 --- /dev/null +++ b/src/na/zoned/decomposer/NoOpDecomposer.cpp @@ -0,0 +1,35 @@ +/* + * 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 + */ + +#include "na/zoned/decomposer/NoOpDecomposer.hpp" + +#include "ir/QuantumComputation.hpp" +#include "na/zoned/Architecture.hpp" + +#include +#include + +namespace na::zoned { +auto NoOpDecomposer::decompose( + const std::vector& singleQubitGateLayers) const + -> std::vector { + std::vector result; + result.reserve(singleQubitGateLayers.size()); + for (const auto& layer : singleQubitGateLayers) { + SingleQubitGateLayer newLayer; + newLayer.reserve(layer.size()); + for (const auto& opRef : layer) { + newLayer.emplace_back(opRef.get().clone()); + } + result.emplace_back(std::move(newLayer)); + } + return result; +} +} // namespace na::zoned diff --git a/src/na/zoned/scheduler/ASAPScheduler.cpp b/src/na/zoned/scheduler/ASAPScheduler.cpp index dec4dba87..939378303 100644 --- a/src/na/zoned/scheduler/ASAPScheduler.cpp +++ b/src/na/zoned/scheduler/ASAPScheduler.cpp @@ -53,14 +53,14 @@ ASAPScheduler::ASAPScheduler(const Architecture& architecture, } } auto ASAPScheduler::schedule(const qc::QuantumComputation& qc) const - -> std::pair, + -> std::pair, std::vector> { if (qc.empty()) { // early exit if there are no operations to schedule - return std::pair{std::vector{}, + return std::pair{std::vector{}, std::vector{}}; } - std::vector singleQubitGateLayers(1); + std::vector singleQubitGateLayers(1); std::vector twoQubitGateLayers(0); // the following vector contains a mapping from qubits to the layer where // the next two-qubit gate can be scheduled for that qubit, i.e., the layer diff --git a/test/na/zoned/test_code_generator.cpp b/test/na/zoned/test_code_generator.cpp index 677b9c45c..7dd8d47bb 100644 --- a/test/na/zoned/test_code_generator.cpp +++ b/test/na/zoned/test_code_generator.cpp @@ -62,46 +62,46 @@ TEST_F(CodeGeneratorGenerateTest, Empty) { const auto& slm = *architecture.storageZones.front(); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(std::vector{}, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n"); } TEST_F(CodeGeneratorGenerateTest, GlobalRYGate) { const auto& slm = *architecture.storageZones.front(); - const auto ry = qc::StandardOperation(0, qc::RY, {0.1}); + qc::StandardOperation ry{0, qc::RY, {0.1}}; + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(ry))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {ry}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ ry 0.10000 global\n"); } TEST_F(CodeGeneratorGenerateTest, GlobalYGate) { const auto& slm = *architecture.storageZones.front(); - const auto y = qc::StandardOperation(0, qc::Y); + qc::StandardOperation y{0, qc::Y}; + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(y))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {y}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ ry 3.14159 global\n"); @@ -111,34 +111,37 @@ TEST_F(CodeGeneratorGenerateTest, GlobalCompoundRYGate) { // Create a compound operation with a single RY gate qc::CompoundOperation cry; cry.emplace_back(0, qc::RY, std::vector{0.1}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(cry))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {cry}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ ry 0.10000 global\n"); } TEST_F(CodeGeneratorGenerateTest, GlobalCompoundYGate) { const auto& slm = *architecture.storageZones.front(); + // Create a compound operation with a single Y gate qc::CompoundOperation cy; cy.emplace_back(0, qc::Y); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(cy))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {cy}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ ry 3.14159 global\n"); @@ -146,16 +149,17 @@ TEST_F(CodeGeneratorGenerateTest, GlobalCompoundYGate) { TEST_F(CodeGeneratorGenerateTest, RZGate) { const auto& slm = *architecture.storageZones.front(); const auto rz = qc::StandardOperation(0, qc::RZ, {0.1}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(rz))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {rz}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz 0.10000 atom0\n"); @@ -163,16 +167,17 @@ TEST_F(CodeGeneratorGenerateTest, RZGate) { TEST_F(CodeGeneratorGenerateTest, PGate) { const auto& slm = *architecture.storageZones.front(); const auto p = qc::StandardOperation(0, qc::P, {0.1}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(p))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {p}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz 0.10000 atom0\n"); @@ -180,16 +185,17 @@ TEST_F(CodeGeneratorGenerateTest, PGate) { TEST_F(CodeGeneratorGenerateTest, ZGate) { const auto& slm = *architecture.storageZones.front(); const auto z = qc::StandardOperation(0, qc::Z); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(z))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {z}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz 3.14159 atom0\n"); @@ -197,16 +203,17 @@ TEST_F(CodeGeneratorGenerateTest, ZGate) { TEST_F(CodeGeneratorGenerateTest, SGate) { const auto& slm = *architecture.storageZones.front(); const auto s = qc::StandardOperation(0, qc::S); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(s))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {s}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz 1.57080 atom0\n"); @@ -214,16 +221,17 @@ TEST_F(CodeGeneratorGenerateTest, SGate) { TEST_F(CodeGeneratorGenerateTest, SdgGate) { const auto& slm = *architecture.storageZones.front(); const auto sdg = qc::StandardOperation(0, qc::Sdg); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(sdg))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {sdg}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz -1.57080 atom0\n"); @@ -231,16 +239,17 @@ TEST_F(CodeGeneratorGenerateTest, SdgGate) { TEST_F(CodeGeneratorGenerateTest, TGate) { const auto& slm = *architecture.storageZones.front(); const auto t = qc::StandardOperation(0, qc::T); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(t))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {t}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz 0.78540 atom0\n"); @@ -248,16 +257,17 @@ TEST_F(CodeGeneratorGenerateTest, TGate) { TEST_F(CodeGeneratorGenerateTest, TdgGate) { const auto& slm = *architecture.storageZones.front(); const auto tdg = qc::StandardOperation(0, qc::Tdg); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(tdg))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {tdg}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ rz -0.78540 atom0\n"); @@ -265,16 +275,17 @@ TEST_F(CodeGeneratorGenerateTest, TdgGate) { TEST_F(CodeGeneratorGenerateTest, U3Gate) { const auto& slm = *architecture.storageZones.front(); const auto u = qc::StandardOperation(0, qc::U, {0.1, 0.2, 0.3}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(u))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {u}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 0.10000 0.20000 0.30000 atom0\n"); @@ -282,16 +293,17 @@ TEST_F(CodeGeneratorGenerateTest, U3Gate) { TEST_F(CodeGeneratorGenerateTest, U2Gate) { const auto& slm = *architecture.storageZones.front(); const auto u2 = qc::StandardOperation(0, qc::U2, {0.1, 0.2}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(u2))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {u2}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 1.57080 0.10000 0.20000 atom0\n"); @@ -299,16 +311,17 @@ TEST_F(CodeGeneratorGenerateTest, U2Gate) { TEST_F(CodeGeneratorGenerateTest, RXGate) { const auto& slm = *architecture.storageZones.front(); const auto rx = qc::StandardOperation(0, qc::RX, {0.1}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(rx))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {rx}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 0.10000 -1.57080 1.57080 atom0\n"); @@ -316,16 +329,17 @@ TEST_F(CodeGeneratorGenerateTest, RXGate) { TEST_F(CodeGeneratorGenerateTest, RYGate) { const auto& slm = *architecture.storageZones.front(); const auto ry = qc::StandardOperation(0, qc::RY, {0.1}); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(ry))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {ry}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}, {slm, 0, 1}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}, {slm, 0, 1}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "atom (3.000, 0.000) atom1\n" @@ -334,16 +348,17 @@ TEST_F(CodeGeneratorGenerateTest, RYGate) { TEST_F(CodeGeneratorGenerateTest, YGate) { const auto& slm = *architecture.storageZones.front(); const auto ry = qc::StandardOperation(0, qc::Y); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(ry))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {ry}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}, {slm, 0, 1}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}, {slm, 0, 1}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "atom (3.000, 0.000) atom1\n" @@ -352,16 +367,17 @@ TEST_F(CodeGeneratorGenerateTest, YGate) { TEST_F(CodeGeneratorGenerateTest, HGate) { const auto& slm = *architecture.storageZones.front(); const auto h = qc::StandardOperation(0, qc::H); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(h))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {h}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 1.57080 0.00000 3.14159 atom0\n"); @@ -369,16 +385,17 @@ TEST_F(CodeGeneratorGenerateTest, HGate) { TEST_F(CodeGeneratorGenerateTest, XGate) { const auto& slm = *architecture.storageZones.front(); const auto x = qc::StandardOperation(0, qc::X); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(x))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {x}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 3.14159 0.00000 3.14159 atom0\n"); @@ -386,16 +403,17 @@ TEST_F(CodeGeneratorGenerateTest, XGate) { TEST_F(CodeGeneratorGenerateTest, VGate) { const auto& slm = *architecture.storageZones.front(); const auto v = qc::StandardOperation(0, qc::V); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(v))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {v}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u -1.57080 -1.57080 1.57080 atom0\n"); @@ -403,16 +421,17 @@ TEST_F(CodeGeneratorGenerateTest, VGate) { TEST_F(CodeGeneratorGenerateTest, VdgGate) { const auto& slm = *architecture.storageZones.front(); const auto vdg = qc::StandardOperation(0, qc::Vdg); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(vdg))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {vdg}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u -1.57080 1.57080 -1.57080 atom0\n"); @@ -420,16 +439,17 @@ TEST_F(CodeGeneratorGenerateTest, VdgGate) { TEST_F(CodeGeneratorGenerateTest, SXGate) { const auto& slm = *architecture.storageZones.front(); const auto sx = qc::StandardOperation(0, qc::SX); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(sx))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {sx}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u 1.57080 -1.57080 1.57080 atom0\n"); @@ -437,16 +457,17 @@ TEST_F(CodeGeneratorGenerateTest, SXGate) { TEST_F(CodeGeneratorGenerateTest, SXdgGate) { const auto& slm = *architecture.storageZones.front(); const auto sxdg = qc::StandardOperation(0, qc::SXdg); + SingleQubitGateLayer layer; + layer.emplace_back(std::make_unique(std::move(sxdg))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{ - {sxdg}}, - std::vector, size_t, size_t>>>{ - {{slm, 0, 0}}}, - std::vector>>{}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{slm, 0, 0}}}, + std::vector>>{}) .toString(), "atom (0.000, 0.000) atom0\n" "@+ u -1.57080 -1.57080 1.57080 atom0\n"); @@ -454,10 +475,14 @@ TEST_F(CodeGeneratorGenerateTest, SXdgGate) { TEST_F(CodeGeneratorGenerateTest, UnsupportedGate) { const auto& slm = *architecture.storageZones.front(); const auto unsupported = qc::NonUnitaryOperation(0, 0); + SingleQubitGateLayer layer; + layer.emplace_back( + std::make_unique(std::move(unsupported))); + std::vector layers; + layers.emplace_back(std::move(layer)); EXPECT_THROW( std::ignore = codeGenerator.generate( - std::vector>>{ - {unsupported}}, + layers, std::vector, size_t, size_t>>>{ {{slm, 0, 0}}}, @@ -470,19 +495,17 @@ TEST_F(CodeGeneratorGenerateTest, TwoQubitGate) { architecture.entanglementZones.front()->front(); const auto& entanglementRight = architecture.entanglementZones.front()->back(); + const std::vector layers(2); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{{}, - {}}, - std::vector, size_t, size_t>>>{ - {{storage, 19, 0}, {storage, 19, 1}}, - {{entanglementLeft, 0, 0}, {entanglementRight, 0, 0}}, - {{storage, 19, 0}, {storage, 19, 1}}}, - std::vector>>{{{0U, 1U}}, - {{0U, 1U}}}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{storage, 19, 0}, {storage, 19, 1}}, + {{entanglementLeft, 0, 0}, {entanglementRight, 0, 0}}, + {{storage, 19, 0}, {storage, 19, 1}}}, + std::vector>>{ + {{0U, 1U}}, {{0U, 1U}}}) .toString(), R"(atom (0.000, 57.000) atom0 atom (3.000, 57.000) atom1 @@ -543,28 +566,26 @@ TEST_F(CodeGeneratorGenerateTest, Offset) { architecture.entanglementZones.front()->front(); const auto& entanglementRight = architecture.entanglementZones.front()->back(); + const std::vector layers(2); EXPECT_EQ( codeGenerator - .generate( - std::vector< - std::vector>>{{}, - {}}, - std::vector, size_t, size_t>>>{ - {{storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}, - {{entanglementLeft, 0, 0}, - {entanglementRight, 0, 0}, - {entanglementLeft, 1, 0}, - {entanglementRight, 1, 0}}, - {{storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}}, - std::vector>>{ - {{0U, 1U, 2U, 3U}}, {{0U, 1U, 2U, 3U}}}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}, + {{entanglementLeft, 0, 0}, + {entanglementRight, 0, 0}, + {entanglementLeft, 1, 0}, + {entanglementRight, 1, 0}}, + {{storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}}, + std::vector>>{ + {{0U, 1U, 2U, 3U}}, {{0U, 1U, 2U, 3U}}}) .toString(), R"(atom (0.000, 54.000) atom0 atom (0.000, 57.000) atom2 @@ -649,34 +670,32 @@ TEST_F(CodeGeneratorGenerateTest, ColumnByColumn) { architecture.entanglementZones.front()->front(); const auto& entanglementRight = architecture.entanglementZones.front()->back(); + const std::vector layers(2); EXPECT_TRUE( codeGenerator - .generate( - std::vector< - std::vector>>{{}, - {}}, - std::vector, size_t, size_t>>>{ - {{storage, 17, 0}, - {storage, 17, 1}, - {storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}, - {{entanglementLeft, 0, 0}, - {entanglementRight, 0, 0}, - {entanglementLeft, 1, 0}, - {entanglementRight, 1, 0}, - {entanglementLeft, 2, 0}, - {entanglementRight, 2, 0}}, - {{storage, 17, 0}, - {storage, 17, 1}, - {storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}}, - std::vector>>{ - {{0U, 1U, 2U, 3U, 4U, 5U}}, {{0U, 1U, 2U, 3U, 4U, 5U}}}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{storage, 17, 0}, + {storage, 17, 1}, + {storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}, + {{entanglementLeft, 0, 0}, + {entanglementRight, 0, 0}, + {entanglementLeft, 1, 0}, + {entanglementRight, 1, 0}, + {entanglementLeft, 2, 0}, + {entanglementRight, 2, 0}}, + {{storage, 17, 0}, + {storage, 17, 1}, + {storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}}, + std::vector>>{ + {{0U, 1U, 2U, 3U, 4U, 5U}}, {{0U, 1U, 2U, 3U, 4U, 5U}}}) .validate() .first); } @@ -694,28 +713,26 @@ TEST_F(CodeGeneratorGenerateTest, RelaxedRouting) { architecture.entanglementZones.front()->front(); const auto& entanglementRight = architecture.entanglementZones.front()->back(); + const std::vector layers(2); EXPECT_TRUE( codeGenerator - .generate( - std::vector< - std::vector>>{{}, - {}}, - std::vector, size_t, size_t>>>{ - {{storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}, - {{entanglementRight, 1, 0}, - {entanglementLeft, 1, 0}, - {entanglementRight, 0, 0}, - {entanglementLeft, 0, 0}}, - {{storage, 18, 0}, - {storage, 18, 1}, - {storage, 19, 0}, - {storage, 19, 1}}}, - std::vector>>{ - {{0U, 1U, 2U, 3U}}, {{0U, 1U, 2U, 3U}}}) + .generate(layers, + std::vector, size_t, size_t>>>{ + {{storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}, + {{entanglementRight, 1, 0}, + {entanglementLeft, 1, 0}, + {entanglementRight, 0, 0}, + {entanglementLeft, 0, 0}}, + {{storage, 18, 0}, + {storage, 18, 1}, + {storage, 19, 0}, + {storage, 19, 1}}}, + std::vector>>{ + {{0U, 1U, 2U, 3U}}, {{0U, 1U, 2U, 3U}}}) .validate() .first); }