From c5707705fa4482cadf623b5caa520d0379e04cb8 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Sat, 8 Feb 2025 20:16:42 +0100 Subject: [PATCH 01/39] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20NACOmputa?= =?UTF-8?q?tion,=20output=20new=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 83 ++------- include/mqt-core/na/NADefinitions.hpp | 143 --------------- include/mqt-core/na/NAUtils.hpp | 52 ++++++ include/mqt-core/na/entities/Atom.hpp | 48 +++++ include/mqt-core/na/entities/Location.hpp | 68 +++++++ include/mqt-core/na/entities/Zone.hpp | 42 +++++ include/mqt-core/na/operations/GlobalCZOp.hpp | 21 +++ include/mqt-core/na/operations/GlobalOp.hpp | 39 ++++ include/mqt-core/na/operations/GlobalRYOp.hpp | 21 +++ include/mqt-core/na/operations/LoadOp.hpp | 57 ++++++ include/mqt-core/na/operations/LocalOp.hpp | 46 +++++ include/mqt-core/na/operations/LocalRZOp.hpp | 23 +++ include/mqt-core/na/operations/MoveOp.hpp | 47 +++++ .../na/operations/NAGlobalOperation.hpp | 48 ----- .../na/operations/NALocalOperation.hpp | 67 ------- .../mqt-core/na/operations/NAOperation.hpp | 32 ---- .../na/operations/NAShuttlingOperation.hpp | 67 ------- include/mqt-core/na/operations/Op.hpp | 33 ++++ .../mqt-core/na/operations/ShuttlingOp.hpp | 34 ++++ include/mqt-core/na/operations/StoreOp.hpp | 57 ++++++ src/na/NAComputation.cpp | 173 ++++++++++-------- .../{NAGlobalOperation.cpp => GlobalOp.cpp} | 15 +- src/na/operations/LoadOp.cpp | 37 ++++ src/na/operations/LocalOp.cpp | 43 +++++ src/na/operations/MoveOp.cpp | 30 +++ src/na/operations/NALocalOperation.cpp | 40 ---- src/na/operations/NAShuttlingOperation.cpp | 43 ----- src/na/operations/StoreOp.cpp | 37 ++++ test/na/test_nacomputation.cpp | 114 ++++++------ test/na/test_nadefinitions.cpp | 14 +- test/na/test_naoperation.cpp | 22 +-- 31 files changed, 927 insertions(+), 669 deletions(-) delete mode 100644 include/mqt-core/na/NADefinitions.hpp create mode 100644 include/mqt-core/na/NAUtils.hpp create mode 100644 include/mqt-core/na/entities/Atom.hpp create mode 100644 include/mqt-core/na/entities/Location.hpp create mode 100644 include/mqt-core/na/entities/Zone.hpp create mode 100644 include/mqt-core/na/operations/GlobalCZOp.hpp create mode 100644 include/mqt-core/na/operations/GlobalOp.hpp create mode 100644 include/mqt-core/na/operations/GlobalRYOp.hpp create mode 100644 include/mqt-core/na/operations/LoadOp.hpp create mode 100644 include/mqt-core/na/operations/LocalOp.hpp create mode 100644 include/mqt-core/na/operations/LocalRZOp.hpp create mode 100644 include/mqt-core/na/operations/MoveOp.hpp delete mode 100644 include/mqt-core/na/operations/NAGlobalOperation.hpp delete mode 100644 include/mqt-core/na/operations/NALocalOperation.hpp delete mode 100644 include/mqt-core/na/operations/NAOperation.hpp delete mode 100644 include/mqt-core/na/operations/NAShuttlingOperation.hpp create mode 100644 include/mqt-core/na/operations/Op.hpp create mode 100644 include/mqt-core/na/operations/ShuttlingOp.hpp create mode 100644 include/mqt-core/na/operations/StoreOp.hpp rename src/na/operations/{NAGlobalOperation.cpp => GlobalOp.cpp} (61%) create mode 100644 src/na/operations/LoadOp.cpp create mode 100644 src/na/operations/LocalOp.cpp create mode 100644 src/na/operations/MoveOp.cpp delete mode 100644 src/na/operations/NALocalOperation.cpp delete mode 100644 src/na/operations/NAShuttlingOperation.cpp create mode 100644 src/na/operations/StoreOp.cpp diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 9a617a3e4..6eff8cc97 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -9,94 +9,41 @@ #pragma once -#include "NADefinitions.hpp" -#include "operations/NAOperation.hpp" +#include "entities/Atom.hpp" +#include "entities/Location.hpp" +#include "operations/Op.hpp" -#include -#include #include -#include #include #include +#include #include namespace na { -class NAComputation { +class NAComputation : std::vector { protected: - std::vector> initialPositions; - std::vector> operations; + std::vector atoms; + std::unordered_map initialLocations; public: NAComputation() = default; + NAComputation(const NAComputation& qc) = default; NAComputation(NAComputation&& qc) noexcept = default; + NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; - NAComputation(const NAComputation& qc) - : initialPositions(qc.initialPositions) { - operations.reserve(qc.operations.size()); - std::transform(qc.operations.cbegin(), qc.operations.cend(), - std::back_inserter(operations), - [](const auto& op) { return op->clone(); }); - } - NAComputation& operator=(const NAComputation& qc) { - if (this != &qc) { - initialPositions = qc.initialPositions; - operations.clear(); - operations.reserve(qc.operations.size()); - std::transform(qc.operations.cbegin(), qc.operations.cend(), - std::back_inserter(operations), - [](const auto& op) { return op->clone(); }); - } - return *this; - } virtual ~NAComputation() = default; - template auto emplaceBack(std::unique_ptr&& op) -> void { - static_assert(std::is_base_of_v, - "T must be a subclass of NAOperation."); - operations.emplace_back(std::move(op)); - } - template auto emplaceBack(const std::unique_ptr& op) -> void { - static_assert(std::is_base_of_v, - "T must be a subclass of NAOperation."); - operations.emplace_back(std::move(op)); - } - template auto emplaceBack(Args&&... args) -> void { - static_assert(std::is_base_of_v, - "T must be a subclass of NAOperation."); - operations.emplace_back(std::make_unique(std::forward(args)...)); + [[nodiscard]] auto getAtoms() -> decltype(atoms)& { + return atoms; } - auto clear(const bool clearInitialPositions = true) -> void { - operations.clear(); - if (clearInitialPositions) { - initialPositions.clear(); - } - } - [[nodiscard]] auto size() const -> std::size_t { return operations.size(); } - [[nodiscard]] auto getInitialPositions() const - -> const std::vector>& { - return initialPositions; - } - auto emplaceInitialPosition(std::shared_ptr p) -> void { - initialPositions.emplace_back(std::move(p)); + [[nodiscard]] auto getInitialLocations() -> + decltype(initialLocations)& { + return initialLocations; } [[nodiscard]] auto toString() const -> std::string; friend auto operator<<(std::ostream& os, const NAComputation& qc) -> std::ostream& { return os << qc.toString(); } - // Iterators (pass-through) - auto begin() noexcept { return operations.begin(); } - [[nodiscard]] auto begin() const noexcept { return operations.begin(); } - [[nodiscard]] auto cbegin() const noexcept { return operations.cbegin(); } - auto end() noexcept { return operations.end(); } - [[nodiscard]] auto end() const noexcept { return operations.end(); } - [[nodiscard]] auto cend() const noexcept { return operations.cend(); } - auto rbegin() noexcept { return operations.rbegin(); } - [[nodiscard]] auto rbegin() const noexcept { return operations.rbegin(); } - [[nodiscard]] auto crbegin() const noexcept { return operations.crbegin(); } - auto rend() noexcept { return operations.rend(); } - [[nodiscard]] auto rend() const noexcept { return operations.rend(); } - [[nodiscard]] auto crend() const noexcept { return operations.crend(); } - - [[nodiscard]] auto validateAODConstraints() const -> bool; + [[nodiscard]] auto validate() const -> bool; }; } // namespace na diff --git a/include/mqt-core/na/NADefinitions.hpp b/include/mqt-core/na/NADefinitions.hpp deleted file mode 100644 index a9d181de3..000000000 --- a/include/mqt-core/na/NADefinitions.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include "Definitions.hpp" -#include "ir/operations/CompoundOperation.hpp" -#include "ir/operations/OpType.hpp" -#include "ir/operations/Operation.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace na { -/// Class to store two-dimensional coordinates -struct Point { - std::int64_t x; - std::int64_t y; - Point(const std::int64_t xp, const std::int64_t yp) : x(xp), y(yp) {}; - Point(const Point& p) = default; - virtual ~Point() = default; - Point& operator=(const Point& p) = default; - Point operator-(const Point& p) const { return {x - p.x, y - p.y}; } - Point operator-(const Point&& p) const { return {x - p.x, y - p.y}; } - Point operator+(const Point& p) const { return {x + p.x, y + p.y}; } - Point operator+(const Point&& p) const { return {x + p.x, y + p.y}; } - [[nodiscard]] auto length() const -> std::uint64_t { - return static_cast(std::round(std::sqrt(x * x + y * y))); - } - [[nodiscard]] auto toString() const -> std::string { - std::stringstream ss; - ss << "(" << x << ", " << y << ")"; - return ss.str(); - } - friend auto operator<<(std::ostream& os, const Point& obj) -> std::ostream& { - return os << obj.toString(); // Using toString() method - } - [[nodiscard]] auto operator==(const Point& other) const -> bool { - return x == other.x && y == other.y; - } - [[maybe_unused]] [[nodiscard]] auto - getEuclideanDistance(const Point& c) const { - const auto delta = *this - c; - return delta.length(); - } - - [[maybe_unused]] [[nodiscard]] std::int64_t - getManhattanDistanceX(const Point& c) const { - if (x > c.x) { - return x - c.x; - } - return c.x - x; - } - [[maybe_unused]] [[nodiscard]] std::int64_t - getManhattanDistanceY(const Point& c) const { - if (y > c.y) { - return y - c.y; - } - return c.y - y; - } -}; -/// More specific operation type including the number of control qubits -struct FullOpType { - qc::OpType type; - std::size_t nControls; - [[nodiscard]] auto toString() const -> std::string { - return std::string(nControls, 'c') + qc::toString(type); - } - friend auto operator<<(std::ostream& os, const FullOpType& obj) - -> std::ostream& { - return os << obj.toString(); // Using toString() method - } - [[nodiscard]] auto operator==(const FullOpType& other) const -> bool { - return type == other.type && nControls == other.nControls; - } - [[nodiscard]] auto isSingleQubitType() const -> bool { - return isSingleQubitGate(type); - } - [[nodiscard]] auto isTwoQubitType() const -> bool { - return isTwoQubitGate(type); - } - [[nodiscard]] auto isControlledType() const -> bool { return nControls > 0; } -}; - -/** - * @brief Checks whether a gate is global. - * @details A StandardOperation is global if it acts on all qubits. - * A CompoundOperation is global if all its sub-operations are - * StandardOperations of the same type with the same parameters acting on all - * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in - * MQT-core. All other operations are not global. - */ -[[nodiscard]] inline auto isGlobal(const qc::Operation& op, - const std::size_t nQubits) -> bool { - if (op.isStandardOperation()) { - return op.getUsedQubits().size() == nQubits; - } - if (op.isCompoundOperation()) { - const auto ops = dynamic_cast(op); - const auto& params = ops.at(0)->getParameter(); - const auto& type = ops.at(0)->getType(); - return op.getUsedQubits().size() == nQubits && - std::all_of(ops.cbegin(), ops.cend(), [&](const auto& operation) { - return operation->isStandardOperation() && - operation->getNcontrols() == 0 && - operation->getType() == type && - operation->getParameter() == params; - }); - } - return false; -} - -} // namespace na - -/// Hash function for OpType, e.g., for use in unordered_map -template <> struct std::hash { - std::size_t operator()(na::FullOpType const& t) const noexcept { - std::size_t const h1 = std::hash{}(t.type); - std::size_t const h2 = std::hash{}(t.nControls); - return qc::combineHash(h1, h2); - } -}; - -/// Hash function for Point, e.g., for use in unordered_map -template <> struct std::hash { - std::size_t operator()(const na::Point& p) const noexcept { - const std::size_t h1 = std::hash{}(p.x); - const std::size_t h2 = std::hash{}(p.y); - return qc::combineHash(h1, h2); - } -}; diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp new file mode 100644 index 000000000..052c8835b --- /dev/null +++ b/include/mqt-core/na/NAUtils.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "Definitions.hpp" +#include "ir/operations/CompoundOperation.hpp" +#include "ir/operations/OpType.hpp" +#include "ir/operations/Operation.hpp" + +#include +#include +#include +#include +#include + +namespace na { +/** + * @brief Checks whether a gate is global. + * @details A StandardOperation is global if it acts on all qubits. + * A CompoundOperation is global if all its sub-operations are + * StandardOperations of the same type with the same parameters acting on all + * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in + * MQT-core. All other operations are not global. + */ +[[nodiscard]] inline auto isGlobal(const qc::Operation& op, + const std::size_t nQubits) -> bool { + if (op.isStandardOperation()) { + return op.getUsedQubits().size() == nQubits; + } + if (op.isCompoundOperation()) { + const auto ops = dynamic_cast(op); + const auto& params = ops.at(0)->getParameter(); + const auto& type = ops.at(0)->getType(); + return op.getUsedQubits().size() == nQubits && + std::all_of(ops.cbegin(), ops.cend(), [&](const auto& operation) { + return operation->isStandardOperation() && + operation->getNcontrols() == 0 && + operation->getType() == type && + operation->getParameter() == params; + }); + } + return false; +} + +} // namespace na diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp new file mode 100644 index 000000000..67e3d34dc --- /dev/null +++ b/include/mqt-core/na/entities/Atom.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include +#include + +namespace na { +class Atom final { + std::string name; + +public: + Atom() = default; + explicit Atom(std::string name) : name(std::move(name)) {} + Atom(const Atom& atom) = default; + Atom(Atom&& atom) noexcept = default; + Atom& operator=(const Atom& atom) = default; + Atom& operator=(Atom&& atom) noexcept = default; + virtual ~Atom() = default; + [[nodiscard]] auto getName() const -> std::string { return name; } + [[nodiscard]] auto toString() const -> std::string { return name; } + friend auto operator<<(std::ostream& os, const Atom& obj) -> std::ostream& { + return os << obj.toString(); + } + [[nodiscard]] auto operator==(const Atom& other) const -> bool { + if (this == &other) { + return true; + } + return name == other.name; + } + [[nodiscard]] auto operator!=(const Atom& other) const -> bool { + return !(*this == other); + } +}; +} // namespace na +template <> struct std::hash { + [[nodiscard]] auto operator()(const na::Atom* atom) const noexcept + -> std::size_t { + return hash{}(atom->getName()); + } +}; // namespace std diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp new file mode 100644 index 000000000..abbe481d9 --- /dev/null +++ b/include/mqt-core/na/entities/Location.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace na { +/// Class to store two-dimensional coordinates +struct Location final { + double x; + double y; + Location(const double x, const double y) : x(x), y(y) {}; + Location(const Location& p) = default; + ~Location() = default; + Location& operator=(const Location& loc) = default; + Location operator-(const Location& loc) const { + return {x - loc.x, y - loc.y}; + } + Location operator-(const Location&& loc) const { + return {x - loc.x, y - loc.y}; + } + Location operator+(const Location& loc) const { + return {x + loc.x, y + loc.y}; + } + Location operator+(const Location&& loc) const { + return {x + loc.x, y + loc.y}; + } + [[nodiscard]] auto length() const -> double { + return std::sqrt((x * x) + (y * y)); + } + [[nodiscard]] auto toString() const -> std::string { + std::stringstream ss; + ss << std::setprecision(3) << std::fixed; + ss << "(" << x << ", " << y << ")"; + return ss.str(); + } + friend auto operator<<(std::ostream& os, const Location& obj) + -> std::ostream& { + return os << obj.toString(); + } + [[nodiscard]] auto operator==(const Location& other) const -> bool { + return x == other.x && y == other.y; + } + [[maybe_unused]] [[nodiscard]] auto + getEuclideanDistance(const Location& loc) const -> double { + return (*this - loc).length(); + } + [[maybe_unused]] [[nodiscard]] auto + getManhattanDistanceX(const Location& loc) const -> double { + return std::abs(x - loc.x); + } + [[maybe_unused]] [[nodiscard]] auto + getManhattanDistanceY(const Location& loc) const -> double { + return std::abs(y - loc.y); + } +}; +} // namespace na diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp new file mode 100644 index 000000000..c7989d93e --- /dev/null +++ b/include/mqt-core/na/entities/Zone.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include +#include + +namespace na { +class Zone final { + std::string name; + +public: + Zone() = default; + explicit Zone(std::string name) : name(std::move(name)) {} + Zone(const Zone& zone) = default; + Zone(Zone&& zone) noexcept = default; + Zone& operator=(const Zone& zone) = default; + Zone& operator=(Zone&& zone) noexcept = default; + virtual ~Zone() = default; + [[nodiscard]] auto getName() const -> std::string { return name; } + [[nodiscard]] auto toString() const -> std::string { return name; } + friend auto operator<<(std::ostream& os, const Zone& obj) -> std::ostream& { + return os << obj.toString(); + } + [[nodiscard]] auto operator==(const Zone& other) const -> bool { + if (this == &other) { + return true; + } + return name == other.name; + } + [[nodiscard]] auto operator!=(const Zone& other) const -> bool { + return !(*this == other); + } +}; +} // namespace na diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp new file mode 100644 index 000000000..76344e410 --- /dev/null +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/operations/GlobalOp.hpp" + +namespace na { +class GlobalCZOp final : public GlobalOp { +public: + explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { + name = "cz"; + } +}; +} // namespace na diff --git a/include/mqt-core/na/operations/GlobalOp.hpp b/include/mqt-core/na/operations/GlobalOp.hpp new file mode 100644 index 000000000..ff2b085d8 --- /dev/null +++ b/include/mqt-core/na/operations/GlobalOp.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "Definitions.hpp" +#include "na/entities/Zone.hpp" +#include "na/operations/Op.hpp" + +#include +#include + +namespace na { +class GlobalOp : public Op { +protected: + std::string name; + std::vector params; + const Zone* zone; + GlobalOp(std::vector params, const Zone* zone) + : params(std::move(params)), zone(zone) {} + explicit GlobalOp(const Zone* zone) : GlobalOp({}, zone) {} + +public: + GlobalOp() = delete; + [[nodiscard]] auto getParams() -> decltype(params)& { return params; } + [[nodiscard]] auto getParams() const -> const decltype(params)& { + return params; + } + [[nodiscard]] auto getZone() -> const Zone*& { return zone; } + [[nodiscard]] auto getZone() const -> const Zone* { return zone; } + [[nodiscard]] auto toString() const -> std::string override; +}; +} // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp new file mode 100644 index 000000000..1e58e7299 --- /dev/null +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/operations/GlobalOp.hpp" + +namespace na { +class GlobalRYOp final : public GlobalOp { +public: + GlobalRYOp(qc::fp angle, const Zone* zone) : GlobalOp({angle}, zone) { + name = "ry"; + } +}; +} // namespace na diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp new file mode 100644 index 000000000..ed6fdd87f --- /dev/null +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" +#include "na/operations/ShuttlingOp.hpp" + +#include +#include +#include +#include + +namespace na { + +class LoadOp : public ShuttlingOp { +protected: + std::optional> targetLocations = std::nullopt; + +public: + explicit LoadOp(std::vector atoms, + std::vector targetLocations) + : ShuttlingOp(std::move(atoms)), + targetLocations(std::move(targetLocations)) { + if (this->atoms.size() != this->targetLocations->size()) { + throw std::invalid_argument( + "Number of atoms and target locations must be equal."); + } + } + explicit LoadOp(std::vector atoms) + : ShuttlingOp(std::move(atoms)) {} + [[nodiscard]] auto hasTargetLocations() const -> bool { + return targetLocations.has_value(); + } + [[nodiscard]] auto getTargetLocations() -> std::vector& override { + if (!targetLocations.has_value()) { + throw std::logic_error("Operation has no target locations set."); + } + return *targetLocations; + } + [[nodiscard]] auto getTargetLocations() const + -> const std::vector& override { + if (!targetLocations.has_value()) { + throw std::logic_error("Operation has no target locations set."); + } + return *targetLocations; + } + [[nodiscard]] auto toString() const -> std::string override; +}; +} // namespace na diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp new file mode 100644 index 000000000..706c32682 --- /dev/null +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "Definitions.hpp" +#include "na/entities/Atom.hpp" +#include "na/operations/Op.hpp" + +#include +#include + +namespace na { +class LocalOp : public Op { +protected: + std::string name; + std::vector params; + std::vector atoms; + + LocalOp(std::vector params, std::vector atoms) + : params(std::move(params)), atoms(std::move(atoms)) {} + explicit LocalOp(std::vector& atoms) + : LocalOp({}, std::move(atoms)) {} + explicit LocalOp(std::vector params, const Atom* atom) + : LocalOp(std::move(params), {atom}) {} + explicit LocalOp(const Atom* atom) : LocalOp({}, atom) {} + +public: + LocalOp() = delete; + [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } + [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { + return atoms; + } + [[nodiscard]] auto getParams() -> decltype(params)& { return params; } + [[nodiscard]] auto getParams() const -> const decltype(params)& { + return params; + } + [[nodiscard]] auto toString() const -> std::string override; +}; +} // namespace na diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp new file mode 100644 index 000000000..14c8c7a44 --- /dev/null +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/operations/LocalOp.hpp" + +#include + +namespace na { +class LocalRZOp final : public LocalOp { +public: + LocalRZOp(qc::fp angle, const Atom* atom) : LocalOp({angle}, atom) { + name = "rz"; + } +}; +} // namespace na diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp new file mode 100644 index 000000000..565f25012 --- /dev/null +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" +#include "na/operations/ShuttlingOp.hpp" + +#include +#include +#include +#include + +namespace na { + +class MoveOp : public ShuttlingOp { +protected: + std::vector targetLocations; + +public: + explicit MoveOp(std::vector atoms, + std::vector targetLocations) + : ShuttlingOp(std::move(atoms)), + targetLocations(std::move(targetLocations)) { + if (this->atoms.size() != this->targetLocations.size()) { + throw std::invalid_argument( + "Number of atoms and target locations must be equal."); + } + } + [[nodiscard]] auto getTargetLocations() + -> decltype(targetLocations)& override { + return targetLocations; + } + [[nodiscard]] auto getTargetLocations() const -> const + decltype(targetLocations)& override { + return targetLocations; + } + [[nodiscard]] auto toString() const -> std::string override; +}; +} // namespace na diff --git a/include/mqt-core/na/operations/NAGlobalOperation.hpp b/include/mqt-core/na/operations/NAGlobalOperation.hpp deleted file mode 100644 index a88826835..000000000 --- a/include/mqt-core/na/operations/NAGlobalOperation.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include "../NADefinitions.hpp" -#include "Definitions.hpp" -#include "NAOperation.hpp" - -#include -#include -#include -#include -#include - -namespace na { -class NAGlobalOperation : public NAOperation { -protected: - FullOpType type; - std::vector params; - -public: - explicit NAGlobalOperation(const FullOpType opType, - const std::vector& parameters) - : type(opType), params(parameters) { - if (!opType.isSingleQubitType()) { - throw std::invalid_argument("Operation is not single qubit."); - } - } - explicit NAGlobalOperation(const FullOpType opType) - : NAGlobalOperation(opType, {}) {} - [[nodiscard]] auto getParams() const -> const std::vector& { - return params; - } - [[nodiscard]] auto getType() const -> FullOpType { return type; } - [[nodiscard]] auto isGlobalOperation() const -> bool override { return true; } - [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } -}; -} // namespace na diff --git a/include/mqt-core/na/operations/NALocalOperation.hpp b/include/mqt-core/na/operations/NALocalOperation.hpp deleted file mode 100644 index 5b7e309f3..000000000 --- a/include/mqt-core/na/operations/NALocalOperation.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include "../NADefinitions.hpp" -#include "Definitions.hpp" -#include "NAOperation.hpp" - -#include -#include -#include -#include -#include -#include - -namespace na { -class NALocalOperation : public NAOperation { -protected: - FullOpType type; - std::vector params; - std::vector> positions; - -public: - NALocalOperation(const FullOpType& opType, - const std::vector& parameter, - const std::vector>& pos) - : type(opType), params(parameter), positions(pos) { - if (!opType.isSingleQubitType()) { - throw std::invalid_argument("Operation is not single qubit."); - } - if (opType.isControlledType()) { - throw std::logic_error("Control qubits are not supported."); - } - } - explicit NALocalOperation(const FullOpType& opType, - const std::vector>& pos) - : NALocalOperation(opType, {}, pos) {} - explicit NALocalOperation(const FullOpType& opType, - const std::vector& parameters, - std::shared_ptr pos) - : NALocalOperation(opType, parameters, - std::vector>{std::move(pos)}) {} - explicit NALocalOperation(const FullOpType& opType, - std::shared_ptr pos) - : NALocalOperation(opType, {}, std::move(pos)) {} - [[nodiscard]] auto getPositions() const - -> const std::vector>& { - return positions; - } - [[nodiscard]] auto getParams() const -> const std::vector& { - return params; - } - [[nodiscard]] auto getType() const -> FullOpType { return type; } - [[nodiscard]] auto isLocalOperation() const -> bool override { return true; } - [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } -}; -} // namespace na diff --git a/include/mqt-core/na/operations/NAOperation.hpp b/include/mqt-core/na/operations/NAOperation.hpp deleted file mode 100644 index 32f2d9717..000000000 --- a/include/mqt-core/na/operations/NAOperation.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include -#include -#include - -namespace na { -class NAOperation { -public: - [[nodiscard]] virtual auto isShuttlingOperation() const -> bool { - return false; - } - [[nodiscard]] virtual auto isLocalOperation() const -> bool { return false; } - [[nodiscard]] virtual auto isGlobalOperation() const -> bool { return false; } - [[nodiscard]] virtual auto toString() const -> std::string = 0; - friend auto operator<<(std::ostream& os, const NAOperation& obj) - -> std::ostream& { - return os << obj.toString(); // Using toString() method - } - virtual ~NAOperation() = default; - [[nodiscard]] virtual auto clone() const -> std::unique_ptr = 0; -}; -} // namespace na diff --git a/include/mqt-core/na/operations/NAShuttlingOperation.hpp b/include/mqt-core/na/operations/NAShuttlingOperation.hpp deleted file mode 100644 index 89c1aace4..000000000 --- a/include/mqt-core/na/operations/NAShuttlingOperation.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include "../NADefinitions.hpp" -#include "NAOperation.hpp" - -#include -#include -#include -#include -#include -#include -#include -namespace na { - -enum ShuttleType : std::uint8_t { LOAD, MOVE, STORE }; - -class NAShuttlingOperation : public NAOperation { -protected: - ShuttleType type; - std::vector> start; - std::vector> end; - -public: - explicit NAShuttlingOperation( - const ShuttleType shuttleType, - const std::vector>& startConfig, - const std::vector>& endConfig) - : type(shuttleType), start(startConfig), end(endConfig) { - if (startConfig.size() != endConfig.size()) { - throw std::logic_error("Shuttling operation must have the same number of " - "start and end qubits."); - } - } - explicit NAShuttlingOperation(const ShuttleType shuttleType, - std::shared_ptr startPoint, - std::shared_ptr endPoint) - : NAShuttlingOperation( - shuttleType, - std::vector>{std::move(startPoint)}, - std::vector>{std::move(endPoint)}) {} - [[nodiscard]] auto getType() const -> ShuttleType { return type; } - [[nodiscard]] auto getStart() const - -> const std::vector>& { - return start; - } - [[nodiscard]] auto getEnd() const - -> const std::vector>& { - return end; - } - [[nodiscard]] auto isShuttlingOperation() const -> bool override { - return true; - } - [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } -}; -} // namespace na diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp new file mode 100644 index 000000000..18811bb4c --- /dev/null +++ b/include/mqt-core/na/operations/Op.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include +#include + +namespace na { +class Op { +public: + virtual ~Op() = default; + [[nodiscard]] virtual auto toString() const -> std::string = 0; + friend auto operator<<(std::ostream& os, const Op& obj) -> std::ostream& { + return os << obj.toString(); // Using toString() method + } + template [[nodiscard]] auto is() const -> bool { + return dynamic_cast(this) != nullptr; + } + template [[nodiscard]] auto as() -> T& { + return dynamic_cast(*this); + } + template [[nodiscard]] auto as() const -> const T& { + return dynamic_cast(*this); + } +}; +} // namespace na diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp new file mode 100644 index 000000000..7b085b0d5 --- /dev/null +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/entities/Atom.hpp" +#include "na/operations/Op.hpp" + +#include +#include + +namespace na { +class ShuttlingOp : public Op { +protected: + std::vector atoms; + explicit ShuttlingOp(std::vector atoms) + : atoms(std::move(atoms)) {} + +public: + [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } + [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { + return atoms; + } + [[nodiscard]] virtual auto getTargetLocations() -> std::vector& = 0; + [[nodiscard]] virtual auto getTargetLocations() const + -> const std::vector& = 0; +}; +} // namespace na diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp new file mode 100644 index 000000000..fff6a2746 --- /dev/null +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#pragma once + +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" +#include "na/operations/ShuttlingOp.hpp" + +#include +#include +#include +#include + +namespace na { + +class StoreOp : public ShuttlingOp { +protected: + std::optional> targetLocations = std::nullopt; + +public: + explicit StoreOp(std::vector atoms, + std::vector targetLocations) + : ShuttlingOp(std::move(atoms)), + targetLocations(std::move(targetLocations)) { + if (this->atoms.size() != this->targetLocations->size()) { + throw std::invalid_argument( + "Number of atoms and target locations must be equal."); + } + } + explicit StoreOp(std::vector atoms) + : ShuttlingOp(std::move(atoms)) {} + [[nodiscard]] auto hasTargetLocations() const -> bool { + return targetLocations.has_value(); + } + [[nodiscard]] auto getTargetLocations() -> std::vector& override { + if (!targetLocations.has_value()) { + throw std::logic_error("Operation has no target locations set."); + } + return *targetLocations; + } + [[nodiscard]] auto getTargetLocations() const + -> const std::vector& override { + if (!targetLocations.has_value()) { + throw std::logic_error("Operation has no target locations set."); + } + return *targetLocations; + } + [[nodiscard]] auto toString() const -> std::string override; +}; +} // namespace na diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index eb692f2fb..f47ddfb42 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -9,103 +9,120 @@ #include "na/NAComputation.hpp" -#include "na/operations/NALocalOperation.hpp" -#include "na/operations/NAShuttlingOperation.hpp" +#include "na/operations/LoadOp.hpp" +#include "na/operations/LocalOp.hpp" +#include "na/operations/ShuttlingOp.hpp" +#include "na/operations/StoreOp.hpp" +#include #include -#include #include #include #include +#include +#include namespace na { auto NAComputation::toString() const -> std::string { std::stringstream ss; - ss << "init at "; - for (const auto& p : initialPositions) { - ss << *p << ", "; + for (const auto& [atom, loc] : initialLocations) { + ss << "atom " << loc << " " << *atom << "\n"; } - if (ss.tellp() == 8) { - ss.seekp(-1, std::ios_base::end); - } else { - ss.seekp(-2, std::ios_base::end); - } - ss << ";\n"; - for (const auto& op : operations) { - ss << *op; + for (const auto& op : *this) { + ss << op << "\n"; } return ss.str(); } -auto NAComputation::validateAODConstraints() const -> bool { +auto NAComputation::validate() const -> bool { std::size_t counter = 1; // the first operation is `init at ...;` - for (const auto& naOp : operations) { + std::unordered_map currentLocations = initialLocations; + std::unordered_set currentlyShuttling{}; + for (const auto& op : *this) { ++counter; - if (naOp->isShuttlingOperation()) { - const auto& shuttlingOp = - dynamic_cast(*naOp); - if (shuttlingOp.getStart().size() != shuttlingOp.getEnd().size()) { - return false; - } - for (std::size_t i = 0; i < shuttlingOp.getStart().size(); ++i) { - for (std::size_t j = i + 1; j < shuttlingOp.getStart().size(); ++j) { - const auto& s1 = shuttlingOp.getStart()[i]; - const auto& s2 = shuttlingOp.getStart()[j]; - const auto& e1 = shuttlingOp.getEnd()[i]; - const auto& e2 = shuttlingOp.getEnd()[j]; - if (*s1 == *s2) { - std::cout << "Error in op number " << counter - << " (two start points identical)\n"; - return false; - } - if (*e1 == *e2) { - std::cout << "Error in op number " << counter - << " (two end points identical)\n"; - return false; - } - if (s1->x == s2->x && e1->x != e2->x) { - std::cout << "Error in op number " << counter - << " (columns not preserved)\n"; - return false; - } - if (s1->y == s2->y && e1->y != e2->y) { - std::cout << "Error in op number " << counter - << " (rows not preserved)\n"; - return false; - } - if (s1->x < s2->x && e1->x >= e2->x) { - std::cout << "Error in op number " << counter - << " (column order not preserved)\n"; - return false; - } - if (s1->y < s2->y && e1->y >= e2->y) { - std::cout << "Error in op number " << counter - << " (row order not preserved)\n"; - return false; - } - if (s1->x > s2->x && e1->x <= e2->x) { - std::cout << "Error in op number " << counter - << " (column order not preserved)\n"; - return false; - } - if (s1->y > s2->y && e1->y <= e2->y) { - std::cout << "Error in op number " << counter - << " (row order not preserved)\n"; - return false; - } + if (op.is()) { + const auto& shuttlingOp = op.as(); + const auto& atoms = shuttlingOp.getAtoms(); + if (shuttlingOp.is()) { + if (std::any_of(atoms.begin(), atoms.end(), + [¤tLocations](const auto* atom) { + return currentLocations.find(atom) != + currentLocations.end(); + })) { + std::cout << "Error in op number " << counter + << " (atom already loaded)\n"; + return false; + } + std::for_each(atoms.begin(), atoms.end(), + [¤tlyShuttling](const auto* atom) { + currentlyShuttling.insert(atom); + }); + } else { + if (std::any_of(atoms.begin(), atoms.end(), + [¤tlyShuttling](const auto* atom) { + return currentlyShuttling.find(atom) == + currentlyShuttling.end(); + })) { + std::cout << "Error in op number " << counter + << " (atom not loaded)\n"; + return false; } } - } else if (naOp->isLocalOperation()) { - const auto& localOp = dynamic_cast(*naOp); - for (std::size_t i = 0; i < localOp.getPositions().size(); ++i) { - for (std::size_t j = i + 1; j < localOp.getPositions().size(); ++j) { - const auto& a = localOp.getPositions()[i]; - const auto& b = localOp.getPositions()[j]; - if (*a == *b) { - std::cout << "Error in op number " << counter - << " (identical positions)\n"; - return false; + if ((op.is() && op.as().hasTargetLocations()) || + (op.is() && op.as().hasTargetLocations())) { + const auto& targetLocations = shuttlingOp.getTargetLocations(); + for (std::size_t i = 0; i < atoms.size(); ++i) { + const auto* a = atoms[i]; + for (std::size_t j = i + 1; j < atoms.size(); ++j) { + const auto* b = atoms[j]; + const auto& s1 = currentLocations[a]; + const auto& s2 = currentLocations[b]; + const auto& e1 = targetLocations[i]; + const auto& e2 = targetLocations[j]; + if (e1 == e2) { + std::cout << "Error in op number " << counter + << " (two end points identical)\n"; + return false; + } + if (s1.x == s2.x && e1.x != e2.x) { + std::cout << "Error in op number " << counter + << " (columns not preserved)\n"; + return false; + } + if (s1.y == s2.y && e1.y != e2.y) { + std::cout << "Error in op number " << counter + << " (rows not preserved)\n"; + return false; + } + if (s1.x < s2.x && e1.x >= e2.x) { + std::cout << "Error in op number " << counter + << " (column order not preserved)\n"; + return false; + } + if (s1.y < s2.y && e1.y >= e2.y) { + std::cout << "Error in op number " << counter + << " (row order not preserved)\n"; + return false; + } + if (s1.x > s2.x && e1.x <= e2.x) { + std::cout << "Error in op number " << counter + << " (column order not preserved)\n"; + return false; + } + if (s1.y > s2.y && e1.y <= e2.y) { + std::cout << "Error in op number " << counter + << " (row order not preserved)\n"; + return false; + } } } + for (std::size_t i = 0; i < atoms.size(); ++i) { + currentLocations[atoms[i]] = targetLocations[i]; + } + } + if (shuttlingOp.is()) { + std::for_each(atoms.begin(), atoms.end(), [&](const auto* atom) { + currentlyShuttling.erase(atom); + }); } } } diff --git a/src/na/operations/NAGlobalOperation.cpp b/src/na/operations/GlobalOp.cpp similarity index 61% rename from src/na/operations/NAGlobalOperation.cpp rename to src/na/operations/GlobalOp.cpp index b4848eeb1..73da77da6 100644 --- a/src/na/operations/NAGlobalOperation.cpp +++ b/src/na/operations/GlobalOp.cpp @@ -7,25 +7,24 @@ * Licensed under the MIT License */ -#include "na/operations/NAGlobalOperation.hpp" +#include "na/operations/GlobalRYOp.hpp" +#include #include #include #include namespace na { -auto NAGlobalOperation::toString() const -> std::string { +auto GlobalOp::toString() const -> std::string { std::stringstream ss; - ss << type; + ss << std::setprecision(5) << std::fixed; + ss << "@+ " << name; if (!params.empty()) { - ss << "("; for (const auto& p : params) { - ss << p << ", "; + ss << " " << p; } - ss.seekp(-2, std::ios_base::end); - ss << ")"; } - ss << ";\n"; + ss << " " << zone; return ss.str(); } } // namespace na diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp new file mode 100644 index 000000000..31ec049ed --- /dev/null +++ b/src/na/operations/LoadOp.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "na/operations/LoadOp.hpp" + +#include +#include + +namespace na { +auto LoadOp::toString() const -> std::string { + std::stringstream ss; + ss << "@+ load"; + if (atoms.size() == 1) { + if (targetLocations) { + ss << " " << targetLocations->front(); + } + ss << " " << *atoms.front(); + } else { + ss << " [\n"; + for (std::size_t i = 0; i < atoms.size(); ++i) { + ss << "\t"; + if (targetLocations) { + ss << (*targetLocations)[i] << " "; + } + ss << *atoms[i] << "\n"; + } + ss << "]"; + } + return ss.str(); +} +} // namespace na diff --git a/src/na/operations/LocalOp.cpp b/src/na/operations/LocalOp.cpp new file mode 100644 index 000000000..56e8eec69 --- /dev/null +++ b/src/na/operations/LocalOp.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "na/operations/LocalOp.hpp" + +#include +#include +#include + +namespace na { +auto LocalOp::toString() const -> std::string { + std::stringstream ss; + ss << std::setprecision(5) << std::fixed; + ss << "@+ " << name; + if (atoms.size() == 1) { + if (!params.empty()) { + for (const auto& p : params) { + ss << " " << p; + } + } + ss << " " << *atoms.front(); + } else { + ss << " [\n"; + for (std::size_t i = 0; i < atoms.size(); ++i) { + ss << "\t"; + if (!params.empty()) { + for (const auto& p : params) { + ss << p << " "; + } + } + ss << *atoms[i] << "\n"; + } + ss << "]"; + } + return ss.str(); +} +} // namespace na diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp new file mode 100644 index 000000000..15fcf8676 --- /dev/null +++ b/src/na/operations/MoveOp.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "na/operations/MoveOp.hpp" + +#include +#include + +namespace na { +auto MoveOp::toString() const -> std::string { + std::stringstream ss; + ss << "@+ move"; + if (atoms.size() == 1) { + ss << " " << targetLocations.front() << " " << *atoms.front(); + } else { + ss << " [\n"; + for (std::size_t i = 0; i < atoms.size(); ++i) { + ss << "\t" << targetLocations[i] << " " << *atoms[i] << "\n"; + } + ss << "]"; + } + return ss.str(); +} +} // namespace na diff --git a/src/na/operations/NALocalOperation.cpp b/src/na/operations/NALocalOperation.cpp deleted file mode 100644 index e9fea833d..000000000 --- a/src/na/operations/NALocalOperation.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#include "na/operations/NALocalOperation.hpp" - -#include -#include -#include - -namespace na { -auto NALocalOperation::toString() const -> std::string { - std::stringstream ss; - ss << type; - if (!params.empty()) { - ss << "("; - for (const auto& p : params) { - ss << p << ", "; - } - ss.seekp(-2, std::ios_base::end); - ss << ")"; - } - ss << " at "; - if (positions.empty()) { - ss.seekp(-1, std::ios_base::end); - } else { - for (const auto& p : positions) { - ss << *p << ", "; - } - ss.seekp(-2, std::ios_base::end); - } - ss << ";\n"; - return ss.str(); -} -} // namespace na diff --git a/src/na/operations/NAShuttlingOperation.cpp b/src/na/operations/NAShuttlingOperation.cpp deleted file mode 100644 index a5f01d3ab..000000000 --- a/src/na/operations/NAShuttlingOperation.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#include "na/operations/NAShuttlingOperation.hpp" - -#include -#include -#include - -namespace na { -auto NAShuttlingOperation::toString() const -> std::string { - std::stringstream ss; - switch (type) { - case LOAD: - ss << "load"; - break; - case MOVE: - ss << "move"; - break; - case STORE: - ss << "store"; - break; - } - ss << " "; - for (const auto& p : start) { - ss << *p << ", "; - } - ss.seekp(-2, std::ios_base::end); - ss << " to "; - for (const auto& p : end) { - ss << *p << ", "; - } - ss.seekp(-2, std::ios_base::end); - ss << ";\n"; - return ss.str(); -} -} // namespace na diff --git a/src/na/operations/StoreOp.cpp b/src/na/operations/StoreOp.cpp new file mode 100644 index 000000000..a3a3e2b6a --- /dev/null +++ b/src/na/operations/StoreOp.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "na/operations/StoreOp.hpp" + +#include +#include + +namespace na { +auto StoreOp::toString() const -> std::string { + std::stringstream ss; + ss << "@+ store"; + if (atoms.size() == 1) { + if (targetLocations) { + ss << " " << targetLocations->front(); + } + ss << " " << *atoms.front(); + } else { + ss << " [\n"; + for (std::size_t i = 0; i < atoms.size(); ++i) { + ss << "\t"; + if (targetLocations) { + ss << (*targetLocations)[i] << " "; + } + ss << *atoms[i] << "\n"; + } + ss << "]"; + } + return ss.str(); +} +} // namespace na diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index aa2eb073c..5ac342f5d 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -9,8 +9,8 @@ #include "Definitions.hpp" #include "ir/operations/OpType.hpp" +#include "na/Definitions.hpp" #include "na/NAComputation.hpp" -#include "na/NADefinitions.hpp" #include "na/operations/NAGlobalOperation.hpp" #include "na/operations/NALocalOperation.hpp" #include "na/operations/NAShuttlingOperation.hpp" @@ -23,29 +23,29 @@ namespace na { TEST(NAComputation, General) { auto qc = NAComputation(); - qc.emplaceInitialPosition(std::make_shared(0, 0)); - qc.emplaceInitialPosition(std::make_shared(1, 0)); - qc.emplaceInitialPosition(std::make_shared(2, 0)); + qc.emplaceInitialPosition(std::make_shared(0, 0)); + qc.emplaceInitialPosition(std::make_shared(1, 0)); + qc.emplaceInitialPosition(std::make_shared(2, 0)); qc.emplaceBack(std::make_unique( FullOpType{qc::RZ, 0}, std::vector{qc::PI_2}, - std::make_shared(0, 0))); + std::make_shared(0, 0))); qc.emplaceBack(std::make_unique(FullOpType{qc::RY, 0}, std::vector{qc::PI_2})); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 1)})); qc.emplaceBack(std::make_unique( MOVE, - std::vector{std::make_shared(0, 1), std::make_shared(1, 1)}, - std::vector{std::make_shared(4, 1), - std::make_shared(5, 1)})); + std::vector{std::make_shared(0, 1), std::make_shared(1, 1)}, + std::vector{std::make_shared(4, 1), + std::make_shared(5, 1)})); qc.emplaceBack(std::make_unique( STORE, - std::vector{std::make_shared(4, 1), std::make_shared(5, 1)}, - std::vector{std::make_shared(4, 0), - std::make_shared(5, 0)})); + std::vector{std::make_shared(4, 1), std::make_shared(5, 1)}, + std::vector{std::make_shared(4, 0), + std::make_shared(5, 0)})); std::stringstream ss; ss << qc; EXPECT_EQ(ss.str(), "init at (0, 0), (1, 0), (2, 0);\n" @@ -65,77 +65,77 @@ TEST(NAComputation, EmptyPrint) { TEST(NAComputation, ValidateAODConstraints) { auto qc = NAComputation(); - qc.emplaceInitialPosition(std::make_shared(0, 0)); - qc.emplaceInitialPosition(std::make_shared(1, 0)); - qc.emplaceInitialPosition(std::make_shared(0, 2)); - qc.emplaceInitialPosition(std::make_shared(1, 2)); + qc.emplaceInitialPosition(std::make_shared(0, 0)); + qc.emplaceInitialPosition(std::make_shared(1, 0)); + qc.emplaceInitialPosition(std::make_shared(0, 2)); + qc.emplaceInitialPosition(std::make_shared(1, 2)); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); - EXPECT_TRUE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 1)})); + EXPECT_TRUE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 0)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(0, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 0)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(0, 1)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(0, 1)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 0)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 0)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(1, 1), - std::make_shared(0, 1)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(1, 1), + std::make_shared(0, 1)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(1, 0), std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(1, 0), std::make_shared(0, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 1)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(0, 2)}, - std::vector{std::make_shared(1, 0), - std::make_shared(0, 1)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(0, 2)}, + std::vector{std::make_shared(1, 0), + std::make_shared(0, 1)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 2)}, - std::vector{std::make_shared(0, 2), - std::make_shared(1, 0)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), std::make_shared(1, 2)}, + std::vector{std::make_shared(0, 2), + std::make_shared(1, 0)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( LOAD, - std::vector{std::make_shared(1, 2), std::make_shared(0, 0)}, - std::vector{std::make_shared(1, 0), - std::make_shared(0, 2)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(1, 2), std::make_shared(0, 0)}, + std::vector{std::make_shared(1, 0), + std::make_shared(0, 2)})); + EXPECT_FALSE(qc.validate()); qc.clear(false); qc.emplaceBack(std::make_unique( FullOpType{qc::RZ, 0}, std::vector{qc::PI_2}, - std::vector{std::make_shared(0, 0), - std::make_shared(0, 0)})); - EXPECT_FALSE(qc.validateAODConstraints()); + std::vector{std::make_shared(0, 0), + std::make_shared(0, 0)})); + EXPECT_FALSE(qc.validate()); } } // namespace na diff --git a/test/na/test_nadefinitions.cpp b/test/na/test_nadefinitions.cpp index aeafe1ddd..8324c8230 100644 --- a/test/na/test_nadefinitions.cpp +++ b/test/na/test_nadefinitions.cpp @@ -19,7 +19,7 @@ namespace na { TEST(NADefinitions, Point) { - const Point p(-1, 2); + const Location p(-1, 2); EXPECT_EQ(p.x, -1); EXPECT_EQ(p.y, 2); EXPECT_EQ(p.length(), 2); @@ -27,15 +27,15 @@ TEST(NADefinitions, Point) { std::stringstream ss; ss << p; EXPECT_EQ(ss.str(), "(-1, 2)"); - EXPECT_EQ(p, Point(-1, 2)); - EXPECT_FALSE(p == Point(1, 2)); - EXPECT_EQ(p - Point(1, 2), Point(-2, 0)); - EXPECT_EQ(Point(1, 2) + p, Point(0, 4)); + EXPECT_EQ(p, Location(-1, 2)); + EXPECT_FALSE(p == Location(1, 2)); + EXPECT_EQ(p - Location(1, 2), Location(-2, 0)); + EXPECT_EQ(Location(1, 2) + p, Location(0, 4)); } TEST(NADefinitions, PointDistances) { - const Point p1(0, 0); - const Point p2(3, 4); + const Location p1(0, 0); + const Location p2(3, 4); EXPECT_EQ(p1.getEuclideanDistance(p2), 5); EXPECT_EQ(p1.getManhattanDistanceX(p2), 3); EXPECT_EQ(p1.getManhattanDistanceY(p2), 4); diff --git a/test/na/test_naoperation.cpp b/test/na/test_naoperation.cpp index 7909fdf05..c340ba187 100644 --- a/test/na/test_naoperation.cpp +++ b/test/na/test_naoperation.cpp @@ -9,7 +9,7 @@ #include "Definitions.hpp" #include "ir/operations/OpType.hpp" -#include "na/NADefinitions.hpp" +#include "na/Definitions.hpp" #include "na/operations/NAGlobalOperation.hpp" #include "na/operations/NALocalOperation.hpp" #include "na/operations/NAShuttlingOperation.hpp" @@ -23,17 +23,17 @@ namespace na { TEST(NAOperation, ShuttlingOperation) { const NAShuttlingOperation shuttling( LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)}); + std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 1)}); EXPECT_TRUE(shuttling.isShuttlingOperation()); EXPECT_FALSE(shuttling.isLocalOperation()); EXPECT_EQ(shuttling.getStart()[1]->x, 1); EXPECT_EQ(shuttling.getEnd()[0]->x, 0); EXPECT_ANY_THROW(NAShuttlingOperation( - ShuttleType::STORE, std::vector{std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); + ShuttleType::STORE, std::vector{std::make_shared(0, 0)}, + std::vector{std::make_shared(0, 1), + std::make_shared(1, 1)})); } TEST(NAOperation, GlobalOperation) { @@ -47,7 +47,7 @@ TEST(NAOperation, GlobalOperation) { TEST(NAOperation, LocalOperation) { const NALocalOperation op(FullOpType{qc::RY, 0}, std::vector{qc::PI_2}, - std::make_shared(0, 0)); + std::make_shared(0, 0)); EXPECT_FALSE(op.isShuttlingOperation()); EXPECT_FALSE(op.isGlobalOperation()); EXPECT_TRUE(op.isLocalOperation()); @@ -55,14 +55,14 @@ TEST(NAOperation, LocalOperation) { EXPECT_DOUBLE_EQ(op.getParams()[0], qc::PI_2); EXPECT_EQ(op.getPositions()[0]->x, 0); EXPECT_ANY_THROW( - NALocalOperation(FullOpType{qc::ECR, 0}, std::make_shared(0, 0))); + NALocalOperation(FullOpType{qc::ECR, 0}, std::make_shared(0, 0))); EXPECT_ANY_THROW( - NALocalOperation(FullOpType{qc::RY, 1}, std::make_shared(0, 0))); + NALocalOperation(FullOpType{qc::RY, 1}, std::make_shared(0, 0))); } TEST(NAOperation, EmptyPrint) { const NALocalOperation op(FullOpType{qc::RY, 0}, std::vector{qc::PI_2}, - std::vector>{}); + std::vector>{}); std::stringstream ss; ss << op; EXPECT_EQ(ss.str(), "ry(1.5708) at;\n"); From 3404c852237fc6f85b0728c2d66ede2785c13507 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Sat, 8 Feb 2025 22:04:14 +0100 Subject: [PATCH 02/39] =?UTF-8?q?=F0=9F=A7=AA=20Work=20on=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 45 ++++- include/mqt-core/na/entities/Location.hpp | 26 ++- include/mqt-core/na/operations/LocalOp.hpp | 2 +- include/mqt-core/na/operations/LocalRZOp.hpp | 4 + src/na/NAComputation.cpp | 61 ++++--- src/na/operations/GlobalOp.cpp | 2 +- src/na/operations/LoadOp.cpp | 6 +- src/na/operations/LocalOp.cpp | 8 +- src/na/operations/MoveOp.cpp | 4 +- src/na/operations/StoreOp.cpp | 6 +- test/na/test_nacomputation.cpp | 176 +++++++++---------- test/na/test_nadefinitions.cpp | 54 +----- test/na/test_naoperation.cpp | 70 -------- 13 files changed, 203 insertions(+), 261 deletions(-) delete mode 100644 test/na/test_naoperation.cpp diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 6eff8cc97..4a5705505 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -11,6 +11,7 @@ #include "entities/Atom.hpp" #include "entities/Location.hpp" +#include "entities/Zone.hpp" #include "operations/Op.hpp" #include @@ -20,10 +21,12 @@ #include namespace na { -class NAComputation : std::vector { +class NAComputation final { protected: std::vector atoms; + std::vector zones; std::unordered_map initialLocations; + std::vector> operations; public: NAComputation() = default; @@ -31,14 +34,48 @@ class NAComputation : std::vector { NAComputation(NAComputation&& qc) noexcept = default; NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; - virtual ~NAComputation() = default; - [[nodiscard]] auto getAtoms() -> decltype(atoms)& { + [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } + [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { return atoms; } - [[nodiscard]] auto getInitialLocations() -> + [[nodiscard]] auto getZones() -> decltype(zones)& { return zones; } + [[nodiscard]] auto getZones() const -> const decltype(zones)& { + return zones; + } + [[nodiscard]] auto getInitialLocations() -> decltype(initialLocations)& { + return initialLocations; + } + [[nodiscard]] auto getInitialLocations() const -> const decltype(initialLocations)& { return initialLocations; } + template auto emplaceBack(T&& op) -> std::unique_ptr& { + return operations.emplace_back(std::make_unique(std::forward(op))); + } + template + auto emplaceBack(Args&&... args) -> std::unique_ptr& { + return operations.emplace_back( + std::make_unique(std::forward(args)...)); + } + [[nodiscard]] auto begin() -> decltype(operations)::iterator { + return operations.begin(); + } + [[nodiscard]] auto begin() const -> decltype(operations)::const_iterator { + return operations.begin(); + } + [[nodiscard]] auto end() -> decltype(operations)::iterator { + return operations.end(); + } + [[nodiscard]] auto end() const -> decltype(operations)::const_iterator { + return operations.end(); + } + auto clear() -> void { operations.clear(); } + [[nodiscard]] auto empty() const -> bool { return operations.empty(); } + [[nodiscard]] auto size() const -> std::size_t { return operations.size(); } + [[nodiscard]] auto operator[](std::size_t i) -> Op& { return *operations[i]; } + [[nodiscard]] auto operator[](std::size_t i) const -> const Op& { + return *operations[i]; + } [[nodiscard]] auto toString() const -> std::string; friend auto operator<<(std::ostream& os, const NAComputation& qc) -> std::ostream& { diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index abbe481d9..c5e57c353 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -18,12 +18,15 @@ namespace na { /// Class to store two-dimensional coordinates struct Location final { - double x; - double y; + double x = 0; + double y = 0; Location(const double x, const double y) : x(x), y(y) {}; - Location(const Location& p) = default; - ~Location() = default; + Location() = default; + Location(const Location& loc) = default; + Location(Location&& loc) noexcept = default; Location& operator=(const Location& loc) = default; + Location& operator=(Location&& loc) noexcept = default; + ~Location() = default; Location operator-(const Location& loc) const { return {x - loc.x, y - loc.y}; } @@ -52,6 +55,21 @@ struct Location final { [[nodiscard]] auto operator==(const Location& other) const -> bool { return x == other.x && y == other.y; } + [[nodiscard]] auto operator!=(const Location& other) const -> bool { + return !(*this == other); + } + [[nodiscard]] auto operator<(const Location& other) const -> bool { + return x < other.x || (x == other.x && y < other.y); + } + [[nodiscard]] auto operator>(const Location& other) const -> bool { + return x > other.x || (x == other.x && y > other.y); + } + [[nodiscard]] auto operator<=(const Location& other) const -> bool { + return x <= other.x || (x == other.x && y <= other.y); + } + [[nodiscard]] auto operator>=(const Location& other) const -> bool { + return x >= other.x || (x == other.x && y >= other.y); + } [[maybe_unused]] [[nodiscard]] auto getEuclideanDistance(const Location& loc) const -> double { return (*this - loc).length(); diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp index 706c32682..9bf1e3f1f 100644 --- a/include/mqt-core/na/operations/LocalOp.hpp +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -28,7 +28,7 @@ class LocalOp : public Op { explicit LocalOp(std::vector& atoms) : LocalOp({}, std::move(atoms)) {} explicit LocalOp(std::vector params, const Atom* atom) - : LocalOp(std::move(params), {atom}) {} + : LocalOp(std::move(params), std::vector{atom}) {} explicit LocalOp(const Atom* atom) : LocalOp({}, atom) {} public: diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index 14c8c7a44..46755f363 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -19,5 +19,9 @@ class LocalRZOp final : public LocalOp { LocalRZOp(qc::fp angle, const Atom* atom) : LocalOp({angle}, atom) { name = "rz"; } + LocalRZOp(qc::fp angle, std::vector atom) + : LocalOp({angle}, std::move(atom)) { + name = "rz"; + } }; } // namespace na diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index f47ddfb42..8ac697113 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -25,11 +25,15 @@ namespace na { auto NAComputation::toString() const -> std::string { std::stringstream ss; - for (const auto& [atom, loc] : initialLocations) { + std::vector> initialLocationsAsc( + initialLocations.begin(), initialLocations.end()); + std::sort(initialLocationsAsc.begin(), initialLocationsAsc.end(), + [](const auto& a, const auto& b) { return a.second < b.second; }); + for (const auto& [atom, loc] : initialLocationsAsc) { ss << "atom " << loc << " " << *atom << "\n"; } for (const auto& op : *this) { - ss << op << "\n"; + ss << *op << "\n"; } return ss.str(); } @@ -39,25 +43,25 @@ auto NAComputation::validate() const -> bool { std::unordered_set currentlyShuttling{}; for (const auto& op : *this) { ++counter; - if (op.is()) { - const auto& shuttlingOp = op.as(); - const auto& atoms = shuttlingOp.getAtoms(); + if (op->is()) { + const auto& shuttlingOp = op->as(); + const auto& opAtoms = shuttlingOp.getAtoms(); if (shuttlingOp.is()) { - if (std::any_of(atoms.begin(), atoms.end(), - [¤tLocations](const auto* atom) { - return currentLocations.find(atom) != - currentLocations.end(); + if (std::any_of(opAtoms.begin(), opAtoms.end(), + [¤tlyShuttling](const auto* atom) { + return currentlyShuttling.find(atom) != + currentlyShuttling.end(); })) { std::cout << "Error in op number " << counter << " (atom already loaded)\n"; return false; } - std::for_each(atoms.begin(), atoms.end(), + std::for_each(opAtoms.begin(), opAtoms.end(), [¤tlyShuttling](const auto* atom) { currentlyShuttling.insert(atom); }); } else { - if (std::any_of(atoms.begin(), atoms.end(), + if (std::any_of(opAtoms.begin(), opAtoms.end(), [¤tlyShuttling](const auto* atom) { return currentlyShuttling.find(atom) == currentlyShuttling.end(); @@ -67,13 +71,18 @@ auto NAComputation::validate() const -> bool { return false; } } - if ((op.is() && op.as().hasTargetLocations()) || - (op.is() && op.as().hasTargetLocations())) { + if ((op->is() && op->as().hasTargetLocations()) || + (op->is() && op->as().hasTargetLocations())) { const auto& targetLocations = shuttlingOp.getTargetLocations(); - for (std::size_t i = 0; i < atoms.size(); ++i) { - const auto* a = atoms[i]; - for (std::size_t j = i + 1; j < atoms.size(); ++j) { - const auto* b = atoms[j]; + for (std::size_t i = 0; i < opAtoms.size(); ++i) { + const auto* a = opAtoms[i]; + for (std::size_t j = i + 1; j < opAtoms.size(); ++j) { + const auto* b = opAtoms[j]; + if (a == b) { + std::cout << "Error in op number " << counter + << " (two atoms identical)\n"; + return false; + } const auto& s1 = currentLocations[a]; const auto& s2 = currentLocations[b]; const auto& e1 = targetLocations[i]; @@ -115,15 +124,27 @@ auto NAComputation::validate() const -> bool { } } } - for (std::size_t i = 0; i < atoms.size(); ++i) { - currentLocations[atoms[i]] = targetLocations[i]; + for (std::size_t i = 0; i < opAtoms.size(); ++i) { + currentLocations[opAtoms[i]] = targetLocations[i]; } } if (shuttlingOp.is()) { - std::for_each(atoms.begin(), atoms.end(), [&](const auto* atom) { + std::for_each(opAtoms.begin(), opAtoms.end(), [&](const auto* atom) { currentlyShuttling.erase(atom); }); } + } else if (op->is()) { + const auto& opAtoms = op->as().getAtoms(); + for (std::size_t i = 0; i < opAtoms.size(); ++i) { + const auto* a = opAtoms[i]; + for (std::size_t j = i + 1; j < opAtoms.size(); ++j) { + if (const auto* b = opAtoms[j]; a == b) { + std::cout << "Error in op number " << counter + << " (two atoms identical)\n"; + return false; + } + } + } } } return true; diff --git a/src/na/operations/GlobalOp.cpp b/src/na/operations/GlobalOp.cpp index 73da77da6..b607aea93 100644 --- a/src/na/operations/GlobalOp.cpp +++ b/src/na/operations/GlobalOp.cpp @@ -24,7 +24,7 @@ auto GlobalOp::toString() const -> std::string { ss << " " << p; } } - ss << " " << zone; + ss << " " << *zone; return ss.str(); } } // namespace na diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp index 31ec049ed..dd04bd85c 100644 --- a/src/na/operations/LoadOp.cpp +++ b/src/na/operations/LoadOp.cpp @@ -20,15 +20,15 @@ auto LoadOp::toString() const -> std::string { if (targetLocations) { ss << " " << targetLocations->front(); } - ss << " " << *atoms.front(); + ss << " " << *(atoms.front()); } else { ss << " [\n"; for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << "\t"; + ss << " "; if (targetLocations) { ss << (*targetLocations)[i] << " "; } - ss << *atoms[i] << "\n"; + ss << *(atoms[i]) << "\n"; } ss << "]"; } diff --git a/src/na/operations/LocalOp.cpp b/src/na/operations/LocalOp.cpp index 56e8eec69..dc9c60864 100644 --- a/src/na/operations/LocalOp.cpp +++ b/src/na/operations/LocalOp.cpp @@ -24,17 +24,17 @@ auto LocalOp::toString() const -> std::string { ss << " " << p; } } - ss << " " << *atoms.front(); + ss << " " << *(atoms.front()); } else { ss << " [\n"; - for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << "\t"; + for (const auto* const atom : atoms) { + ss << " "; if (!params.empty()) { for (const auto& p : params) { ss << p << " "; } } - ss << *atoms[i] << "\n"; + ss << *atom << "\n"; } ss << "]"; } diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp index 15fcf8676..ea8bec2bf 100644 --- a/src/na/operations/MoveOp.cpp +++ b/src/na/operations/MoveOp.cpp @@ -17,11 +17,11 @@ auto MoveOp::toString() const -> std::string { std::stringstream ss; ss << "@+ move"; if (atoms.size() == 1) { - ss << " " << targetLocations.front() << " " << *atoms.front(); + ss << " " << targetLocations.front() << " " << *(atoms.front()); } else { ss << " [\n"; for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << "\t" << targetLocations[i] << " " << *atoms[i] << "\n"; + ss << " " << targetLocations[i] << " " << *(atoms[i]) << "\n"; } ss << "]"; } diff --git a/src/na/operations/StoreOp.cpp b/src/na/operations/StoreOp.cpp index a3a3e2b6a..c71d3108b 100644 --- a/src/na/operations/StoreOp.cpp +++ b/src/na/operations/StoreOp.cpp @@ -20,15 +20,15 @@ auto StoreOp::toString() const -> std::string { if (targetLocations) { ss << " " << targetLocations->front(); } - ss << " " << *atoms.front(); + ss << " " << *(atoms.front()); } else { ss << " [\n"; for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << "\t"; + ss << " "; if (targetLocations) { ss << (*targetLocations)[i] << " "; } - ss << *atoms[i] << "\n"; + ss << *(atoms[i]) << "\n"; } ss << "]"; } diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 5ac342f5d..773c6fbc1 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -9,11 +9,14 @@ #include "Definitions.hpp" #include "ir/operations/OpType.hpp" -#include "na/Definitions.hpp" #include "na/NAComputation.hpp" -#include "na/operations/NAGlobalOperation.hpp" -#include "na/operations/NALocalOperation.hpp" -#include "na/operations/NAShuttlingOperation.hpp" +#include "na/NAUtils.hpp" +#include "na/operations/GlobalOp.hpp" +#include "na/operations/GlobalRYOp.hpp" +#include "na/operations/LoadOp.hpp" +#include "na/operations/LocalRZOp.hpp" +#include "na/operations/MoveOp.hpp" +#include "na/operations/StoreOp.hpp" #include #include @@ -23,119 +26,100 @@ namespace na { TEST(NAComputation, General) { auto qc = NAComputation(); - qc.emplaceInitialPosition(std::make_shared(0, 0)); - qc.emplaceInitialPosition(std::make_shared(1, 0)); - qc.emplaceInitialPosition(std::make_shared(2, 0)); - qc.emplaceBack(std::make_unique( - FullOpType{qc::RZ, 0}, std::vector{qc::PI_2}, - std::make_shared(0, 0))); - qc.emplaceBack(std::make_unique(FullOpType{qc::RY, 0}, - std::vector{qc::PI_2})); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); - qc.emplaceBack(std::make_unique( - MOVE, - std::vector{std::make_shared(0, 1), std::make_shared(1, 1)}, - std::vector{std::make_shared(4, 1), - std::make_shared(5, 1)})); - qc.emplaceBack(std::make_unique( - STORE, - std::vector{std::make_shared(4, 1), std::make_shared(5, 1)}, - std::vector{std::make_shared(4, 0), - std::make_shared(5, 0)})); + const auto* atom0 = &qc.getAtoms().emplace_back("atom0"); + const auto* atom1 = &qc.getAtoms().emplace_back("atom1"); + const auto* atom2 = &qc.getAtoms().emplace_back("atom2"); + const auto* globalZone = &qc.getZones().emplace_back("global"); + qc.getInitialLocations().emplace(atom0, Location{0, 0}); + qc.getInitialLocations().emplace(atom1, Location{1, 0}); + qc.getInitialLocations().emplace(atom2, Location{2, 0}); + qc.emplaceBack(qc::PI_2, atom0); + qc.emplaceBack(qc::PI_2, globalZone); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, 1}}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{4, 1}, Location{5, 1}}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{4, 0}, Location{5, 0}}); std::stringstream ss; ss << qc; - EXPECT_EQ(ss.str(), "init at (0, 0), (1, 0), (2, 0);\n" - "rz(1.5708) at (0, 0);\n" - "ry(1.5708);\n" - "load (0, 0), (1, 0) to (0, 1), (1, 1);\n" - "move (0, 1), (1, 1) to (4, 1), (5, 1);\n" - "store (4, 1), (5, 1) to (4, 0), (5, 0);\n"); + EXPECT_EQ(ss.str(), "atom (0.000, 0.000) atom0\n" + "atom (1.000, 0.000) atom1\n" + "atom (2.000, 0.000) atom2\n" + "@+ rz 1.57080 atom0\n" + "@+ ry 1.5708 global\n" + "@+ load [" + " (1, 0) atom0\n" + " (1, 1) atom1\n" + "]\n" + "@+ move [\n" + " (1, 1) atom0\n" + " (5, 1) atom1\n" + "]\n" + "@+ store [\n" + " (5, 1) atom0\n" + " (5, 0) atom1\n" + "]\n"); } TEST(NAComputation, EmptyPrint) { const NAComputation qc; std::stringstream ss; ss << qc; - EXPECT_EQ(ss.str(), "init at;\n"); + EXPECT_EQ(ss.str(), ""); } TEST(NAComputation, ValidateAODConstraints) { auto qc = NAComputation(); - qc.emplaceInitialPosition(std::make_shared(0, 0)); - qc.emplaceInitialPosition(std::make_shared(1, 0)); - qc.emplaceInitialPosition(std::make_shared(0, 2)); - qc.emplaceInitialPosition(std::make_shared(1, 2)); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); + const auto* atom0 = &qc.getAtoms().emplace_back("atom0"); + const auto* atom1 = &qc.getAtoms().emplace_back("atom1"); + const auto* atom2 = &qc.getAtoms().emplace_back("atom2"); + const auto* atom3 = &qc.getAtoms().emplace_back("atom3"); + qc.getInitialLocations().emplace(atom0, Location{0, 0}); + qc.getInitialLocations().emplace(atom1, Location{1, 0}); + qc.getInitialLocations().emplace(atom2, Location{0, 2}); + qc.getInitialLocations().emplace(atom3, Location{1, 2}); + qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, 1}})); EXPECT_TRUE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 0)})); + // atom already loaded + qc.emplaceBack(LoadOp({atom0}, {Location{0, 1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(0, 1)})); + qc.clear(); + // atom not loaded + qc.emplaceBack(MoveOp({atom0}, {Location{0, 1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 0)})); + qc.clear(); + // two atoms identical + qc.emplaceBack(LoadOp({atom0, atom0}, {Location{0, 1}, Location{1, 1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(1, 1), - std::make_shared(0, 1)})); + qc.clear(); + // two end points identical + qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{0, 1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(1, 0), std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); + qc.clear(); + // columns not preserved + qc.emplaceBack(LoadOp({atom1, atom3}, {Location{0, 1}, Location{2, 2}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(0, 2)}, - std::vector{std::make_shared(1, 0), - std::make_shared(0, 1)})); + qc.clear(); + // rows not preserved + qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, -1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 2)}, - std::vector{std::make_shared(0, 2), - std::make_shared(1, 0)})); + qc.clear(); + // column order not preserved + qc.emplaceBack(LoadOp({atom0, atom3}, {Location{1, 1}, Location{0, 1}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - LOAD, - std::vector{std::make_shared(1, 2), std::make_shared(0, 0)}, - std::vector{std::make_shared(1, 0), - std::make_shared(0, 2)})); + qc.clear(); + // row order not preserved + qc.emplaceBack(LoadOp({atom0, atom3}, {Location{0, 1}, Location{2, 0}})); EXPECT_FALSE(qc.validate()); - qc.clear(false); - qc.emplaceBack(std::make_unique( - FullOpType{qc::RZ, 0}, std::vector{qc::PI_2}, - std::vector{std::make_shared(0, 0), - std::make_shared(0, 0)})); + qc.clear(); + // column order not preserved + qc.emplaceBack(LoadOp({atom2, atom1}, {Location{1, 3}, Location{0, 1}})); + EXPECT_FALSE(qc.validate()); + qc.clear(); + // row order not preserved + qc.emplaceBack(LoadOp({atom2, atom1}, {Location{0, 1}, Location{2, 2}})); + EXPECT_FALSE(qc.validate()); + qc.clear(); + // two atoms identical + qc.emplaceBack(LocalRZOp(qc::PI_2, {atom0, atom0})); EXPECT_FALSE(qc.validate()); } } // namespace na diff --git a/test/na/test_nadefinitions.cpp b/test/na/test_nadefinitions.cpp index 8324c8230..ce64f963d 100644 --- a/test/na/test_nadefinitions.cpp +++ b/test/na/test_nadefinitions.cpp @@ -8,53 +8,13 @@ */ #include "ir/QuantumComputation.hpp" -#include "ir/operations/OpType.hpp" -#include "na/NADefinitions.hpp" +#include "na/NAUtils.hpp" #include "qasm3/Importer.hpp" #include -#include #include -#include namespace na { -TEST(NADefinitions, Point) { - const Location p(-1, 2); - EXPECT_EQ(p.x, -1); - EXPECT_EQ(p.y, 2); - EXPECT_EQ(p.length(), 2); - EXPECT_EQ(p.toString(), "(-1, 2)"); - std::stringstream ss; - ss << p; - EXPECT_EQ(ss.str(), "(-1, 2)"); - EXPECT_EQ(p, Location(-1, 2)); - EXPECT_FALSE(p == Location(1, 2)); - EXPECT_EQ(p - Location(1, 2), Location(-2, 0)); - EXPECT_EQ(Location(1, 2) + p, Location(0, 4)); -} - -TEST(NADefinitions, PointDistances) { - const Location p1(0, 0); - const Location p2(3, 4); - EXPECT_EQ(p1.getEuclideanDistance(p2), 5); - EXPECT_EQ(p1.getManhattanDistanceX(p2), 3); - EXPECT_EQ(p1.getManhattanDistanceY(p2), 4); - EXPECT_EQ(p2.getManhattanDistanceX(p1), 3); - EXPECT_EQ(p2.getManhattanDistanceY(p1), 4); -} - -TEST(NADefinitions, OpType) { - constexpr FullOpType t{qc::OpType::X, 1}; - EXPECT_EQ(t.type, qc::OpType::X); - EXPECT_EQ(t.nControls, 1); - EXPECT_EQ(t.toString(), "cx"); - std::stringstream ss; - ss << t; - EXPECT_EQ(ss.str(), "cx"); - EXPECT_EQ(t, (FullOpType{qc::OpType::X, 1})); - EXPECT_FALSE(t == (FullOpType{qc::OpType::X, 2})); -} - TEST(NADefinitions, IsGlobal) { const std::string testfile = "OPENQASM 3.0;\n" "include \"stdgates.inc\";\n" @@ -66,16 +26,4 @@ TEST(NADefinitions, IsGlobal) { EXPECT_FALSE(isGlobal(*qc.at(0), 3)); EXPECT_TRUE(isGlobal(*qc.at(1), 3)); } - -TEST(NADefinitions, OpTypeHash) { - std::unordered_map map; - map[FullOpType{qc::OpType::X, 1}] = 1; - map[FullOpType{qc::OpType::X, 2}] = 2; - map[FullOpType{qc::OpType::Y, 1}] = 3; - map[FullOpType{qc::OpType::Y, 2}] = 4; - EXPECT_EQ((map[FullOpType{qc::OpType::X, 1}]), 1); - EXPECT_EQ((map[FullOpType{qc::OpType::X, 2}]), 2); - EXPECT_EQ((map[FullOpType{qc::OpType::Y, 1}]), 3); - EXPECT_EQ((map[FullOpType{qc::OpType::Y, 2}]), 4); -} } // namespace na diff --git a/test/na/test_naoperation.cpp b/test/na/test_naoperation.cpp deleted file mode 100644 index c340ba187..000000000 --- a/test/na/test_naoperation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#include "Definitions.hpp" -#include "ir/operations/OpType.hpp" -#include "na/Definitions.hpp" -#include "na/operations/NAGlobalOperation.hpp" -#include "na/operations/NALocalOperation.hpp" -#include "na/operations/NAShuttlingOperation.hpp" - -#include -#include -#include -#include - -namespace na { -TEST(NAOperation, ShuttlingOperation) { - const NAShuttlingOperation shuttling( - LOAD, - std::vector{std::make_shared(0, 0), std::make_shared(1, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)}); - EXPECT_TRUE(shuttling.isShuttlingOperation()); - EXPECT_FALSE(shuttling.isLocalOperation()); - EXPECT_EQ(shuttling.getStart()[1]->x, 1); - EXPECT_EQ(shuttling.getEnd()[0]->x, 0); - EXPECT_ANY_THROW(NAShuttlingOperation( - ShuttleType::STORE, std::vector{std::make_shared(0, 0)}, - std::vector{std::make_shared(0, 1), - std::make_shared(1, 1)})); -} - -TEST(NAOperation, GlobalOperation) { - const NAGlobalOperation op(FullOpType{qc::RY, 0}, std::vector{qc::PI_2}); - EXPECT_FALSE(op.isShuttlingOperation()); - EXPECT_FALSE(op.isLocalOperation()); - EXPECT_TRUE(op.isGlobalOperation()); - EXPECT_DOUBLE_EQ(op.getParams()[0], qc::PI_2); - EXPECT_ANY_THROW(NAGlobalOperation(FullOpType{qc::ECR, 0})); -} - -TEST(NAOperation, LocalOperation) { - const NALocalOperation op(FullOpType{qc::RY, 0}, std::vector{qc::PI_2}, - std::make_shared(0, 0)); - EXPECT_FALSE(op.isShuttlingOperation()); - EXPECT_FALSE(op.isGlobalOperation()); - EXPECT_TRUE(op.isLocalOperation()); - EXPECT_EQ(op.getType(), (FullOpType{qc::RY, 0})); - EXPECT_DOUBLE_EQ(op.getParams()[0], qc::PI_2); - EXPECT_EQ(op.getPositions()[0]->x, 0); - EXPECT_ANY_THROW( - NALocalOperation(FullOpType{qc::ECR, 0}, std::make_shared(0, 0))); - EXPECT_ANY_THROW( - NALocalOperation(FullOpType{qc::RY, 1}, std::make_shared(0, 0))); -} - -TEST(NAOperation, EmptyPrint) { - const NALocalOperation op(FullOpType{qc::RY, 0}, std::vector{qc::PI_2}, - std::vector>{}); - std::stringstream ss; - ss << op; - EXPECT_EQ(ss.str(), "ry(1.5708) at;\n"); -} -} // namespace na From a8758e70d39d9c25a7787491594b78d3f9226e33 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Sat, 8 Feb 2025 23:27:14 +0100 Subject: [PATCH 03/39] =?UTF-8?q?=F0=9F=90=9B=20Use=20unique=20pointers=20?= =?UTF-8?q?to=20avoid=20invalidated=20pointers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 56 ++++++++++----------------- test/na/test_nacomputation.cpp | 46 +++++++++++----------- 2 files changed, 43 insertions(+), 59 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 4a5705505..ef2d894f1 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -21,61 +21,45 @@ #include namespace na { -class NAComputation final { +class NAComputation final : protected std::vector> { protected: - std::vector atoms; - std::vector zones; + std::vector> atoms; + std::vector> zones; std::unordered_map initialLocations; - std::vector> operations; public: + using std::vector>::begin; + using std::vector>::clear; + using std::vector>::end; + using std::vector>::size; + using std::vector>::operator[]; NAComputation() = default; NAComputation(const NAComputation& qc) = default; NAComputation(NAComputation&& qc) noexcept = default; NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; - [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } - [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { - return atoms; + auto emplaceBackAtom(std::string name) -> const Atom* { + return atoms.emplace_back(std::make_unique(std::move(name))).get(); } - [[nodiscard]] auto getZones() -> decltype(zones)& { return zones; } - [[nodiscard]] auto getZones() const -> const decltype(zones)& { - return zones; + auto emplaceBackZone(std::string name) -> const Zone* { + return zones.emplace_back(std::make_unique(std::move(name))).get(); } - [[nodiscard]] auto getInitialLocations() -> decltype(initialLocations)& { - return initialLocations; + auto emplaceBackInitialLocation(const Atom* atom, const Location& loc) -> void { + initialLocations.emplace(atom, loc); } - [[nodiscard]] auto getInitialLocations() const -> const - decltype(initialLocations)& { - return initialLocations; + template + auto emplaceBackInitialLocation(const Atom* atom, Args&&... loc) -> void { + initialLocations.emplace(atom, Location(std::forward(loc)...)); } template auto emplaceBack(T&& op) -> std::unique_ptr& { - return operations.emplace_back(std::make_unique(std::forward(op))); + return std::vector>::emplace_back( + std::make_unique(std::forward(op))); } template auto emplaceBack(Args&&... args) -> std::unique_ptr& { - return operations.emplace_back( + return std::vector>::emplace_back( std::make_unique(std::forward(args)...)); } - [[nodiscard]] auto begin() -> decltype(operations)::iterator { - return operations.begin(); - } - [[nodiscard]] auto begin() const -> decltype(operations)::const_iterator { - return operations.begin(); - } - [[nodiscard]] auto end() -> decltype(operations)::iterator { - return operations.end(); - } - [[nodiscard]] auto end() const -> decltype(operations)::const_iterator { - return operations.end(); - } - auto clear() -> void { operations.clear(); } - [[nodiscard]] auto empty() const -> bool { return operations.empty(); } - [[nodiscard]] auto size() const -> std::size_t { return operations.size(); } - [[nodiscard]] auto operator[](std::size_t i) -> Op& { return *operations[i]; } - [[nodiscard]] auto operator[](std::size_t i) const -> const Op& { - return *operations[i]; - } [[nodiscard]] auto toString() const -> std::string; friend auto operator<<(std::ostream& os, const NAComputation& qc) -> std::ostream& { diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 773c6fbc1..29ba4e962 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -26,13 +26,13 @@ namespace na { TEST(NAComputation, General) { auto qc = NAComputation(); - const auto* atom0 = &qc.getAtoms().emplace_back("atom0"); - const auto* atom1 = &qc.getAtoms().emplace_back("atom1"); - const auto* atom2 = &qc.getAtoms().emplace_back("atom2"); - const auto* globalZone = &qc.getZones().emplace_back("global"); - qc.getInitialLocations().emplace(atom0, Location{0, 0}); - qc.getInitialLocations().emplace(atom1, Location{1, 0}); - qc.getInitialLocations().emplace(atom2, Location{2, 0}); + const auto* const atom0 = qc.emplaceBackAtom("atom0"); + const auto* const atom1 = qc.emplaceBackAtom("atom1"); + const auto* const atom2 = qc.emplaceBackAtom("atom2"); + const auto* const globalZone = qc.emplaceBackZone("global"); + qc.emplaceBackInitialLocation(atom0, 0, 0); + qc.emplaceBackInitialLocation(atom1, 1, 0); + qc.emplaceBackInitialLocation(atom2, 2, 0); qc.emplaceBack(qc::PI_2, atom0); qc.emplaceBack(qc::PI_2, globalZone); qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, 1}}); @@ -44,18 +44,18 @@ TEST(NAComputation, General) { "atom (1.000, 0.000) atom1\n" "atom (2.000, 0.000) atom2\n" "@+ rz 1.57080 atom0\n" - "@+ ry 1.5708 global\n" - "@+ load [" - " (1, 0) atom0\n" - " (1, 1) atom1\n" + "@+ ry 1.57080 global\n" + "@+ load [\n" + " (0.000, 1.000) atom0\n" + " (1.000, 1.000) atom1\n" "]\n" "@+ move [\n" - " (1, 1) atom0\n" - " (5, 1) atom1\n" + " (4.000, 1.000) atom0\n" + " (5.000, 1.000) atom1\n" "]\n" "@+ store [\n" - " (5, 1) atom0\n" - " (5, 0) atom1\n" + " (4.000, 0.000) atom0\n" + " (5.000, 0.000) atom1\n" "]\n"); } @@ -68,14 +68,14 @@ TEST(NAComputation, EmptyPrint) { TEST(NAComputation, ValidateAODConstraints) { auto qc = NAComputation(); - const auto* atom0 = &qc.getAtoms().emplace_back("atom0"); - const auto* atom1 = &qc.getAtoms().emplace_back("atom1"); - const auto* atom2 = &qc.getAtoms().emplace_back("atom2"); - const auto* atom3 = &qc.getAtoms().emplace_back("atom3"); - qc.getInitialLocations().emplace(atom0, Location{0, 0}); - qc.getInitialLocations().emplace(atom1, Location{1, 0}); - qc.getInitialLocations().emplace(atom2, Location{0, 2}); - qc.getInitialLocations().emplace(atom3, Location{1, 2}); + const auto* const atom0 = qc.emplaceBackAtom("atom0"); + const auto* const atom1 = qc.emplaceBackAtom("atom1"); + const auto* const atom2 = qc.emplaceBackAtom("atom2"); + const auto* const atom3 = qc.emplaceBackAtom("atom3"); + qc.emplaceBackInitialLocation(atom0, 0, 0); + qc.emplaceBackInitialLocation(atom1, 1, 0); + qc.emplaceBackInitialLocation(atom2, 0, 2); + qc.emplaceBackInitialLocation(atom3, 1, 2); qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, 1}})); EXPECT_TRUE(qc.validate()); // atom already loaded From 5d28e53885a8cdc2e99d747e09f1e194085f6b86 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Sat, 8 Feb 2025 23:37:02 +0100 Subject: [PATCH 04/39] =?UTF-8?q?=F0=9F=8E=A8=20Add=20hash=20for=20pair=20?= =?UTF-8?q?replacing=20FullOpType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAUtils.hpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp index 052c8835b..7ddbed80c 100644 --- a/include/mqt-core/na/NAUtils.hpp +++ b/include/mqt-core/na/NAUtils.hpp @@ -48,5 +48,20 @@ namespace na { } return false; } - } // namespace na + +template <> struct std::hash> { + std::size_t operator()(const std::pair& t) const noexcept { + const std::size_t h1 = std::hash{}(t.first); + const std::size_t h2 = std::hash{}(t.second); + return qc::combineHash(h1, h2); + } +}; + +template <> struct std::hash> { + std::size_t operator()(const std::pair& p) const noexcept { + const std::size_t h1 = std::hash{}(p.first); + const std::size_t h2 = std::hash{}(p.second); + return qc::combineHash(h1, h2); + } +}; From 2975642f53582dad740296b6a16739cf45b9170d Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Sun, 9 Feb 2025 00:40:59 +0100 Subject: [PATCH 05/39] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bug=20in=20validate?= =?UTF-8?q?=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/na/NAComputation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 8ac697113..d4df47ed8 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -72,7 +72,7 @@ auto NAComputation::validate() const -> bool { } } if ((op->is() && op->as().hasTargetLocations()) || - (op->is() && op->as().hasTargetLocations())) { + (op->is() && op->as().hasTargetLocations())) { const auto& targetLocations = shuttlingOp.getTargetLocations(); for (std::size_t i = 0; i < opAtoms.size(); ++i) { const auto* a = opAtoms[i]; From 1ab326201ccf9fa015162b376d5ea7cb2b77be47 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 09:23:01 +0100 Subject: [PATCH 06/39] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/na/NAComputation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index d4df47ed8..272b5e654 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -39,6 +39,9 @@ auto NAComputation::toString() const -> std::string { } auto NAComputation::validate() const -> bool { std::size_t counter = 1; // the first operation is `init at ...;` + if (atoms.size() != initialLocations.size()) { + std::cout << "Number of atoms and initial locations must be equal\n"; + } std::unordered_map currentLocations = initialLocations; std::unordered_set currentlyShuttling{}; for (const auto& op : *this) { From 45514c8d338f86f616b7e82d3bc7b372893ffc27 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:13:58 +0100 Subject: [PATCH 07/39] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20inteface=20of=20?= =?UTF-8?q?NAComputation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 27 +++++++++++++++++++++++---- src/na/NAComputation.cpp | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index ef2d894f1..827dddbf8 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -12,6 +12,7 @@ #include "entities/Atom.hpp" #include "entities/Location.hpp" #include "entities/Zone.hpp" +#include "operations/MoveOp.hpp" #include "operations/Op.hpp" #include @@ -38,6 +39,24 @@ class NAComputation final : protected std::vector> { NAComputation(NAComputation&& qc) noexcept = default; NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; + [[nodiscard]] auto getAtomsSize() const -> std::size_t { return atoms.size(); } + [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { + return atoms; + } + [[nodiscard]] auto getLocationOfAtomAfterOperation(const std::unique_ptr& atom, const std::unique_ptr& op) const + -> Location { + return getLocationOfAtomAfterOperation(atom.get(), op.get()); + } + [[nodiscard]] auto getLocationOfAtomAfterOperation(const std::unique_ptr& atom, const Op* op) const + -> Location { + return getLocationOfAtomAfterOperation(atom.get(), op); + } + [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, const std::unique_ptr& op) const + -> Location { + return getLocationOfAtomAfterOperation(atom, op.get()); + } + [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, const Op* op) const + -> Location; auto emplaceBackAtom(std::string name) -> const Atom* { return atoms.emplace_back(std::make_unique(std::move(name))).get(); } @@ -51,14 +70,14 @@ class NAComputation final : protected std::vector> { auto emplaceBackInitialLocation(const Atom* atom, Args&&... loc) -> void { initialLocations.emplace(atom, Location(std::forward(loc)...)); } - template auto emplaceBack(T&& op) -> std::unique_ptr& { + template auto emplaceBack(T&& op) -> const Op* { return std::vector>::emplace_back( - std::make_unique(std::forward(op))); + std::make_unique(std::forward(op))).get(); } template - auto emplaceBack(Args&&... args) -> std::unique_ptr& { + auto emplaceBack(Args&&... args) -> const Op* { return std::vector>::emplace_back( - std::make_unique(std::forward(args)...)); + std::make_unique(std::forward(args)...)).get(); } [[nodiscard]] auto toString() const -> std::string; friend auto operator<<(std::ostream& os, const NAComputation& qc) diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 272b5e654..eb05a208f 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -23,6 +23,28 @@ #include namespace na { +auto NAComputation::getLocationOfAtomAfterOperation(const Atom* atom, + const Op* op) const + -> Location { + auto currentLocation = initialLocations.at(atom); + for (const auto& opUniquePtr : *this) { + if (opUniquePtr->is()) { + const auto& moveOp = opUniquePtr->as(); + const auto& opAtoms = moveOp.getAtoms(); + const auto& targetLocations = moveOp.getTargetLocations(); + for (std::size_t k = 0; k < opAtoms.size(); ++k) { + if (opAtoms[k] == atom) { + currentLocation = targetLocations[k]; + break; + } + } + } + if (opUniquePtr.get() == op) { + break; + } + } + return currentLocation; +} auto NAComputation::toString() const -> std::string { std::stringstream ss; std::vector> initialLocationsAsc( From 35f8683436433b03a1862a93dc108e8dbc863113 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:15:14 +0100 Subject: [PATCH 08/39] =?UTF-8?q?=F0=9F=8E=A8=20Pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 35 ++++++++++++------- include/mqt-core/na/NAUtils.hpp | 6 ++-- include/mqt-core/na/operations/GlobalCZOp.hpp | 4 +-- .../mqt-core/na/operations/ShuttlingOp.hpp | 2 +- test/na/test_nacomputation.cpp | 9 +++-- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 827dddbf8..06fd6b20c 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -39,23 +39,29 @@ class NAComputation final : protected std::vector> { NAComputation(NAComputation&& qc) noexcept = default; NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; - [[nodiscard]] auto getAtomsSize() const -> std::size_t { return atoms.size(); } + [[nodiscard]] auto getAtomsSize() const -> std::size_t { + return atoms.size(); + } [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { return atoms; } - [[nodiscard]] auto getLocationOfAtomAfterOperation(const std::unique_ptr& atom, const std::unique_ptr& op) const + [[nodiscard]] auto + getLocationOfAtomAfterOperation(const std::unique_ptr& atom, + const std::unique_ptr& op) const -> Location { - return getLocationOfAtomAfterOperation(atom.get(), op.get()); + return getLocationOfAtomAfterOperation(atom.get(), op.get()); } - [[nodiscard]] auto getLocationOfAtomAfterOperation(const std::unique_ptr& atom, const Op* op) const - -> Location { - return getLocationOfAtomAfterOperation(atom.get(), op); + [[nodiscard]] auto + getLocationOfAtomAfterOperation(const std::unique_ptr& atom, + const Op* op) const -> Location { + return getLocationOfAtomAfterOperation(atom.get(), op); } - [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, const std::unique_ptr& op) const - -> Location { - return getLocationOfAtomAfterOperation(atom, op.get()); + [[nodiscard]] auto getLocationOfAtomAfterOperation( + const Atom* atom, const std::unique_ptr& op) const -> Location { + return getLocationOfAtomAfterOperation(atom, op.get()); } - [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, const Op* op) const + [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, + const Op* op) const -> Location; auto emplaceBackAtom(std::string name) -> const Atom* { return atoms.emplace_back(std::make_unique(std::move(name))).get(); @@ -63,7 +69,8 @@ class NAComputation final : protected std::vector> { auto emplaceBackZone(std::string name) -> const Zone* { return zones.emplace_back(std::make_unique(std::move(name))).get(); } - auto emplaceBackInitialLocation(const Atom* atom, const Location& loc) -> void { + auto emplaceBackInitialLocation(const Atom* atom, const Location& loc) + -> void { initialLocations.emplace(atom, loc); } template @@ -72,12 +79,14 @@ class NAComputation final : protected std::vector> { } template auto emplaceBack(T&& op) -> const Op* { return std::vector>::emplace_back( - std::make_unique(std::forward(op))).get(); + std::make_unique(std::forward(op))) + .get(); } template auto emplaceBack(Args&&... args) -> const Op* { return std::vector>::emplace_back( - std::make_unique(std::forward(args)...)).get(); + std::make_unique(std::forward(args)...)) + .get(); } [[nodiscard]] auto toString() const -> std::string; friend auto operator<<(std::ostream& os, const NAComputation& qc) diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp index 7ddbed80c..6e5bca8ef 100644 --- a/include/mqt-core/na/NAUtils.hpp +++ b/include/mqt-core/na/NAUtils.hpp @@ -51,7 +51,8 @@ namespace na { } // namespace na template <> struct std::hash> { - std::size_t operator()(const std::pair& t) const noexcept { + std::size_t + operator()(const std::pair& t) const noexcept { const std::size_t h1 = std::hash{}(t.first); const std::size_t h2 = std::hash{}(t.second); return qc::combineHash(h1, h2); @@ -59,7 +60,8 @@ template <> struct std::hash> { }; template <> struct std::hash> { - std::size_t operator()(const std::pair& p) const noexcept { + std::size_t + operator()(const std::pair& p) const noexcept { const std::size_t h1 = std::hash{}(p.first); const std::size_t h2 = std::hash{}(p.second); return qc::combineHash(h1, h2); diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index 76344e410..cca06ecac 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -14,8 +14,6 @@ namespace na { class GlobalCZOp final : public GlobalOp { public: - explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { - name = "cz"; - } + explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { name = "cz"; } }; } // namespace na diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp index 7b085b0d5..410a17893 100644 --- a/include/mqt-core/na/operations/ShuttlingOp.hpp +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -12,8 +12,8 @@ #include "na/entities/Atom.hpp" #include "na/operations/Op.hpp" -#include #include +#include namespace na { class ShuttlingOp : public Op { diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 29ba4e962..53ce0f3d3 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -35,9 +35,12 @@ TEST(NAComputation, General) { qc.emplaceBackInitialLocation(atom2, 2, 0); qc.emplaceBack(qc::PI_2, atom0); qc.emplaceBack(qc::PI_2, globalZone); - qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, 1}}); - qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{4, 1}, Location{5, 1}}); - qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{4, 0}, Location{5, 0}}); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{0, 1}, Location{1, 1}}); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{4, 1}, Location{5, 1}}); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{4, 0}, Location{5, 0}}); std::stringstream ss; ss << qc; EXPECT_EQ(ss.str(), "atom (0.000, 0.000) atom0\n" From c7b542de91c51ff1897366af73a73f1b83683ec8 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:17:00 +0100 Subject: [PATCH 09/39] =?UTF-8?q?=F0=9F=8E=A8=20Change=20function=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 5 ++--- test/na/test_nacomputation.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 06fd6b20c..624c56949 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -69,12 +69,11 @@ class NAComputation final : protected std::vector> { auto emplaceBackZone(std::string name) -> const Zone* { return zones.emplace_back(std::make_unique(std::move(name))).get(); } - auto emplaceBackInitialLocation(const Atom* atom, const Location& loc) - -> void { + auto emplaceInitialLocation(const Atom* atom, const Location& loc) -> void { initialLocations.emplace(atom, loc); } template - auto emplaceBackInitialLocation(const Atom* atom, Args&&... loc) -> void { + auto emplaceInitialLocation(const Atom* atom, Args&&... loc) -> void { initialLocations.emplace(atom, Location(std::forward(loc)...)); } template auto emplaceBack(T&& op) -> const Op* { diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 53ce0f3d3..feb9a6771 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -30,9 +30,9 @@ TEST(NAComputation, General) { const auto* const atom1 = qc.emplaceBackAtom("atom1"); const auto* const atom2 = qc.emplaceBackAtom("atom2"); const auto* const globalZone = qc.emplaceBackZone("global"); - qc.emplaceBackInitialLocation(atom0, 0, 0); - qc.emplaceBackInitialLocation(atom1, 1, 0); - qc.emplaceBackInitialLocation(atom2, 2, 0); + qc.emplaceInitialLocation(atom0, 0, 0); + qc.emplaceInitialLocation(atom1, 1, 0); + qc.emplaceInitialLocation(atom2, 2, 0); qc.emplaceBack(qc::PI_2, atom0); qc.emplaceBack(qc::PI_2, globalZone); qc.emplaceBack(std::vector{atom0, atom1}, @@ -75,10 +75,10 @@ TEST(NAComputation, ValidateAODConstraints) { const auto* const atom1 = qc.emplaceBackAtom("atom1"); const auto* const atom2 = qc.emplaceBackAtom("atom2"); const auto* const atom3 = qc.emplaceBackAtom("atom3"); - qc.emplaceBackInitialLocation(atom0, 0, 0); - qc.emplaceBackInitialLocation(atom1, 1, 0); - qc.emplaceBackInitialLocation(atom2, 0, 2); - qc.emplaceBackInitialLocation(atom3, 1, 2); + qc.emplaceInitialLocation(atom0, 0, 0); + qc.emplaceInitialLocation(atom1, 1, 0); + qc.emplaceInitialLocation(atom2, 0, 2); + qc.emplaceInitialLocation(atom3, 1, 2); qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, 1}})); EXPECT_TRUE(qc.validate()); // atom already loaded From bb59ce882a528736680ceaf58a11d83df7181f83 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:33:28 +0100 Subject: [PATCH 10/39] =?UTF-8?q?=F0=9F=8E=A8=20Implement=20clone=20functi?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/operations/GlobalCZOp.hpp | 3 +++ include/mqt-core/na/operations/GlobalRYOp.hpp | 3 +++ include/mqt-core/na/operations/LoadOp.hpp | 3 +++ include/mqt-core/na/operations/LocalRZOp.hpp | 3 +++ include/mqt-core/na/operations/MoveOp.hpp | 3 +++ include/mqt-core/na/operations/Op.hpp | 1 + include/mqt-core/na/operations/StoreOp.hpp | 3 +++ test/na/na_ops.cpp | 23 +++++++++++++++++++ ...st_nadefinitions.cpp => test_na_utils.cpp} | 0 9 files changed, 42 insertions(+) create mode 100644 test/na/na_ops.cpp rename test/na/{test_nadefinitions.cpp => test_na_utils.cpp} (100%) diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index cca06ecac..be532a5ee 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -15,5 +15,8 @@ namespace na { class GlobalCZOp final : public GlobalOp { public: explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { name = "cz"; } + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index 1e58e7299..f46c4813e 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -17,5 +17,8 @@ class GlobalRYOp final : public GlobalOp { GlobalRYOp(qc::fp angle, const Zone* zone) : GlobalOp({angle}, zone) { name = "ry"; } + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index ed6fdd87f..30d8824f7 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -53,5 +53,8 @@ class LoadOp : public ShuttlingOp { return *targetLocations; } [[nodiscard]] auto toString() const -> std::string override; + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index 46755f363..a0596f884 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -23,5 +23,8 @@ class LocalRZOp final : public LocalOp { : LocalOp({angle}, std::move(atom)) { name = "rz"; } + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index 565f25012..a2f7485f5 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -43,5 +43,8 @@ class MoveOp : public ShuttlingOp { return targetLocations; } [[nodiscard]] auto toString() const -> std::string override; + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp index 18811bb4c..2c895fff8 100644 --- a/include/mqt-core/na/operations/Op.hpp +++ b/include/mqt-core/na/operations/Op.hpp @@ -29,5 +29,6 @@ class Op { template [[nodiscard]] auto as() const -> const T& { return dynamic_cast(*this); } + [[nodiscard]] virtual auto clone() const -> std::unique_ptr = 0; }; } // namespace na diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index fff6a2746..45992dbf5 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -53,5 +53,8 @@ class StoreOp : public ShuttlingOp { return *targetLocations; } [[nodiscard]] auto toString() const -> std::string override; + [[nodiscard]] auto clone() const -> std::unique_ptr override { + return std::make_unique(*this); + } }; } // namespace na diff --git a/test/na/na_ops.cpp b/test/na/na_ops.cpp new file mode 100644 index 000000000..205e178ba --- /dev/null +++ b/test/na/na_ops.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Chair for Design Automation, TUM + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * Licensed under the MIT License + */ + +#include "na/entities/Atom.hpp" +#include "na/operations/LocalRZOp.hpp" + +#include + +namespace na { +TEST(NAOps, Clone) { + const auto* atom0 = new Atom("atom0"); + const auto op = std::make_unique(1.57080, atom0); + auto clone = op->clone(); + EXPECT_NE(clone.get(), op.get()); + EXPECT_EQ(op->toString(), clone->toString()); +} +} // namespace na diff --git a/test/na/test_nadefinitions.cpp b/test/na/test_na_utils.cpp similarity index 100% rename from test/na/test_nadefinitions.cpp rename to test/na/test_na_utils.cpp From 6bb958f4b5c363a4244c3159f5d0b6f4f814aa84 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:36:21 +0100 Subject: [PATCH 11/39] =?UTF-8?q?=F0=9F=8E=A8=20Add=20getter=20for=20initi?= =?UTF-8?q?al=20locations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 624c56949..c345a16a8 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -45,6 +45,10 @@ class NAComputation final : protected std::vector> { [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { return atoms; } + [[nodiscard]] auto getInitialLocations() const -> const + decltype(initialLocations)& { + return initialLocations; + } [[nodiscard]] auto getLocationOfAtomAfterOperation(const std::unique_ptr& atom, const std::unique_ptr& op) const From 9e8bf8cd4ef8575d7cfde270f3fa5ef445a43160 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Tue, 11 Feb 2025 08:15:05 +0100 Subject: [PATCH 12/39] =?UTF-8?q?=F0=9F=8E=A8=20Good=20stuff=20from=20try?= =?UTF-8?q?=20to=20make=20it=20copyable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 9 ++++--- include/mqt-core/na/entities/Atom.hpp | 2 +- include/mqt-core/na/entities/Zone.hpp | 2 +- include/mqt-core/na/operations/Op.hpp | 1 + src/na/NAComputation.cpp | 1 + test/na/na_ops.cpp | 23 ------------------ test/na/test_nacomputation.cpp | 34 +++++++++++++++++---------- 7 files changed, 29 insertions(+), 43 deletions(-) delete mode 100644 test/na/na_ops.cpp diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index c345a16a8..36c5ab67c 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -9,11 +9,10 @@ #pragma once -#include "entities/Atom.hpp" -#include "entities/Location.hpp" -#include "entities/Zone.hpp" -#include "operations/MoveOp.hpp" -#include "operations/Op.hpp" +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" +#include "na/entities/Zone.hpp" +#include "na/operations/Op.hpp" #include #include diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp index 67e3d34dc..09c6dbaf8 100644 --- a/include/mqt-core/na/entities/Atom.hpp +++ b/include/mqt-core/na/entities/Atom.hpp @@ -23,7 +23,7 @@ class Atom final { Atom(Atom&& atom) noexcept = default; Atom& operator=(const Atom& atom) = default; Atom& operator=(Atom&& atom) noexcept = default; - virtual ~Atom() = default; + ~Atom() = default; [[nodiscard]] auto getName() const -> std::string { return name; } [[nodiscard]] auto toString() const -> std::string { return name; } friend auto operator<<(std::ostream& os, const Atom& obj) -> std::ostream& { diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp index c7989d93e..276f2f4c4 100644 --- a/include/mqt-core/na/entities/Zone.hpp +++ b/include/mqt-core/na/entities/Zone.hpp @@ -23,7 +23,7 @@ class Zone final { Zone(Zone&& zone) noexcept = default; Zone& operator=(const Zone& zone) = default; Zone& operator=(Zone&& zone) noexcept = default; - virtual ~Zone() = default; + ~Zone() = default; [[nodiscard]] auto getName() const -> std::string { return name; } [[nodiscard]] auto toString() const -> std::string { return name; } friend auto operator<<(std::ostream& os, const Zone& obj) -> std::ostream& { diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp index 2c895fff8..2ec25c37a 100644 --- a/include/mqt-core/na/operations/Op.hpp +++ b/include/mqt-core/na/operations/Op.hpp @@ -15,6 +15,7 @@ namespace na { class Op { public: + Op() = default; virtual ~Op() = default; [[nodiscard]] virtual auto toString() const -> std::string = 0; friend auto operator<<(std::ostream& os, const Op& obj) -> std::ostream& { diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index eb05a208f..78f3f05c5 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -11,6 +11,7 @@ #include "na/operations/LoadOp.hpp" #include "na/operations/LocalOp.hpp" +#include "na/operations/MoveOp.hpp" #include "na/operations/ShuttlingOp.hpp" #include "na/operations/StoreOp.hpp" diff --git a/test/na/na_ops.cpp b/test/na/na_ops.cpp deleted file mode 100644 index 205e178ba..000000000 --- a/test/na/na_ops.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#include "na/entities/Atom.hpp" -#include "na/operations/LocalRZOp.hpp" - -#include - -namespace na { -TEST(NAOps, Clone) { - const auto* atom0 = new Atom("atom0"); - const auto op = std::make_unique(1.57080, atom0); - auto clone = op->clone(); - EXPECT_NE(clone.get(), op.get()); - EXPECT_EQ(op->toString(), clone->toString()); -} -} // namespace na diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index feb9a6771..253ee8fd2 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -11,7 +11,6 @@ #include "ir/operations/OpType.hpp" #include "na/NAComputation.hpp" #include "na/NAUtils.hpp" -#include "na/operations/GlobalOp.hpp" #include "na/operations/GlobalRYOp.hpp" #include "na/operations/LoadOp.hpp" #include "na/operations/LocalRZOp.hpp" @@ -79,50 +78,59 @@ TEST(NAComputation, ValidateAODConstraints) { qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 0, 2); qc.emplaceInitialLocation(atom3, 1, 2); - qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, 1}})); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{0, 1}, Location{1, 1}}); EXPECT_TRUE(qc.validate()); // atom already loaded - qc.emplaceBack(LoadOp({atom0}, {Location{0, 1}})); + qc.emplaceBack(std::vector{atom0}, std::vector{Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // atom not loaded - qc.emplaceBack(MoveOp({atom0}, {Location{0, 1}})); + qc.emplaceBack(std::vector{atom0}, std::vector{Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // two atoms identical - qc.emplaceBack(LoadOp({atom0, atom0}, {Location{0, 1}, Location{1, 1}})); + qc.emplaceBack(std::vector{atom0, atom0}, + std::vector{Location{0, 1}, Location{1, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // two end points identical - qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{0, 1}})); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{0, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // columns not preserved - qc.emplaceBack(LoadOp({atom1, atom3}, {Location{0, 1}, Location{2, 2}})); + qc.emplaceBack(std::vector{atom1, atom3}, + std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate()); qc.clear(); // rows not preserved - qc.emplaceBack(LoadOp({atom0, atom1}, {Location{0, 1}, Location{1, -1}})); + qc.emplaceBack(std::vector{atom0, atom1}, + std::vector{Location{0, 1}, Location{1, -1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // column order not preserved - qc.emplaceBack(LoadOp({atom0, atom3}, {Location{1, 1}, Location{0, 1}})); + qc.emplaceBack(std::vector{atom0, atom3}, + std::vector{Location{1, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // row order not preserved - qc.emplaceBack(LoadOp({atom0, atom3}, {Location{0, 1}, Location{2, 0}})); + qc.emplaceBack(std::vector{atom0, atom3}, + std::vector{Location{0, 1}, Location{2, 0}}); EXPECT_FALSE(qc.validate()); qc.clear(); // column order not preserved - qc.emplaceBack(LoadOp({atom2, atom1}, {Location{1, 3}, Location{0, 1}})); + qc.emplaceBack(std::vector{atom2, atom1}, + std::vector{Location{1, 3}, Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // row order not preserved - qc.emplaceBack(LoadOp({atom2, atom1}, {Location{0, 1}, Location{2, 2}})); + qc.emplaceBack(std::vector{atom2, atom1}, + std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate()); qc.clear(); // two atoms identical - qc.emplaceBack(LocalRZOp(qc::PI_2, {atom0, atom0})); + qc.emplaceBack(qc::PI_2, std::vector{atom0, atom0}); EXPECT_FALSE(qc.validate()); } } // namespace na From fce953950ac883b48ac64c133449de5f9ba7bd59 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Tue, 11 Feb 2025 08:35:25 +0100 Subject: [PATCH 13/39] =?UTF-8?q?=F0=9F=8E=A8=20Add=20getZones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 36c5ab67c..60ad87430 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -34,9 +34,7 @@ class NAComputation final : protected std::vector> { using std::vector>::size; using std::vector>::operator[]; NAComputation() = default; - NAComputation(const NAComputation& qc) = default; NAComputation(NAComputation&& qc) noexcept = default; - NAComputation& operator=(const NAComputation& qc) = default; NAComputation& operator=(NAComputation&& qc) noexcept = default; [[nodiscard]] auto getAtomsSize() const -> std::size_t { return atoms.size(); @@ -44,6 +42,9 @@ class NAComputation final : protected std::vector> { [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { return atoms; } + [[nodiscard]] auto getZones() const -> const decltype(zones)& { + return zones; + } [[nodiscard]] auto getInitialLocations() const -> const decltype(initialLocations)& { return initialLocations; From 3b65ad34d4c51ab1385949648b85c34fffabfc13 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Tue, 11 Feb 2025 08:38:32 +0100 Subject: [PATCH 14/39] =?UTF-8?q?=F0=9F=94=A5=20Remove=20clone()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/operations/GlobalCZOp.hpp | 3 --- include/mqt-core/na/operations/GlobalRYOp.hpp | 3 --- include/mqt-core/na/operations/LoadOp.hpp | 3 --- include/mqt-core/na/operations/LocalRZOp.hpp | 3 --- include/mqt-core/na/operations/MoveOp.hpp | 3 --- include/mqt-core/na/operations/Op.hpp | 1 - include/mqt-core/na/operations/StoreOp.hpp | 3 --- 7 files changed, 19 deletions(-) diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index be532a5ee..cca06ecac 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -15,8 +15,5 @@ namespace na { class GlobalCZOp final : public GlobalOp { public: explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { name = "cz"; } - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index f46c4813e..1e58e7299 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -17,8 +17,5 @@ class GlobalRYOp final : public GlobalOp { GlobalRYOp(qc::fp angle, const Zone* zone) : GlobalOp({angle}, zone) { name = "ry"; } - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index 30d8824f7..ed6fdd87f 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -53,8 +53,5 @@ class LoadOp : public ShuttlingOp { return *targetLocations; } [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index a0596f884..46755f363 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -23,8 +23,5 @@ class LocalRZOp final : public LocalOp { : LocalOp({angle}, std::move(atom)) { name = "rz"; } - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index a2f7485f5..565f25012 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -43,8 +43,5 @@ class MoveOp : public ShuttlingOp { return targetLocations; } [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp index 2ec25c37a..ec1bab25a 100644 --- a/include/mqt-core/na/operations/Op.hpp +++ b/include/mqt-core/na/operations/Op.hpp @@ -30,6 +30,5 @@ class Op { template [[nodiscard]] auto as() const -> const T& { return dynamic_cast(*this); } - [[nodiscard]] virtual auto clone() const -> std::unique_ptr = 0; }; } // namespace na diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index 45992dbf5..fff6a2746 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -53,8 +53,5 @@ class StoreOp : public ShuttlingOp { return *targetLocations; } [[nodiscard]] auto toString() const -> std::string override; - [[nodiscard]] auto clone() const -> std::unique_ptr override { - return std::make_unique(*this); - } }; } // namespace na From ad6bb26f00d18b3bf90655378df3a684702b8689 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Tue, 11 Feb 2025 13:52:14 +0100 Subject: [PATCH 15/39] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20superfluous=20lin?= =?UTF-8?q?k=20targets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/na/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/na/CMakeLists.txt b/src/na/CMakeLists.txt index 4a459fd04..0eb2d44fa 100644 --- a/src/na/CMakeLists.txt +++ b/src/na/CMakeLists.txt @@ -19,10 +19,7 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-na) add_library(${MQT_CORE_TARGET_NAME}-na ${NA_HEADERS} ${NA_SOURCES}) # add link libraries - target_link_libraries( - ${MQT_CORE_TARGET_NAME}-na - PUBLIC MQT::CoreIR MQT::CoreDS - PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) + target_link_libraries(${MQT_CORE_TARGET_NAME}-na PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) # set include directories target_include_directories( From 71a5fd1a1862699a605c9b275f56654df1f05862 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:19:12 +0100 Subject: [PATCH 16/39] =?UTF-8?q?=F0=9F=8E=A8=20Offer=20more=20constructor?= =?UTF-8?q?s=20for=20locations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/entities/Location.hpp | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index c5e57c353..60951f93f 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -20,7 +20,31 @@ namespace na { struct Location final { double x = 0; double y = 0; + Location(const float x, const float y) + : x(static_cast(x)), y(static_cast(y)) {}; Location(const double x, const double y) : x(x), y(y) {}; + Location(const std::int32_t x, const std::int32_t y) + : x(static_cast(x)), y(static_cast(y)) {}; + Location(const std::int64_t x, const std::int64_t y) + : x(static_cast(x)), y(static_cast(y)) {}; + Location(const std::uint32_t x, const std::uint32_t y) + : x(static_cast(x)), y(static_cast(y)) {}; + Location(const std::uint64_t x, const std::uint64_t y) + : x(static_cast(x)), y(static_cast(y)) {}; + Location(const std::size_t x, const std::size_t y) + : x(static_cast(x)), y(static_cast(y)) {}; + Location(const std::pair p) : Location(p.first, p.second) {}; + Location(const std::pair p) : Location(p.first, p.second) {}; + Location(const std::pair p) + : Location(p.first, p.second) {}; + Location(const std::pair p) + : Location(p.first, p.second) {}; + Location(const std::pair p) + : Location(p.first, p.second) {}; + Location(const std::pair p) + : Location(p.first, p.second) {}; + Location(const std::pair p) + : Location(p.first, p.second) {}; Location() = default; Location(const Location& loc) = default; Location(Location&& loc) noexcept = default; From dbcf43f74c7299a0277fc7fb79fb5811c7951505 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:27:29 +0100 Subject: [PATCH 17/39] =?UTF-8?q?=F0=9F=90=9B=20Fix=20creation=20of=20Loca?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 60ad87430..c422986d5 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -78,7 +78,7 @@ class NAComputation final : protected std::vector> { } template auto emplaceInitialLocation(const Atom* atom, Args&&... loc) -> void { - initialLocations.emplace(atom, Location(std::forward(loc)...)); + initialLocations.emplace(atom, Location{std::forward(loc)...}); } template auto emplaceBack(T&& op) -> const Op* { return std::vector>::emplace_back( From cd8ad9c3458e2cb3d49ff0b03f572310f8e45210 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:27:18 +0100 Subject: [PATCH 18/39] =?UTF-8?q?=E2=9C=85=20Cover=20GlobalCZOp=20with=20t?= =?UTF-8?q?ests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/operations/LoadOp.hpp | 3 ++- include/mqt-core/na/operations/MoveOp.hpp | 2 +- include/mqt-core/na/operations/StoreOp.hpp | 2 +- test/na/test_nacomputation.cpp | 5 ++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index ed6fdd87f..441291d3a 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -13,6 +13,7 @@ #include "na/entities/Location.hpp" #include "na/operations/ShuttlingOp.hpp" +#include #include #include #include @@ -20,7 +21,7 @@ namespace na { -class LoadOp : public ShuttlingOp { +class LoadOp final : public ShuttlingOp { protected: std::optional> targetLocations = std::nullopt; diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index 565f25012..8dbbcfbec 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -20,7 +20,7 @@ namespace na { -class MoveOp : public ShuttlingOp { +class MoveOp final : public ShuttlingOp { protected: std::vector targetLocations; diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index fff6a2746..532b9ea77 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -20,7 +20,7 @@ namespace na { -class StoreOp : public ShuttlingOp { +class StoreOp final : public ShuttlingOp { protected: std::optional> targetLocations = std::nullopt; diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 253ee8fd2..ac64e360e 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -11,6 +11,7 @@ #include "ir/operations/OpType.hpp" #include "na/NAComputation.hpp" #include "na/NAUtils.hpp" +#include "na/operations/GlobalCZOp.hpp" #include "na/operations/GlobalRYOp.hpp" #include "na/operations/LoadOp.hpp" #include "na/operations/LocalRZOp.hpp" @@ -40,6 +41,7 @@ TEST(NAComputation, General) { std::vector{Location{4, 1}, Location{5, 1}}); qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{4, 0}, Location{5, 0}}); + qc.emplaceBack(GlobalCZOp(globalZone)); std::stringstream ss; ss << qc; EXPECT_EQ(ss.str(), "atom (0.000, 0.000) atom0\n" @@ -58,7 +60,8 @@ TEST(NAComputation, General) { "@+ store [\n" " (4.000, 0.000) atom0\n" " (5.000, 0.000) atom1\n" - "]\n"); + "]\n" + "@+ cz global\n"); } TEST(NAComputation, EmptyPrint) { From 779abd692e3b419076c1d4e7ab4c0468d25d7cfa Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:45:00 +0100 Subject: [PATCH 19/39] =?UTF-8?q?=F0=9F=90=9B=20Add=20missing=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 1 + include/mqt-core/na/entities/Location.hpp | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index c422986d5..0f1de6b25 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -15,6 +15,7 @@ #include "na/operations/Op.hpp" #include +#include #include #include #include diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index 60951f93f..a844e76f6 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -10,10 +10,12 @@ #pragma once #include +#include #include #include #include #include +#include namespace na { /// Class to store two-dimensional coordinates @@ -33,17 +35,19 @@ struct Location final { : x(static_cast(x)), y(static_cast(y)) {}; Location(const std::size_t x, const std::size_t y) : x(static_cast(x)), y(static_cast(y)) {}; - Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) + explicit Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) + explicit Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) + explicit Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) + explicit Location(const std::pair p) : Location(p.first, p.second) {}; - Location(const std::pair p) + explicit Location(const std::pair p) + : Location(p.first, p.second) {}; + explicit Location(const std::pair p) + : Location(p.first, p.second) {}; + explicit Location(const std::pair p) : Location(p.first, p.second) {}; Location() = default; Location(const Location& loc) = default; From db68ced652c33eb1e5e8b2a7484c3fca3ca67353 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 11:11:58 +0100 Subject: [PATCH 20/39] =?UTF-8?q?=F0=9F=90=9B=20Link=20against=20missing?= =?UTF-8?q?=20target?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/na/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/na/CMakeLists.txt b/src/na/CMakeLists.txt index 0eb2d44fa..edfc97c79 100644 --- a/src/na/CMakeLists.txt +++ b/src/na/CMakeLists.txt @@ -19,7 +19,10 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME}-na) add_library(${MQT_CORE_TARGET_NAME}-na ${NA_HEADERS} ${NA_SOURCES}) # add link libraries - target_link_libraries(${MQT_CORE_TARGET_NAME}-na PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) + target_link_libraries( + ${MQT_CORE_TARGET_NAME}-na + PUBLIC MQT::CoreIR + PRIVATE MQT::ProjectOptions MQT::ProjectWarnings) # set include directories target_include_directories( From efe341d7b861aca8bdb13a31239f4f04e7c129e0 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:39:05 +0100 Subject: [PATCH 21/39] =?UTF-8?q?=F0=9F=8E=A8=20Add=20missing=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 3 ++- include/mqt-core/na/NAUtils.hpp | 3 +-- include/mqt-core/na/entities/Atom.hpp | 3 +++ include/mqt-core/na/entities/Zone.hpp | 1 + include/mqt-core/na/operations/GlobalCZOp.hpp | 1 + include/mqt-core/na/operations/GlobalOp.hpp | 1 + include/mqt-core/na/operations/GlobalRYOp.hpp | 2 ++ include/mqt-core/na/operations/LocalOp.hpp | 1 + include/mqt-core/na/operations/LocalRZOp.hpp | 4 ++++ include/mqt-core/na/operations/ShuttlingOp.hpp | 1 + include/mqt-core/na/operations/StoreOp.hpp | 1 + src/na/NAComputation.cpp | 5 +++++ src/na/operations/GlobalOp.cpp | 2 +- src/na/operations/LoadOp.cpp | 1 + src/na/operations/LocalOp.cpp | 1 + src/na/operations/MoveOp.cpp | 1 + 16 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 0f1de6b25..7e6b2214c 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -14,11 +14,12 @@ #include "na/entities/Zone.hpp" #include "na/operations/Op.hpp" -#include +#include #include #include #include #include +#include #include namespace na { diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp index 6e5bca8ef..fd426748f 100644 --- a/include/mqt-core/na/NAUtils.hpp +++ b/include/mqt-core/na/NAUtils.hpp @@ -17,8 +17,7 @@ #include #include #include -#include -#include +#include namespace na { /** diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp index 09c6dbaf8..b10a23f74 100644 --- a/include/mqt-core/na/entities/Atom.hpp +++ b/include/mqt-core/na/entities/Atom.hpp @@ -9,6 +9,9 @@ #pragma once +#include +#include +#include #include #include diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp index 276f2f4c4..3d5710bc5 100644 --- a/include/mqt-core/na/entities/Zone.hpp +++ b/include/mqt-core/na/entities/Zone.hpp @@ -9,6 +9,7 @@ #pragma once +#include #include #include diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index cca06ecac..9889b7528 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -9,6 +9,7 @@ #pragma once +#include "na/entities/Zone.hpp" #include "na/operations/GlobalOp.hpp" namespace na { diff --git a/include/mqt-core/na/operations/GlobalOp.hpp b/include/mqt-core/na/operations/GlobalOp.hpp index ff2b085d8..985ac3927 100644 --- a/include/mqt-core/na/operations/GlobalOp.hpp +++ b/include/mqt-core/na/operations/GlobalOp.hpp @@ -13,6 +13,7 @@ #include "na/entities/Zone.hpp" #include "na/operations/Op.hpp" +#include #include #include diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index 1e58e7299..a22d62144 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -9,6 +9,8 @@ #pragma once +#include "Definitions.hpp" +#include "na/entities/Zone.hpp" #include "na/operations/GlobalOp.hpp" namespace na { diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp index 9bf1e3f1f..1f910b70e 100644 --- a/include/mqt-core/na/operations/LocalOp.hpp +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -13,6 +13,7 @@ #include "na/entities/Atom.hpp" #include "na/operations/Op.hpp" +#include #include #include diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index 46755f363..e770ca310 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -9,9 +9,13 @@ #pragma once +#include "Definitions.hpp" +#include "na/entities/Atom.hpp" #include "na/operations/LocalOp.hpp" #include +#include +#include namespace na { class LocalRZOp final : public LocalOp { diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp index 410a17893..8da240591 100644 --- a/include/mqt-core/na/operations/ShuttlingOp.hpp +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -10,6 +10,7 @@ #pragma once #include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" #include "na/operations/Op.hpp" #include diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index 532b9ea77..f6ed2c7b6 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -13,6 +13,7 @@ #include "na/entities/Location.hpp" #include "na/operations/ShuttlingOp.hpp" +#include #include #include #include diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 78f3f05c5..46429ba7d 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -9,9 +9,12 @@ #include "na/NAComputation.hpp" +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" #include "na/operations/LoadOp.hpp" #include "na/operations/LocalOp.hpp" #include "na/operations/MoveOp.hpp" +#include "na/operations/Op.hpp" #include "na/operations/ShuttlingOp.hpp" #include "na/operations/StoreOp.hpp" @@ -22,6 +25,8 @@ #include #include #include +#include +#include namespace na { auto NAComputation::getLocationOfAtomAfterOperation(const Atom* atom, diff --git a/src/na/operations/GlobalOp.cpp b/src/na/operations/GlobalOp.cpp index b607aea93..5ad55d7a4 100644 --- a/src/na/operations/GlobalOp.cpp +++ b/src/na/operations/GlobalOp.cpp @@ -7,7 +7,7 @@ * Licensed under the MIT License */ -#include "na/operations/GlobalRYOp.hpp" +#include "na/operations/GlobalOp.hpp" #include #include diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp index dd04bd85c..a4197ea70 100644 --- a/src/na/operations/LoadOp.cpp +++ b/src/na/operations/LoadOp.cpp @@ -9,6 +9,7 @@ #include "na/operations/LoadOp.hpp" +#include #include #include diff --git a/src/na/operations/LocalOp.cpp b/src/na/operations/LocalOp.cpp index dc9c60864..1d1f5ee81 100644 --- a/src/na/operations/LocalOp.cpp +++ b/src/na/operations/LocalOp.cpp @@ -10,6 +10,7 @@ #include "na/operations/LocalOp.hpp" #include +#include #include #include diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp index ea8bec2bf..c21a63ada 100644 --- a/src/na/operations/MoveOp.cpp +++ b/src/na/operations/MoveOp.cpp @@ -9,6 +9,7 @@ #include "na/operations/MoveOp.hpp" +#include #include #include From 7caeb30847c022df9aae239df5b1d8e03358c66c Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:05:45 +0100 Subject: [PATCH 22/39] =?UTF-8?q?=F0=9F=8E=A8=20Add=20missing=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/entities/Location.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index a844e76f6..60603c9e1 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include #include @@ -35,19 +36,19 @@ struct Location final { : x(static_cast(x)), y(static_cast(y)) {}; Location(const std::size_t x, const std::size_t y) : x(static_cast(x)), y(static_cast(y)) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair p) + explicit Location(const std::pair& p) : Location(p.first, p.second) {}; Location() = default; Location(const Location& loc) = default; From fe38f0f7ad02bf5c5020afe684724d9f669ee6f8 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:08:43 +0100 Subject: [PATCH 23/39] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20header=20includes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/entities/Location.hpp | 5 +---- src/na/operations/StoreOp.cpp | 1 + test/na/test_nacomputation.cpp | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index 60603c9e1..06e20da51 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ struct Location final { : x(static_cast(x)), y(static_cast(y)) {}; Location(const std::uint64_t x, const std::uint64_t y) : x(static_cast(x)), y(static_cast(y)) {}; - Location(const std::size_t x, const std::size_t y) - : x(static_cast(x)), y(static_cast(y)) {}; explicit Location(const std::pair& p) : Location(p.first, p.second) {}; explicit Location(const std::pair& p) @@ -48,8 +47,6 @@ struct Location final { : Location(p.first, p.second) {}; explicit Location(const std::pair& p) : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; Location() = default; Location(const Location& loc) = default; Location(Location&& loc) noexcept = default; diff --git a/src/na/operations/StoreOp.cpp b/src/na/operations/StoreOp.cpp index c71d3108b..c3155b76c 100644 --- a/src/na/operations/StoreOp.cpp +++ b/src/na/operations/StoreOp.cpp @@ -9,6 +9,7 @@ #include "na/operations/StoreOp.hpp" +#include #include #include diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index ac64e360e..931671915 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -8,9 +8,7 @@ */ #include "Definitions.hpp" -#include "ir/operations/OpType.hpp" #include "na/NAComputation.hpp" -#include "na/NAUtils.hpp" #include "na/operations/GlobalCZOp.hpp" #include "na/operations/GlobalRYOp.hpp" #include "na/operations/LoadOp.hpp" @@ -19,7 +17,6 @@ #include "na/operations/StoreOp.hpp" #include -#include #include #include From 0bf53182b3b994d8ac237c24ad018d9752473759 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:14:54 +0100 Subject: [PATCH 24/39] =?UTF-8?q?=F0=9F=92=9A=20Work=20on=20ci=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 7 ++++ include/mqt-core/na/entities/Location.hpp | 1 - src/na/NAComputation.cpp | 33 ++++++++++++++++-- test/na/test_nacomputation.cpp | 41 ++++++++++++++++++----- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 7e6b2214c..4caf55daa 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -98,6 +98,13 @@ class NAComputation final : protected std::vector> { -> std::ostream& { return os << qc.toString(); } + /// Validates the NAComputation and checks whether all AOD constraints are + /// fulfilled. + /// I.e., + /// - each atom is loaded before it is moved + /// - the relative order of loaded atoms is preserved + /// - each atom is loaded before it is stored + /// - each atom is stored before it is loaded (again) [[nodiscard]] auto validate() const -> bool; }; } // namespace na diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index 06e20da51..1d2271454 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -10,7 +10,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 46429ba7d..bbfd0d727 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -66,18 +66,34 @@ auto NAComputation::toString() const -> std::string { return ss.str(); } auto NAComputation::validate() const -> bool { - std::size_t counter = 1; // the first operation is `init at ...;` + // This counter is used to display the operation number where an error + // occurred. + // As every operation might not correspond to one line in the output, + // this may not be identical with the line number in the output. + // However, the first operation initializes the atom and because of that, the + // counter starts with 1. + std::size_t counter = 1; if (atoms.size() != initialLocations.size()) { std::cout << "Number of atoms and initial locations must be equal\n"; } + // This map is used to keep track of each atom's current location to check + // the constraints when shuttling atoms. std::unordered_map currentLocations = initialLocations; + // This set is used to keep track of the atoms that are currently shuttling, + // i.e., they are loaded but not yet stored again. std::unordered_set currentlyShuttling{}; for (const auto& op : *this) { ++counter; if (op->is()) { + //===----------------------------------------------------------------===// + // Shuttling Operations + //===----------------------------------------------------------------===// const auto& shuttlingOp = op->as(); const auto& opAtoms = shuttlingOp.getAtoms(); if (shuttlingOp.is()) { + //===-----------------------------------------------------------------// + // Load Operations + //-----------------------------------------------------------------===// if (std::any_of(opAtoms.begin(), opAtoms.end(), [¤tlyShuttling](const auto* atom) { return currentlyShuttling.find(atom) != @@ -92,6 +108,9 @@ auto NAComputation::validate() const -> bool { currentlyShuttling.insert(atom); }); } else { + //===-----------------------------------------------------------------// + // Move and Store Operations + //-----------------------------------------------------------------===// if (std::any_of(opAtoms.begin(), opAtoms.end(), [¤tlyShuttling](const auto* atom) { return currentlyShuttling.find(atom) == @@ -102,8 +121,12 @@ auto NAComputation::validate() const -> bool { return false; } } + //===----------------------------------------------------------------===// + // All Shuttling Operations that move atoms + //===----------------------------------------------------------------===// if ((op->is() && op->as().hasTargetLocations()) || - (op->is() && op->as().hasTargetLocations())) { + (op->is() && op->as().hasTargetLocations()) || + op->is()) { const auto& targetLocations = shuttlingOp.getTargetLocations(); for (std::size_t i = 0; i < opAtoms.size(); ++i) { const auto* a = opAtoms[i]; @@ -160,11 +183,17 @@ auto NAComputation::validate() const -> bool { } } if (shuttlingOp.is()) { + //===-----------------------------------------------------------------// + // Store Operations + //-----------------------------------------------------------------===// std::for_each(opAtoms.begin(), opAtoms.end(), [&](const auto* atom) { currentlyShuttling.erase(atom); }); } } else if (op->is()) { + //===----------------------------------------------------------------===// + // Local Operations + //===----------------------------------------------------------------===// const auto& opAtoms = op->as().getAtoms(); for (std::size_t i = 0; i < opAtoms.size(); ++i) { const auto* a = opAtoms[i]; diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 931671915..3ededf68a 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -90,47 +90,70 @@ TEST(NAComputation, ValidateAODConstraints) { EXPECT_FALSE(qc.validate()); qc.clear(); // two atoms identical - qc.emplaceBack(std::vector{atom0, atom0}, + qc.emplaceBack(std::vector{atom0, atom0}); + qc.emplaceBack(std::vector{atom0, atom0}, std::vector{Location{0, 1}, Location{1, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // two end points identical - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{atom0, atom1}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // columns not preserved - qc.emplaceBack(std::vector{atom1, atom3}, + qc.emplaceBack(std::vector{atom1, atom3}); + qc.emplaceBack(std::vector{atom1, atom3}, std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate()); qc.clear(); // rows not preserved - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{atom0, atom1}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, -1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // column order not preserved - qc.emplaceBack(std::vector{atom0, atom3}, + qc.emplaceBack(std::vector{atom0, atom3}); + qc.emplaceBack(std::vector{atom0, atom3}, std::vector{Location{1, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate()); qc.clear(); // row order not preserved - qc.emplaceBack(std::vector{atom0, atom3}, + qc.emplaceBack(std::vector{atom0, atom3}); + qc.emplaceBack(std::vector{atom0, atom3}, std::vector{Location{0, 1}, Location{2, 0}}); EXPECT_FALSE(qc.validate()); qc.clear(); // column order not preserved - qc.emplaceBack(std::vector{atom2, atom1}, - std::vector{Location{1, 3}, Location{0, 1}}); + qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{atom1, atom2}, + std::vector{Location{0, 1}, Location{1, 3}}); EXPECT_FALSE(qc.validate()); qc.clear(); // row order not preserved - qc.emplaceBack(std::vector{atom2, atom1}, + qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{atom2, atom1}, std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate()); qc.clear(); // two atoms identical qc.emplaceBack(qc::PI_2, std::vector{atom0, atom0}); EXPECT_FALSE(qc.validate()); + qc.clear(); + // store unloaded atom + qc.emplaceBack(std::vector{atom0}); + EXPECT_FALSE(qc.validate()); +} + +TEST(NAComputation, GetPositionOfAtomAfterOperation) { + auto qc = NAComputation(); + const auto* const atom0 = qc.emplaceBackAtom("atom0"); + qc.emplaceInitialLocation(atom0, 0, 0); + qc.emplaceBack(std::vector{atom0}); + qc.emplaceBack(std::vector{atom0}, std::vector{Location{1, 1}}); + qc.emplaceBack(std::vector{atom0}); + EXPECT_EQ(qc.getLocationOfAtomAfterOperation(atom0, qc[0]), (Location{0, 0})); + EXPECT_EQ(qc.getLocationOfAtomAfterOperation(atom0, qc[2]), (Location{1, 1})); } } // namespace na From 878c01ac1abcc9a37e56dc38c68b7f91dc5ce785 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:37:14 +0100 Subject: [PATCH 25/39] =?UTF-8?q?=F0=9F=93=9D=20Add=20more=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/na/NAComputation.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index bbfd0d727..28b8484c9 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -146,31 +146,60 @@ auto NAComputation::validate() const -> bool { << " (two end points identical)\n"; return false; } + // Exp.: + // o -----> o + // o --> o if (s1.x == s2.x && e1.x != e2.x) { std::cout << "Error in op number " << counter << " (columns not preserved)\n"; return false; } + // Exp.: + // o o + // | | + // v | + // o v + // o if (s1.y == s2.y && e1.y != e2.y) { std::cout << "Error in op number " << counter << " (rows not preserved)\n"; return false; } + // Exp.: + // o -------> o + // o--> o if (s1.x < s2.x && e1.x >= e2.x) { std::cout << "Error in op number " << counter << " (column order not preserved)\n"; return false; } + // Exp.: + // o + // | o + // | | + // | v + // v o + // o if (s1.y < s2.y && e1.y >= e2.y) { std::cout << "Error in op number " << counter << " (row order not preserved)\n"; return false; } + // Exp.: + // o--> o + // o -------> o if (s1.x > s2.x && e1.x <= e2.x) { std::cout << "Error in op number " << counter << " (column order not preserved)\n"; return false; } + // Exp.: + // o + // o | + // | | + // v | + // o v + // o if (s1.y > s2.y && e1.y <= e2.y) { std::cout << "Error in op number " << counter << " (row order not preserved)\n"; From d1efe8f550e75186fc5ba34eb701edd8b5e8e758 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Mon, 3 Mar 2025 16:42:41 +0100 Subject: [PATCH 26/39] =?UTF-8?q?=F0=9F=92=9A=20Work=20on=20CI=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/na/test_nacomputation.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 3ededf68a..dab488988 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -31,6 +31,7 @@ TEST(NAComputation, General) { qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 2, 0); qc.emplaceBack(qc::PI_2, atom0); + qc.emplaceBack(qc::PI_2, std::vector{atom1, atom2}); qc.emplaceBack(qc::PI_2, globalZone); qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, 1}}); @@ -45,6 +46,10 @@ TEST(NAComputation, General) { "atom (1.000, 0.000) atom1\n" "atom (2.000, 0.000) atom2\n" "@+ rz 1.57080 atom0\n" + "@+ rz [\n" + " 1.57080 atom1\n" + " 1.57080 atom2\n" + "]\n" "@+ ry 1.57080 global\n" "@+ load [\n" " (0.000, 1.000) atom0\n" @@ -144,6 +149,17 @@ TEST(NAComputation, ValidateAODConstraints) { // store unloaded atom qc.emplaceBack(std::vector{atom0}); EXPECT_FALSE(qc.validate()); + qc.clear(); + qc.emplaceBack(std::vector{atom2, atom1}); + // row order not preserved + qc.emplaceBack(std::vector{atom2, atom1}, + std::vector{Location{0, 1}, Location{2, 2}}); + EXPECT_FALSE(qc.validate()); + qc.clear(); + qc.emplaceBack(std::vector{atom1}); + qc.emplaceBack(std::vector{atom1}); + qc.emplaceBack(std::vector{atom1}); + EXPECT_FALSE(qc.validate()); } TEST(NAComputation, GetPositionOfAtomAfterOperation) { From 6552eb1d4ca6b7e859c1d78d7c50a81c43751b4d Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 07:43:47 +0100 Subject: [PATCH 27/39] =?UTF-8?q?=F0=9F=8E=A8=20WIP=20incorporate=20feedba?= =?UTF-8?q?ck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 128 ++++++++++-------- include/mqt-core/na/entities/Atom.hpp | 24 +--- include/mqt-core/na/entities/Location.hpp | 60 ++------ include/mqt-core/na/entities/Zone.hpp | 16 +-- include/mqt-core/na/operations/GlobalCZOp.hpp | 2 +- include/mqt-core/na/operations/GlobalOp.hpp | 19 ++- include/mqt-core/na/operations/GlobalRYOp.hpp | 4 +- include/mqt-core/na/operations/LoadOp.hpp | 24 ++-- include/mqt-core/na/operations/LocalOp.hpp | 25 ++-- include/mqt-core/na/operations/LocalRZOp.hpp | 10 +- include/mqt-core/na/operations/MoveOp.hpp | 19 ++- .../mqt-core/na/operations/ShuttlingOp.hpp | 3 +- include/mqt-core/na/operations/StoreOp.hpp | 12 +- src/na/NAComputation.cpp | 41 +++--- src/na/operations/GlobalOp.cpp | 8 +- src/na/operations/LoadOp.cpp | 8 +- src/na/operations/LocalOp.cpp | 16 +-- src/na/operations/MoveOp.cpp | 4 +- test/na/test_nacomputation.cpp | 46 +++++-- 19 files changed, 220 insertions(+), 249 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 4caf55daa..ac9d67486 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -23,77 +23,95 @@ #include namespace na { -class NAComputation final : protected std::vector> { +class NAComputation final { protected: - std::vector> atoms; - std::vector> zones; - std::unordered_map initialLocations; + std::vector> operations_; + std::vector> atoms_; + std::vector> zones_; + std::unordered_map initialLocations_; public: - using std::vector>::begin; - using std::vector>::clear; - using std::vector>::end; - using std::vector>::size; - using std::vector>::operator[]; - NAComputation() = default; - NAComputation(NAComputation&& qc) noexcept = default; - NAComputation& operator=(NAComputation&& qc) noexcept = default; + [[nodiscard]] auto begin() -> decltype(operations_.begin()) { + return operations_.begin(); + } + [[nodiscard]] auto begin() const -> decltype(operations_.begin()) { + return operations_.begin(); + } + [[nodiscard]] auto end() -> decltype(operations_.end()) { + return operations_.end(); + } + [[nodiscard]] auto end() const -> decltype(operations_.end()) { + return operations_.end(); + } + [[nodiscard]] auto size() const -> std::size_t { return operations_.size(); } + [[nodiscard]] auto operator[](std::size_t i) -> Op& { + return *operations_[i]; + } + [[nodiscard]] auto operator[](std::size_t i) const -> const Op& { + return *operations_[i]; + } + auto clear() -> void { operations_.clear(); } [[nodiscard]] auto getAtomsSize() const -> std::size_t { - return atoms.size(); + return atoms_.size(); } - [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { - return atoms; + /// Returns the atoms used in the NAComputation. + [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { + return atoms_; } - [[nodiscard]] auto getZones() const -> const decltype(zones)& { - return zones; + /// Returns the zones used in global operations within the NAComputation. + [[nodiscard]] auto getZones() const -> const decltype(zones_)& { + return zones_; } + /// Returns the initial locations of the atoms. [[nodiscard]] auto getInitialLocations() const -> const - decltype(initialLocations)& { - return initialLocations; - } - [[nodiscard]] auto - getLocationOfAtomAfterOperation(const std::unique_ptr& atom, - const std::unique_ptr& op) const - -> Location { - return getLocationOfAtomAfterOperation(atom.get(), op.get()); - } - [[nodiscard]] auto - getLocationOfAtomAfterOperation(const std::unique_ptr& atom, - const Op* op) const -> Location { - return getLocationOfAtomAfterOperation(atom.get(), op); - } - [[nodiscard]] auto getLocationOfAtomAfterOperation( - const Atom* atom, const std::unique_ptr& op) const -> Location { - return getLocationOfAtomAfterOperation(atom, op.get()); - } - [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom* atom, - const Op* op) const + decltype(initialLocations_)& { + return initialLocations_; + } + /// Returns the location of the given atom after the given operation. + [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom& atom, + const Op& op) const -> Location; - auto emplaceBackAtom(std::string name) -> const Atom* { - return atoms.emplace_back(std::make_unique(std::move(name))).get(); + /// Emplaces a new atom with the given name and returns a reference to the + /// newly created atom. + auto emplaceBackAtom(std::string name) -> const Atom& { + return *atoms_.emplace_back(std::make_unique(std::move(name))); } - auto emplaceBackZone(std::string name) -> const Zone* { - return zones.emplace_back(std::make_unique(std::move(name))).get(); + /// Emplaces a new operation of type T with the given operation and returns a + /// reference to the newly created operation. + auto emplaceBackZone(std::string name) -> const Zone& { + return *zones_.emplace_back(std::make_unique(std::move(name))); } - auto emplaceInitialLocation(const Atom* atom, const Location& loc) -> void { - initialLocations.emplace(atom, loc); + /// Emplaces a new initial location for the given atom with the given location + /// and returns a reference to the newly created location. + auto emplaceInitialLocation(const Atom* atom, const Location& loc) + -> const Location& { + return initialLocations_.emplace(atom, loc).first->second; } + /// Emplaces a new initial location for the given atom with the given + /// arguments and returns a reference to the newly created location. template - auto emplaceInitialLocation(const Atom* atom, Args&&... loc) -> void { - initialLocations.emplace(atom, Location{std::forward(loc)...}); + auto emplaceInitialLocation(const Atom* atom, Args&&... loc) + -> const Location& { + return initialLocations_.emplace(atom, Location{std::forward(loc)...}) + .first->second; } - template auto emplaceBack(T&& op) -> const Op* { - return std::vector>::emplace_back( - std::make_unique(std::forward(op))) - .get(); + /// Emplaces a new operation of type T with the given operation and returns a + /// reference to the newly created operation. + template auto emplaceBack(T&& op) -> const Op& { + return *std::vector>::emplace_back( + std::make_unique(std::forward(op))); } + /// Emplaces a new operation of type T with the given arguments and returns a + /// reference to the newly created operation. template - auto emplaceBack(Args&&... args) -> const Op* { - return std::vector>::emplace_back( - std::make_unique(std::forward(args)...)) - .get(); + auto emplaceBack(Args&&... args) -> const Op& { + return *std::vector>::emplace_back( + std::make_unique(std::forward(args)...)); } + /// Returns a string representation of the NAComputation. [[nodiscard]] auto toString() const -> std::string; + /// Outputs the NAComputation to the given output stream, i.e., the string + /// returned by toString(). friend auto operator<<(std::ostream& os, const NAComputation& qc) -> std::ostream& { return os << qc.toString(); @@ -105,6 +123,8 @@ class NAComputation final : protected std::vector> { /// - the relative order of loaded atoms is preserved /// - each atom is loaded before it is stored /// - each atom is stored before it is loaded (again) - [[nodiscard]] auto validate() const -> bool; + /// @returns a pair of a boolean indicating whether the NAComputation is valid + /// and a string containing the error message if the NAComputation is invalid. + [[nodiscard]] auto validate() const -> std::pair; }; } // namespace na diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp index b10a23f74..3cd9eb1da 100644 --- a/include/mqt-core/na/entities/Atom.hpp +++ b/include/mqt-core/na/entities/Atom.hpp @@ -9,43 +9,29 @@ #pragma once -#include -#include #include #include #include namespace na { class Atom final { - std::string name; + std::string name_; public: Atom() = default; - explicit Atom(std::string name) : name(std::move(name)) {} - Atom(const Atom& atom) = default; - Atom(Atom&& atom) noexcept = default; - Atom& operator=(const Atom& atom) = default; - Atom& operator=(Atom&& atom) noexcept = default; - ~Atom() = default; - [[nodiscard]] auto getName() const -> std::string { return name; } - [[nodiscard]] auto toString() const -> std::string { return name; } + explicit Atom(std::string name) : name_(std::move(name)) {} + [[nodiscard]] auto getName() const -> std::string { return name_; } friend auto operator<<(std::ostream& os, const Atom& obj) -> std::ostream& { - return os << obj.toString(); + return os << obj.getName(); } [[nodiscard]] auto operator==(const Atom& other) const -> bool { if (this == &other) { return true; } - return name == other.name; + return name_ == other.name_; } [[nodiscard]] auto operator!=(const Atom& other) const -> bool { return !(*this == other); } }; } // namespace na -template <> struct std::hash { - [[nodiscard]] auto operator()(const na::Atom* atom) const noexcept - -> std::size_t { - return hash{}(atom->getName()); - } -}; // namespace std diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index 1d2271454..589f3c4fc 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -23,50 +23,13 @@ namespace na { struct Location final { double x = 0; double y = 0; - Location(const float x, const float y) - : x(static_cast(x)), y(static_cast(y)) {}; - Location(const double x, const double y) : x(x), y(y) {}; - Location(const std::int32_t x, const std::int32_t y) - : x(static_cast(x)), y(static_cast(y)) {}; - Location(const std::int64_t x, const std::int64_t y) - : x(static_cast(x)), y(static_cast(y)) {}; - Location(const std::uint32_t x, const std::uint32_t y) - : x(static_cast(x)), y(static_cast(y)) {}; - Location(const std::uint64_t x, const std::uint64_t y) - : x(static_cast(x)), y(static_cast(y)) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - explicit Location(const std::pair& p) - : Location(p.first, p.second) {}; - Location() = default; - Location(const Location& loc) = default; - Location(Location&& loc) noexcept = default; - Location& operator=(const Location& loc) = default; - Location& operator=(Location&& loc) noexcept = default; - ~Location() = default; Location operator-(const Location& loc) const { return {x - loc.x, y - loc.y}; } - Location operator-(const Location&& loc) const { - return {x - loc.x, y - loc.y}; - } Location operator+(const Location& loc) const { return {x + loc.x, y + loc.y}; } - Location operator+(const Location&& loc) const { - return {x + loc.x, y + loc.y}; - } - [[nodiscard]] auto length() const -> double { - return std::sqrt((x * x) + (y * y)); - } + [[nodiscard]] auto length() const -> double { return std::hypot(x, y); } [[nodiscard]] auto toString() const -> std::string { std::stringstream ss; ss << std::setprecision(3) << std::fixed; @@ -87,24 +50,23 @@ struct Location final { return x < other.x || (x == other.x && y < other.y); } [[nodiscard]] auto operator>(const Location& other) const -> bool { - return x > other.x || (x == other.x && y > other.y); - } - [[nodiscard]] auto operator<=(const Location& other) const -> bool { - return x <= other.x || (x == other.x && y <= other.y); + return other < *this; } [[nodiscard]] auto operator>=(const Location& other) const -> bool { - return x >= other.x || (x == other.x && y >= other.y); + return !(other < *this); + } + [[nodiscard]] auto operator<=(const Location& other) const -> bool { + return *this >= other; } - [[maybe_unused]] [[nodiscard]] auto - getEuclideanDistance(const Location& loc) const -> double { + [[nodiscard]] auto getEuclideanDistance(const Location& loc) const -> double { return (*this - loc).length(); } - [[maybe_unused]] [[nodiscard]] auto - getManhattanDistanceX(const Location& loc) const -> double { + [[nodiscard]] auto getManhattanDistanceX(const Location& loc) const + -> double { return std::abs(x - loc.x); } - [[maybe_unused]] [[nodiscard]] auto - getManhattanDistanceY(const Location& loc) const -> double { + [[nodiscard]] auto getManhattanDistanceY(const Location& loc) const + -> double { return std::abs(y - loc.y); } }; diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp index 3d5710bc5..3260a4ca1 100644 --- a/include/mqt-core/na/entities/Zone.hpp +++ b/include/mqt-core/na/entities/Zone.hpp @@ -15,26 +15,20 @@ namespace na { class Zone final { - std::string name; + std::string name_; public: Zone() = default; - explicit Zone(std::string name) : name(std::move(name)) {} - Zone(const Zone& zone) = default; - Zone(Zone&& zone) noexcept = default; - Zone& operator=(const Zone& zone) = default; - Zone& operator=(Zone&& zone) noexcept = default; - ~Zone() = default; - [[nodiscard]] auto getName() const -> std::string { return name; } - [[nodiscard]] auto toString() const -> std::string { return name; } + explicit Zone(std::string name) : name_(std::move(name)) {} + [[nodiscard]] auto getName() const -> std::string { return name_; } friend auto operator<<(std::ostream& os, const Zone& obj) -> std::ostream& { - return os << obj.toString(); + return os << obj.getName(); } [[nodiscard]] auto operator==(const Zone& other) const -> bool { if (this == &other) { return true; } - return name == other.name; + return name_ == other.name_; } [[nodiscard]] auto operator!=(const Zone& other) const -> bool { return !(*this == other); diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index 9889b7528..2735bed8c 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -15,6 +15,6 @@ namespace na { class GlobalCZOp final : public GlobalOp { public: - explicit GlobalCZOp(const Zone* zone) : GlobalOp(zone) { name = "cz"; } + explicit GlobalCZOp(const Zone& zone) : GlobalOp(zone, {}) { name_ = "cz"; } }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalOp.hpp b/include/mqt-core/na/operations/GlobalOp.hpp index 985ac3927..a673bdb3a 100644 --- a/include/mqt-core/na/operations/GlobalOp.hpp +++ b/include/mqt-core/na/operations/GlobalOp.hpp @@ -20,21 +20,18 @@ namespace na { class GlobalOp : public Op { protected: - std::string name; - std::vector params; - const Zone* zone; - GlobalOp(std::vector params, const Zone* zone) - : params(std::move(params)), zone(zone) {} - explicit GlobalOp(const Zone* zone) : GlobalOp({}, zone) {} + std::string name_; + std::vector params_; + const Zone* zone_; + GlobalOp(const Zone& zone, std::vector params) + : params_(std::move(params)), zone_(&zone) {} public: GlobalOp() = delete; - [[nodiscard]] auto getParams() -> decltype(params)& { return params; } - [[nodiscard]] auto getParams() const -> const decltype(params)& { - return params; + [[nodiscard]] auto getParams() const -> const decltype(params_)& { + return params_; } - [[nodiscard]] auto getZone() -> const Zone*& { return zone; } - [[nodiscard]] auto getZone() const -> const Zone* { return zone; } + [[nodiscard]] auto getZone() const -> const Zone& { return *zone_; } [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index a22d62144..d60340a5c 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -16,8 +16,8 @@ namespace na { class GlobalRYOp final : public GlobalOp { public: - GlobalRYOp(qc::fp angle, const Zone* zone) : GlobalOp({angle}, zone) { - name = "ry"; + GlobalRYOp(const Zone& zone, qc::fp angle) : GlobalOp(zone, {angle}) { + name_ = "ry"; } }; } // namespace na diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index 441291d3a..27719bac2 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -23,35 +23,31 @@ namespace na { class LoadOp final : public ShuttlingOp { protected: - std::optional> targetLocations = std::nullopt; + std::optional> targetLocations_ = std::nullopt; public: - explicit LoadOp(std::vector atoms, - std::vector targetLocations) + LoadOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), - targetLocations(std::move(targetLocations)) { - if (this->atoms.size() != this->targetLocations->size()) { + targetLocations_(std::move(targetLocations)) { + if (this->atoms.size() != this->targetLocations_->size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } explicit LoadOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + LoadOp(const Atom& atom, const Location& targetLocation) + : LoadOp({&atom}, {targetLocation}) {} + explicit LoadOp(const Atom& atom) : LoadOp({&atom}) {} [[nodiscard]] auto hasTargetLocations() const -> bool { - return targetLocations.has_value(); - } - [[nodiscard]] auto getTargetLocations() -> std::vector& override { - if (!targetLocations.has_value()) { - throw std::logic_error("Operation has no target locations set."); - } - return *targetLocations; + return targetLocations_.has_value(); } [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { - if (!targetLocations.has_value()) { + if (!targetLocations_.has_value()) { throw std::logic_error("Operation has no target locations set."); } - return *targetLocations; + return *targetLocations_; } [[nodiscard]] auto toString() const -> std::string override; }; diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp index 1f910b70e..24fdd0498 100644 --- a/include/mqt-core/na/operations/LocalOp.hpp +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -20,27 +20,20 @@ namespace na { class LocalOp : public Op { protected: - std::string name; - std::vector params; - std::vector atoms; + std::string name_; + std::vector params_; + std::vector atoms_; - LocalOp(std::vector params, std::vector atoms) - : params(std::move(params)), atoms(std::move(atoms)) {} - explicit LocalOp(std::vector& atoms) - : LocalOp({}, std::move(atoms)) {} - explicit LocalOp(std::vector params, const Atom* atom) - : LocalOp(std::move(params), std::vector{atom}) {} - explicit LocalOp(const Atom* atom) : LocalOp({}, atom) {} + LocalOp(std::vector atoms, std::vector params) + : params_(std::move(params)), atoms_(std::move(atoms)) {} public: LocalOp() = delete; - [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } - [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { - return atoms; + [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { + return atoms_; } - [[nodiscard]] auto getParams() -> decltype(params)& { return params; } - [[nodiscard]] auto getParams() const -> const decltype(params)& { - return params; + [[nodiscard]] auto getParams() const -> const decltype(params_)& { + return params_; } [[nodiscard]] auto toString() const -> std::string override; }; diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index e770ca310..c5235067c 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -20,12 +20,12 @@ namespace na { class LocalRZOp final : public LocalOp { public: - LocalRZOp(qc::fp angle, const Atom* atom) : LocalOp({angle}, atom) { - name = "rz"; + LocalRZOp(std::vector atom, const qc::fp angle) + : LocalOp(std::move(atom), {angle}) { + name_ = "rz"; } - LocalRZOp(qc::fp angle, std::vector atom) - : LocalOp({angle}, std::move(atom)) { - name = "rz"; + LocalRZOp(const Atom& atom, const qc::fp angle) : LocalRZOp({&atom}, angle) { + name_ = "rz"; } }; } // namespace na diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index 8dbbcfbec..f4e29aaab 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -22,25 +22,22 @@ namespace na { class MoveOp final : public ShuttlingOp { protected: - std::vector targetLocations; + std::vector targetLocations_; public: - explicit MoveOp(std::vector atoms, - std::vector targetLocations) + MoveOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), - targetLocations(std::move(targetLocations)) { - if (this->atoms.size() != this->targetLocations.size()) { + targetLocations_(std::move(targetLocations)) { + if (this->atoms.size() != this->targetLocations_.size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } - [[nodiscard]] auto getTargetLocations() - -> decltype(targetLocations)& override { - return targetLocations; - } + MoveOp(const Atom& atom, const Location& targetLocation) + : MoveOp({&atom}, {targetLocation}) {} [[nodiscard]] auto getTargetLocations() const -> const - decltype(targetLocations)& override { - return targetLocations; + decltype(targetLocations_)& override { + return targetLocations_; } [[nodiscard]] auto toString() const -> std::string override; }; diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp index 8da240591..87ecbe095 100644 --- a/include/mqt-core/na/operations/ShuttlingOp.hpp +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -24,11 +24,10 @@ class ShuttlingOp : public Op { : atoms(std::move(atoms)) {} public: - [[nodiscard]] auto getAtoms() -> decltype(atoms)& { return atoms; } + ShuttlingOp() = delete; [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { return atoms; } - [[nodiscard]] virtual auto getTargetLocations() -> std::vector& = 0; [[nodiscard]] virtual auto getTargetLocations() const -> const std::vector& = 0; }; diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index f6ed2c7b6..aca1528f0 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -26,8 +26,7 @@ class StoreOp final : public ShuttlingOp { std::optional> targetLocations = std::nullopt; public: - explicit StoreOp(std::vector atoms, - std::vector targetLocations) + StoreOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations(std::move(targetLocations)) { if (this->atoms.size() != this->targetLocations->size()) { @@ -37,15 +36,12 @@ class StoreOp final : public ShuttlingOp { } explicit StoreOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + StoreOp(const Atom& atom, const Location& targetLocation) + : StoreOp({&atom}, {targetLocation}) {} + explicit StoreOp(const Atom& atom) : StoreOp({&atom}) {} [[nodiscard]] auto hasTargetLocations() const -> bool { return targetLocations.has_value(); } - [[nodiscard]] auto getTargetLocations() -> std::vector& override { - if (!targetLocations.has_value()) { - throw std::logic_error("Operation has no target locations set."); - } - return *targetLocations; - } [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { if (!targetLocations.has_value()) { diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 28b8484c9..69cc0da46 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -29,23 +30,23 @@ #include namespace na { -auto NAComputation::getLocationOfAtomAfterOperation(const Atom* atom, - const Op* op) const +auto NAComputation::getLocationOfAtomAfterOperation(const Atom& atom, + const Op& op) const -> Location { - auto currentLocation = initialLocations.at(atom); + auto currentLocation = initialLocations_.at(&atom); for (const auto& opUniquePtr : *this) { if (opUniquePtr->is()) { const auto& moveOp = opUniquePtr->as(); const auto& opAtoms = moveOp.getAtoms(); const auto& targetLocations = moveOp.getTargetLocations(); for (std::size_t k = 0; k < opAtoms.size(); ++k) { - if (opAtoms[k] == atom) { + if (opAtoms[k] == &atom) { currentLocation = targetLocations[k]; break; } } } - if (opUniquePtr.get() == op) { + if (opUniquePtr.get() == &op) { break; } } @@ -53,11 +54,9 @@ auto NAComputation::getLocationOfAtomAfterOperation(const Atom* atom, } auto NAComputation::toString() const -> std::string { std::stringstream ss; - std::vector> initialLocationsAsc( - initialLocations.begin(), initialLocations.end()); - std::sort(initialLocationsAsc.begin(), initialLocationsAsc.end(), - [](const auto& a, const auto& b) { return a.second < b.second; }); - for (const auto& [atom, loc] : initialLocationsAsc) { + const std::map initialLocationsAsc( + initialLocations_.begin(), initialLocations_.end()); + for (const auto& [loc, atom] : initialLocationsAsc) { ss << "atom " << loc << " " << *atom << "\n"; } for (const auto& op : *this) { @@ -65,7 +64,7 @@ auto NAComputation::toString() const -> std::string { } return ss.str(); } -auto NAComputation::validate() const -> bool { +auto NAComputation::validate() const -> std::pair { // This counter is used to display the operation number where an error // occurred. // As every operation might not correspond to one line in the output, @@ -73,12 +72,15 @@ auto NAComputation::validate() const -> bool { // However, the first operation initializes the atom and because of that, the // counter starts with 1. std::size_t counter = 1; - if (atoms.size() != initialLocations.size()) { - std::cout << "Number of atoms and initial locations must be equal\n"; + std::stringstream ss; + if (atoms_.size() != initialLocations_.size()) { + ss << "Number of atoms and initial locations must be equal\n"; + return {false, ss.str()}; } // This map is used to keep track of each atom's current location to check // the constraints when shuttling atoms. - std::unordered_map currentLocations = initialLocations; + std::unordered_map currentLocations = + initialLocations_; // This set is used to keep track of the atoms that are currently shuttling, // i.e., they are loaded but not yet stored again. std::unordered_set currentlyShuttling{}; @@ -103,10 +105,9 @@ auto NAComputation::validate() const -> bool { << " (atom already loaded)\n"; return false; } - std::for_each(opAtoms.begin(), opAtoms.end(), - [¤tlyShuttling](const auto* atom) { - currentlyShuttling.insert(atom); - }); + for (const auto* atom : opAtoms) { + currentlyShuttling.emplace(atom); + } } else { //===-----------------------------------------------------------------// // Move and Store Operations @@ -215,9 +216,9 @@ auto NAComputation::validate() const -> bool { //===-----------------------------------------------------------------// // Store Operations //-----------------------------------------------------------------===// - std::for_each(opAtoms.begin(), opAtoms.end(), [&](const auto* atom) { + for (const auto& atom : opAtoms) { currentlyShuttling.erase(atom); - }); + } } } else if (op->is()) { //===----------------------------------------------------------------===// diff --git a/src/na/operations/GlobalOp.cpp b/src/na/operations/GlobalOp.cpp index 5ad55d7a4..9a08cd48f 100644 --- a/src/na/operations/GlobalOp.cpp +++ b/src/na/operations/GlobalOp.cpp @@ -18,13 +18,13 @@ namespace na { auto GlobalOp::toString() const -> std::string { std::stringstream ss; ss << std::setprecision(5) << std::fixed; - ss << "@+ " << name; - if (!params.empty()) { - for (const auto& p : params) { + ss << "@+ " << name_; + if (!params_.empty()) { + for (const auto& p : params_) { ss << " " << p; } } - ss << " " << *zone; + ss << " " << *zone_; return ss.str(); } } // namespace na diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp index a4197ea70..5f9572c13 100644 --- a/src/na/operations/LoadOp.cpp +++ b/src/na/operations/LoadOp.cpp @@ -18,16 +18,16 @@ auto LoadOp::toString() const -> std::string { std::stringstream ss; ss << "@+ load"; if (atoms.size() == 1) { - if (targetLocations) { - ss << " " << targetLocations->front(); + if (targetLocations_) { + ss << " " << targetLocations_->front(); } ss << " " << *(atoms.front()); } else { ss << " [\n"; for (std::size_t i = 0; i < atoms.size(); ++i) { ss << " "; - if (targetLocations) { - ss << (*targetLocations)[i] << " "; + if (targetLocations_) { + ss << (*targetLocations_)[i] << " "; } ss << *(atoms[i]) << "\n"; } diff --git a/src/na/operations/LocalOp.cpp b/src/na/operations/LocalOp.cpp index 1d1f5ee81..533285ade 100644 --- a/src/na/operations/LocalOp.cpp +++ b/src/na/operations/LocalOp.cpp @@ -18,20 +18,20 @@ namespace na { auto LocalOp::toString() const -> std::string { std::stringstream ss; ss << std::setprecision(5) << std::fixed; - ss << "@+ " << name; - if (atoms.size() == 1) { - if (!params.empty()) { - for (const auto& p : params) { + ss << "@+ " << name_; + if (atoms_.size() == 1) { + if (!params_.empty()) { + for (const auto& p : params_) { ss << " " << p; } } - ss << " " << *(atoms.front()); + ss << " " << *(atoms_.front()); } else { ss << " [\n"; - for (const auto* const atom : atoms) { + for (const auto* const atom : atoms_) { ss << " "; - if (!params.empty()) { - for (const auto& p : params) { + if (!params_.empty()) { + for (const auto& p : params_) { ss << p << " "; } } diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp index c21a63ada..b31a7c018 100644 --- a/src/na/operations/MoveOp.cpp +++ b/src/na/operations/MoveOp.cpp @@ -18,11 +18,11 @@ auto MoveOp::toString() const -> std::string { std::stringstream ss; ss << "@+ move"; if (atoms.size() == 1) { - ss << " " << targetLocations.front() << " " << *(atoms.front()); + ss << " " << targetLocations_.front() << " " << *(atoms.front()); } else { ss << " [\n"; for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << " " << targetLocations[i] << " " << *(atoms[i]) << "\n"; + ss << " " << targetLocations_[i] << " " << *(atoms[i]) << "\n"; } ss << "]"; } diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index dab488988..5ceffdebf 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -9,6 +9,9 @@ #include "Definitions.hpp" #include "na/NAComputation.hpp" +#include "na/entities/Atom.hpp" +#include "na/entities/Location.hpp" +#include "na/entities/Zone.hpp" #include "na/operations/GlobalCZOp.hpp" #include "na/operations/GlobalRYOp.hpp" #include "na/operations/LoadOp.hpp" @@ -21,12 +24,39 @@ #include namespace na { +TEST(NAComputation, Atom) { + const auto atom = Atom("atom"); + EXPECT_EQ(atom.getName(), "atom"); + std::stringstream ss; + ss << atom; + EXPECT_EQ(ss.str(), "atom"); +} + +TEST(NAComputation, Zone) { + const auto zone = Zone("zone"); + EXPECT_EQ(zone.getName(), "zone"); + std::stringstream ss; + ss << zone; + EXPECT_EQ(ss.str(), "zone"); +} + +TEST(NAComputation, Location) { + const Location loc{3, 4}; + EXPECT_EQ(loc, (Location{3, 4})); + std::stringstream ss; + ss << loc; + EXPECT_EQ(ss.str(), "(3.000, 4.000)"); + EXPECT_DOUBLE_EQ(loc.getEuclideanDistance(loc), 5.0); + EXPECT_DOUBLE_EQ(loc.getManhattanDistanceX(loc), 3); + EXPECT_DOUBLE_EQ(loc.getManhattanDistanceX(loc), 4); +} + TEST(NAComputation, General) { auto qc = NAComputation(); - const auto* const atom0 = qc.emplaceBackAtom("atom0"); - const auto* const atom1 = qc.emplaceBackAtom("atom1"); - const auto* const atom2 = qc.emplaceBackAtom("atom2"); - const auto* const globalZone = qc.emplaceBackZone("global"); + const auto& atom0 = qc.emplaceBackAtom("atom0"); + const auto& atom1 = qc.emplaceBackAtom("atom1"); + const auto& atom2 = qc.emplaceBackAtom("atom2"); + const auto& globalZone = qc.emplaceBackZone("global"); qc.emplaceInitialLocation(atom0, 0, 0); qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 2, 0); @@ -75,10 +105,10 @@ TEST(NAComputation, EmptyPrint) { TEST(NAComputation, ValidateAODConstraints) { auto qc = NAComputation(); - const auto* const atom0 = qc.emplaceBackAtom("atom0"); - const auto* const atom1 = qc.emplaceBackAtom("atom1"); - const auto* const atom2 = qc.emplaceBackAtom("atom2"); - const auto* const atom3 = qc.emplaceBackAtom("atom3"); + const auto& atom0 = qc.emplaceBackAtom("atom0"); + const auto& atom1 = qc.emplaceBackAtom("atom1"); + const auto& atom2 = qc.emplaceBackAtom("atom2"); + const auto& atom3 = qc.emplaceBackAtom("atom3"); qc.emplaceInitialLocation(atom0, 0, 0); qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 0, 2); From 21f311ea8bb6a997611fc8e979942ea3f65c465e Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 12:55:38 +0100 Subject: [PATCH 28/39] =?UTF-8?q?=F0=9F=93=9D=20Add=20mostly=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 49 +++++++++++++- include/mqt-core/na/NAUtils.hpp | 26 +++++--- include/mqt-core/na/entities/Atom.hpp | 19 +++++- include/mqt-core/na/entities/Location.hpp | 46 ++++++++++++- include/mqt-core/na/entities/Zone.hpp | 18 +++++- include/mqt-core/na/operations/GlobalCZOp.hpp | 3 + include/mqt-core/na/operations/GlobalOp.hpp | 13 ++++ include/mqt-core/na/operations/GlobalRYOp.hpp | 4 ++ include/mqt-core/na/operations/LoadOp.hpp | 33 +++++++++- include/mqt-core/na/operations/LocalOp.hpp | 12 +++- include/mqt-core/na/operations/LocalRZOp.hpp | 7 ++ include/mqt-core/na/operations/MoveOp.hpp | 20 +++++- include/mqt-core/na/operations/Op.hpp | 16 +++++ .../mqt-core/na/operations/ShuttlingOp.hpp | 21 ++++-- include/mqt-core/na/operations/StoreOp.hpp | 41 +++++++++--- src/na/NAComputation.cpp | 64 +++++++++---------- src/na/operations/LoadOp.cpp | 8 +-- src/na/operations/MoveOp.cpp | 8 +-- src/na/operations/StoreOp.cpp | 16 ++--- 19 files changed, 342 insertions(+), 82 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index ac9d67486..883630171 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -31,64 +31,99 @@ class NAComputation final { std::unordered_map initialLocations_; public: + /// Returns an iterator to the beginning of the operations. + /// @return An iterator to the beginning of the operations. [[nodiscard]] auto begin() -> decltype(operations_.begin()) { return operations_.begin(); } + /// Returns an iterator to the beginning of the operations. + /// @return An iterator to the beginning of the operations. [[nodiscard]] auto begin() const -> decltype(operations_.begin()) { return operations_.begin(); } + /// Returns an iterator to the end of the operations. + /// @return An iterator to the end of the operations. [[nodiscard]] auto end() -> decltype(operations_.end()) { return operations_.end(); } + /// Returns an iterator to the end of the operations. + /// @return An iterator to the end of the operations. [[nodiscard]] auto end() const -> decltype(operations_.end()) { return operations_.end(); } + /// Returns the number of operations in the NAComputation. + /// @return The number of operations in the NAComputation. [[nodiscard]] auto size() const -> std::size_t { return operations_.size(); } + /// Returns a reference to the operation at the given index. + /// @param i The index of the operation. + /// @return A reference to the operation at the given index. [[nodiscard]] auto operator[](std::size_t i) -> Op& { return *operations_[i]; } + /// Returns a reference to the operation at the given index. + /// @param i The index of the operation. + /// @return A reference to the operation at the given index. [[nodiscard]] auto operator[](std::size_t i) const -> const Op& { return *operations_[i]; } + /// Clears the operations in the NAComputation. auto clear() -> void { operations_.clear(); } + /// Returns the number of atoms used in the NAComputation. + /// @return The number of atoms used in the NAComputation. [[nodiscard]] auto getAtomsSize() const -> std::size_t { return atoms_.size(); } /// Returns the atoms used in the NAComputation. + /// @return The atoms used in the NAComputation. [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { return atoms_; } /// Returns the zones used in global operations within the NAComputation. + /// @return The zones used in global operations within the NAComputation. [[nodiscard]] auto getZones() const -> const decltype(zones_)& { return zones_; } /// Returns the initial locations of the atoms. + /// @return The initial locations of the atoms. [[nodiscard]] auto getInitialLocations() const -> const decltype(initialLocations_)& { return initialLocations_; } /// Returns the location of the given atom after the given operation. + /// @param atom The atom to get the location for. + /// @param op The operation to get the location after. + /// @return The location of the atom after the operation. [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom& atom, const Op& op) const -> Location; /// Emplaces a new atom with the given name and returns a reference to the /// newly created atom. + /// @param name The name of the atom. + /// @return A reference to the newly created atom. auto emplaceBackAtom(std::string name) -> const Atom& { return *atoms_.emplace_back(std::make_unique(std::move(name))); } - /// Emplaces a new operation of type T with the given operation and returns a - /// reference to the newly created operation. + /// Emplaces a new zone with the given name and returns a reference to the + /// newly created zone. + /// @param name The name of the zone. + /// @return A reference to the newly created zone. auto emplaceBackZone(std::string name) -> const Zone& { return *zones_.emplace_back(std::make_unique(std::move(name))); } /// Emplaces a new initial location for the given atom with the given location /// and returns a reference to the newly created location. + /// @param atom The atom to set the initial location for. + /// @param loc The location of the atom. + /// @return A reference to the newly created location. auto emplaceInitialLocation(const Atom* atom, const Location& loc) -> const Location& { return initialLocations_.emplace(atom, loc).first->second; } /// Emplaces a new initial location for the given atom with the given /// arguments and returns a reference to the newly created location. + /// @param atom The atom to set the initial location for. + /// @param loc The parameters for the location of the atom. + /// @return A reference to the newly created location. template auto emplaceInitialLocation(const Atom* atom, Args&&... loc) -> const Location& { @@ -97,21 +132,31 @@ class NAComputation final { } /// Emplaces a new operation of type T with the given operation and returns a /// reference to the newly created operation. + /// @tparam T The concrete type of the operation. + /// @param op The operation to emplace. + /// @return A reference to the newly created operation. template auto emplaceBack(T&& op) -> const Op& { return *std::vector>::emplace_back( std::make_unique(std::forward(op))); } /// Emplaces a new operation of type T with the given arguments and returns a /// reference to the newly created operation. + /// @tparam T The concrete type of the operation. + /// @param args The arguments for the operation. + /// @return A reference to the newly created operation. template auto emplaceBack(Args&&... args) -> const Op& { return *std::vector>::emplace_back( std::make_unique(std::forward(args)...)); } /// Returns a string representation of the NAComputation. + /// @return A string representation of the NAComputation. [[nodiscard]] auto toString() const -> std::string; /// Outputs the NAComputation to the given output stream, i.e., the string /// returned by toString(). + /// @param os The output stream to print the NAComputation to. + /// @param qc The NAComputation to print. + /// @return The output stream after printing the NAComputation. friend auto operator<<(std::ostream& os, const NAComputation& qc) -> std::ostream& { return os << qc.toString(); diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp index fd426748f..4d06c2a1f 100644 --- a/include/mqt-core/na/NAUtils.hpp +++ b/include/mqt-core/na/NAUtils.hpp @@ -27,6 +27,9 @@ namespace na { * StandardOperations of the same type with the same parameters acting on all * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in * MQT-core. All other operations are not global. + * @param op The operation to check. + * @param nQubits The number of qubits in the circuit. + * @return True if the operation is global, false otherwise. */ [[nodiscard]] inline auto isGlobal(const qc::Operation& op, const std::size_t nQubits) -> bool { @@ -49,20 +52,23 @@ namespace na { } } // namespace na -template <> struct std::hash> { - std::size_t - operator()(const std::pair& t) const noexcept { - const std::size_t h1 = std::hash{}(t.first); - const std::size_t h2 = std::hash{}(t.second); +/// @brief Specialization of std::hash for std::pair. +template <> struct std::hash> { + /// @brief Hashes a pair of qc::OpType and size_t values. + auto operator()(const std::pair& t) const noexcept + -> size_t { + const size_t h1 = std::hash{}(t.first); + const size_t h2 = std::hash{}(t.second); return qc::combineHash(h1, h2); } }; -template <> struct std::hash> { - std::size_t - operator()(const std::pair& p) const noexcept { - const std::size_t h1 = std::hash{}(p.first); - const std::size_t h2 = std::hash{}(p.second); +/// @brief Specialization of std::hash for std::pair. +template <> struct std::hash> { + /// @brief Hashes a pair of size_t values. + auto operator()(const std::pair& p) const noexcept -> size_t { + const size_t h1 = std::hash{}(p.first); + const size_t h2 = std::hash{}(p.second); return qc::combineHash(h1, h2); } }; diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp index 3cd9eb1da..16c860cd9 100644 --- a/include/mqt-core/na/entities/Atom.hpp +++ b/include/mqt-core/na/entities/Atom.hpp @@ -14,22 +14,39 @@ #include namespace na { +/// Represents an atom in the NA computation. +/// @details The name of the atom is used for printing the NAComputation. +/// To maintain the uniqueness of atoms, the name of the atom should be unique +/// for this atom. class Atom final { std::string name_; public: - Atom() = default; + /// Creates a new atom with the given name. + /// @param name The name of the atom. explicit Atom(std::string name) : name_(std::move(name)) {} + /// Returns the name of the atom. + /// @return The name of the atom. [[nodiscard]] auto getName() const -> std::string { return name_; } + /// Prints the atom to the given output stream. + /// @param os The output stream to print the atom to. + /// @param obj The atom to print. + /// @return The output stream after printing the atom. friend auto operator<<(std::ostream& os, const Atom& obj) -> std::ostream& { return os << obj.getName(); } + /// Compares two atoms for equality. + /// @param other The atom to compare with. + /// @return True if the atoms are equal, false otherwise. [[nodiscard]] auto operator==(const Atom& other) const -> bool { if (this == &other) { return true; } return name_ == other.name_; } + /// Compares two atoms for inequality. + /// @param other The atom to compare with. + /// @return True if the atoms are not equal, false otherwise. [[nodiscard]] auto operator!=(const Atom& other) const -> bool { return !(*this == other); } diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index 589f3c4fc..eb4e55d9d 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -19,52 +19,96 @@ #include namespace na { -/// Class to store two-dimensional coordinates +/// Class to store two-dimensional coordinates of type double. struct Location final { double x = 0; double y = 0; + /// Subtracts the coordinates of the given location from this location. + /// @param loc The location to subtract. + /// @return The location resulting from the subtraction. Location operator-(const Location& loc) const { return {x - loc.x, y - loc.y}; } + /// Adds the coordinates of the given location to this location. + /// @param loc The location to add. + /// @return The location resulting from the addition. Location operator+(const Location& loc) const { return {x + loc.x, y + loc.y}; } + /// Computes the length of the vector from the origin to this location. + /// @return The length of the vector. [[nodiscard]] auto length() const -> double { return std::hypot(x, y); } + /// Returns a string representation of the location. + /// @return The string representation of the location in the format "(x, y)". [[nodiscard]] auto toString() const -> std::string { std::stringstream ss; ss << std::setprecision(3) << std::fixed; ss << "(" << x << ", " << y << ")"; return ss.str(); } + /// Prints the location to the given output stream. + /// @param os The output stream to print the location to. + /// @param obj The location to print. + /// @return The output stream after printing the location. friend auto operator<<(std::ostream& os, const Location& obj) -> std::ostream& { return os << obj.toString(); } + /// Compares two locations for equality. + /// @param other The location to compare with. + /// @return True if the locations are equal, false otherwise. [[nodiscard]] auto operator==(const Location& other) const -> bool { return x == other.x && y == other.y; } + /// Compares two locations for inequality. + /// @param other The location to compare with. + /// @return True if the locations are not equal, false otherwise. [[nodiscard]] auto operator!=(const Location& other) const -> bool { return !(*this == other); } + /// Compares two locations for less than. + /// @param other The location to compare with. + /// @return True if this location is less than the other location, false [[nodiscard]] auto operator<(const Location& other) const -> bool { return x < other.x || (x == other.x && y < other.y); } + /// Compares two locations for greater than. + /// @param other The location to compare with. + /// @return True if this location is greater than the other location, false [[nodiscard]] auto operator>(const Location& other) const -> bool { return other < *this; } + /// Compares two locations for greater than or equal. + /// @param other The location to compare with. + /// @return True if this location is greater than or equal to the other [[nodiscard]] auto operator>=(const Location& other) const -> bool { return !(other < *this); } + /// Compares two locations for less than or equal. + /// @param other The location to compare with. + /// @return True if this location is less than or equal to the other location, [[nodiscard]] auto operator<=(const Location& other) const -> bool { return *this >= other; } + /// Computes the Euclidean distance between this location and the given + /// location. + /// @param loc The location to compute the distance to. + /// @return The Euclidean distance between the two locations. [[nodiscard]] auto getEuclideanDistance(const Location& loc) const -> double { return (*this - loc).length(); } + /// Computes the horizontal distance between this location and the given + /// location. + /// @param loc The location to compute the distance to. + /// @return The horizontal distance between the two locations. [[nodiscard]] auto getManhattanDistanceX(const Location& loc) const -> double { return std::abs(x - loc.x); } + /// Computes the vertical distance between this location and the given + /// location. + /// @param loc The location to compute the distance to. + /// @return The vertical distance between the two locations. [[nodiscard]] auto getManhattanDistanceY(const Location& loc) const -> double { return std::abs(y - loc.y); diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp index 3260a4ca1..22d5df478 100644 --- a/include/mqt-core/na/entities/Zone.hpp +++ b/include/mqt-core/na/entities/Zone.hpp @@ -14,22 +14,38 @@ #include namespace na { +/// Represents a zone in the NA computation. +/// @details The name of the zone is used for printing the NAComputation. +/// To maintain the uniqueness of zones, the name of the zone should be unique +/// for this zone. class Zone final { std::string name_; public: - Zone() = default; + /// Creates a new zone with the given name. + /// @param name The name of the zone. explicit Zone(std::string name) : name_(std::move(name)) {} + /// Returns the name of the zone. [[nodiscard]] auto getName() const -> std::string { return name_; } + /// Prints the zone to the given output stream. + /// @param os The output stream to print the zone to. + /// @param obj The zone to print. + /// @return The output stream after printing the zone. friend auto operator<<(std::ostream& os, const Zone& obj) -> std::ostream& { return os << obj.getName(); } + /// Compares two zones for equality. + /// @param other The zone to compare with. + /// @return True if the zones are equal, false otherwise. [[nodiscard]] auto operator==(const Zone& other) const -> bool { if (this == &other) { return true; } return name_ == other.name_; } + /// Compares two zones for inequality. + /// @param other The zone to compare with. + /// @return True if the zones are not equal, false otherwise. [[nodiscard]] auto operator!=(const Zone& other) const -> bool { return !(*this == other); } diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index 2735bed8c..8e8cf1467 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -13,8 +13,11 @@ #include "na/operations/GlobalOp.hpp" namespace na { +/// Represents a global cz operation in the NA computation. class GlobalCZOp final : public GlobalOp { public: + /// Creates a new cz operation in the given zone. + /// @param zone The zone the operation is applied to. explicit GlobalCZOp(const Zone& zone) : GlobalOp(zone, {}) { name_ = "cz"; } }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalOp.hpp b/include/mqt-core/na/operations/GlobalOp.hpp index a673bdb3a..0ab79b647 100644 --- a/include/mqt-core/na/operations/GlobalOp.hpp +++ b/include/mqt-core/na/operations/GlobalOp.hpp @@ -18,20 +18,33 @@ #include namespace na { +/// Represents a global operation in the NA computation. +/// @details Global operations are applied to entire zones instead of to +/// individual atoms. class GlobalOp : public Op { protected: std::string name_; std::vector params_; const Zone* zone_; + /// Creates a new global operation in the given zone with the given + /// parameters. + /// @param zone The zone the operation is applied to. + /// @param params The parameters of the operation. GlobalOp(const Zone& zone, std::vector params) : params_(std::move(params)), zone_(&zone) {} public: GlobalOp() = delete; + /// Returns the parameters of the operation. + /// @return The parameters of the operation. [[nodiscard]] auto getParams() const -> const decltype(params_)& { return params_; } + /// Returns the zone the operation is applied to. + /// @return The zone the operation is applied to. [[nodiscard]] auto getZone() const -> const Zone& { return *zone_; } + /// Returns a string representation of the operation. + /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index d60340a5c..1b8b1b42d 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -14,8 +14,12 @@ #include "na/operations/GlobalOp.hpp" namespace na { +/// Represents a global ry operation in the NA computation. class GlobalRYOp final : public GlobalOp { public: + /// Creates a new ry operation in the given zone with the given angle. + /// @param zone The zone the operation is applied to. + /// @param angle The angle of the operation. GlobalRYOp(const Zone& zone, qc::fp angle) : GlobalOp(zone, {angle}) { name_ = "ry"; } diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index 27719bac2..3661c67fb 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -20,28 +20,53 @@ #include namespace na { - +/// Represents a load operation in the NA computation. +/// @details Before an atom can be moved, it must be loaded, i.e., transferred +/// from a static SLM to an adjustable AOD trap. class LoadOp final : public ShuttlingOp { protected: std::optional> targetLocations_ = std::nullopt; public: + /// Creates a new load operation with the given atoms and target locations. + /// @details The target locations can be set if the loading operation contains + /// a certain offset. + /// @param atoms The atoms to load. + /// @param targetLocations The target locations to load the atoms to. LoadOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations_(std::move(targetLocations)) { - if (this->atoms.size() != this->targetLocations_->size()) { + if (this->atoms_.size() != this->targetLocations_->size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new load operation with the given atoms. + /// @details This constructor is used if the target locations are not set, + /// i.e., the load operation does not incorporate any offset. + /// @param atoms The atoms to load. explicit LoadOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + /// Creates a new load operation with the given atom and target location. + /// @details The target locations can be set if the loading operation contains + /// a certain offset. + /// @param atom The atom to load. + /// @param targetLocation The target location to load the atom to. LoadOp(const Atom& atom, const Location& targetLocation) : LoadOp({&atom}, {targetLocation}) {} + /// Creates a new load operation with the given atom. + /// @details This constructor is used if the target locations are not set, + /// i.e., the load operation does not incorporate any offset. + /// @param atom The atom to load. explicit LoadOp(const Atom& atom) : LoadOp({&atom}) {} - [[nodiscard]] auto hasTargetLocations() const -> bool { + /// Returns true if the load operation has target locations set. + /// @return True if the load operation has target locations set, false + /// otherwise. + [[nodiscard]] auto hasTargetLocations() const -> bool override { return targetLocations_.has_value(); } + /// Returns the target locations of the load operation. + /// @return The target locations of the load operation. [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { if (!targetLocations_.has_value()) { @@ -49,6 +74,8 @@ class LoadOp final : public ShuttlingOp { } return *targetLocations_; } + /// Returns a string representation of the load operation. + /// @return A string representation of the load operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp index 24fdd0498..5d718e70e 100644 --- a/include/mqt-core/na/operations/LocalOp.hpp +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -18,23 +18,33 @@ #include namespace na { +/// Represents a local operation in the NA computation. +/// @details A local operation is applied to individual atoms. class LocalOp : public Op { protected: std::string name_; std::vector params_; std::vector atoms_; - + /// Creates a new local operation with the given atoms and parameters. + /// @param atoms The atoms the operation is applied to. + /// @param params The parameters of the operation. LocalOp(std::vector atoms, std::vector params) : params_(std::move(params)), atoms_(std::move(atoms)) {} public: LocalOp() = delete; + /// Returns the atoms the operation is applied to. + /// @return The atoms the operation is applied to. [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { return atoms_; } + /// Returns the parameters of the operation. + /// @return The parameters of the operation. [[nodiscard]] auto getParams() const -> const decltype(params_)& { return params_; } + /// Returns a string representation of the operation. + /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index c5235067c..27251910f 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -18,12 +18,19 @@ #include namespace na { +/// Represents a local RZ operation in the NA computation. class LocalRZOp final : public LocalOp { public: + /// Creates a new RZ operation with the given atoms and angle. + /// @param atom The atoms the operation is applied to. + /// @param angle The angle of the operation. LocalRZOp(std::vector atom, const qc::fp angle) : LocalOp(std::move(atom), {angle}) { name_ = "rz"; } + /// Creates a new RZ operation with the given atom and angle. + /// @param atom The atom the operation is applied to. + /// @param angle The angle of the operation. LocalRZOp(const Atom& atom, const qc::fp angle) : LocalRZOp({&atom}, angle) { name_ = "rz"; } diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index f4e29aaab..c7b612d8b 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -19,26 +19,42 @@ #include namespace na { - +/// Represents a move operation in the NA computation. class MoveOp final : public ShuttlingOp { protected: std::vector targetLocations_; public: + /// Creates a new move operation with the given atoms and target locations. + /// @param atoms The atoms to move. + /// @param targetLocations The target locations to move the atoms to. MoveOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations_(std::move(targetLocations)) { - if (this->atoms.size() != this->targetLocations_.size()) { + if (this->atoms_.size() != this->targetLocations_.size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new move operation with the given atom and target location. + /// @param atom The atom to move. + /// @param targetLocation The target location to move the atom to. MoveOp(const Atom& atom, const Location& targetLocation) : MoveOp({&atom}, {targetLocation}) {} + /// Returns true if the move operation has target locations set. + /// @return True if the move operation has target locations set, false + /// otherwise. + [[nodiscard]] auto hasTargetLocations() const -> bool override { + return true; + } + /// Returns the target locations of the move operation. + /// @return The target locations of the move operation. [[nodiscard]] auto getTargetLocations() const -> const decltype(targetLocations_)& override { return targetLocations_; } + /// Returns a string representation of the operation. + /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp index ec1bab25a..6acd14ac5 100644 --- a/include/mqt-core/na/operations/Op.hpp +++ b/include/mqt-core/na/operations/Op.hpp @@ -13,20 +13,36 @@ #include namespace na { +/// This is the base class for all operations in the NA computation. class Op { public: Op() = default; virtual ~Op() = default; + /// Returns a string representation of the operation. + /// @return A string representation of the operation. [[nodiscard]] virtual auto toString() const -> std::string = 0; + /// Prints the operation to the given output stream. + /// @param os The output stream to print the operation to. + /// @param obj The operation to print. + /// @return The output stream after printing the operation. friend auto operator<<(std::ostream& os, const Op& obj) -> std::ostream& { return os << obj.toString(); // Using toString() method } + /// Checks if the operation is of the given type. + /// @tparam T The type to check for. + /// @return True if the operation is of the given type, false otherwise. template [[nodiscard]] auto is() const -> bool { return dynamic_cast(this) != nullptr; } + /// Casts the operation to the given type. + /// @tparam T The type to cast to. + /// @return The operation as the given type. template [[nodiscard]] auto as() -> T& { return dynamic_cast(*this); } + /// Casts the operation to the given type. + /// @tparam T The type to cast to. + /// @return The operation as the given type. template [[nodiscard]] auto as() const -> const T& { return dynamic_cast(*this); } diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp index 87ecbe095..6d26821b2 100644 --- a/include/mqt-core/na/operations/ShuttlingOp.hpp +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -17,17 +17,30 @@ #include namespace na { +/// Represents a shuttling operation in the NA computation. +/// @details A shuttling operation is the super class for all shuttling related +/// operations, i.e., load, store, and move operations. class ShuttlingOp : public Op { protected: - std::vector atoms; + std::vector atoms_; + /// Creates a new shuttling operation with the given atoms. + /// @param atoms The atoms the operation is applied to. explicit ShuttlingOp(std::vector atoms) - : atoms(std::move(atoms)) {} + : atoms_(std::move(atoms)) {} public: ShuttlingOp() = delete; - [[nodiscard]] auto getAtoms() const -> const decltype(atoms)& { - return atoms; + /// Returns the atoms the operation is applied to. + /// @return The atoms the operation is applied to. + [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { + return atoms_; } + /// Returns true if the shuttling operation has target locations set. + /// @return True if the shuttling operation has target locations set, false + /// otherwise. + [[nodiscard]] virtual auto hasTargetLocations() const -> bool = 0; + /// Returns the target locations of the shuttling operation. + /// @return The target locations of the shuttling operation. [[nodiscard]] virtual auto getTargetLocations() const -> const std::vector& = 0; }; diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index aca1528f0..44b3270a1 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -20,35 +20,60 @@ #include namespace na { - +/// Represents a store operation in the NA computation. class StoreOp final : public ShuttlingOp { protected: - std::optional> targetLocations = std::nullopt; + std::optional> targetLocations_ = std::nullopt; public: + /// Creates a new store operation with the given atoms and target locations. + /// @details The target locations can be used if the store operation + /// incorporates some offset. + /// @param atoms The atoms to store. + /// @param targetLocations The target locations to store the atoms to. StoreOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), - targetLocations(std::move(targetLocations)) { - if (this->atoms.size() != this->targetLocations->size()) { + targetLocations_(std::move(targetLocations)) { + if (this->atoms_.size() != this->targetLocations_->size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new store operation with the given atoms and target locations. + /// @details Here, the target locations are not used, i.e., this store does + /// not contain any offset. + /// @param atoms The atoms to store. explicit StoreOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + /// Creates a new store operation with the given atom and target location. + /// @details The target location can be used if the store operation + /// incorporates some offset. + /// @param atom The atom to store. + /// @param targetLocation The target location to store the atom to. StoreOp(const Atom& atom, const Location& targetLocation) : StoreOp({&atom}, {targetLocation}) {} + /// Creates a new store operation with the given atom and target locations. + /// @details Here, the target locations are not used, i.e., this store does + /// not contain any offset. + /// @param atom The atom to store. explicit StoreOp(const Atom& atom) : StoreOp({&atom}) {} - [[nodiscard]] auto hasTargetLocations() const -> bool { - return targetLocations.has_value(); + /// Returns true if the store operation has target locations set. + /// @return True if the store operation has target locations set, false + /// otherwise. + [[nodiscard]] auto hasTargetLocations() const -> bool override { + return targetLocations_.has_value(); } + /// Returns the target locations of the store operation. + /// @return The target locations of the store operation. [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { - if (!targetLocations.has_value()) { + if (!targetLocations_.has_value()) { throw std::logic_error("Operation has no target locations set."); } - return *targetLocations; + return *targetLocations_; } + /// Returns a string representation of the operation. + /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 69cc0da46..6b55b6ab2 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -101,9 +101,8 @@ auto NAComputation::validate() const -> std::pair { return currentlyShuttling.find(atom) != currentlyShuttling.end(); })) { - std::cout << "Error in op number " << counter - << " (atom already loaded)\n"; - return false; + ss << "Error in op number " << counter << " (atom already loaded)\n"; + return {false, ss.str()}; } for (const auto* atom : opAtoms) { currentlyShuttling.emplace(atom); @@ -117,9 +116,8 @@ auto NAComputation::validate() const -> std::pair { return currentlyShuttling.find(atom) == currentlyShuttling.end(); })) { - std::cout << "Error in op number " << counter - << " (atom not loaded)\n"; - return false; + ss << "Error in op number " << counter << " (atom not loaded)\n"; + return {false, ss.str()}; } } //===----------------------------------------------------------------===// @@ -134,26 +132,26 @@ auto NAComputation::validate() const -> std::pair { for (std::size_t j = i + 1; j < opAtoms.size(); ++j) { const auto* b = opAtoms[j]; if (a == b) { - std::cout << "Error in op number " << counter - << " (two atoms identical)\n"; - return false; + ss << "Error in op number " << counter + << " (two atoms identical)\n"; + return {false, ss.str()}; } const auto& s1 = currentLocations[a]; const auto& s2 = currentLocations[b]; const auto& e1 = targetLocations[i]; const auto& e2 = targetLocations[j]; if (e1 == e2) { - std::cout << "Error in op number " << counter - << " (two end points identical)\n"; - return false; + ss << "Error in op number " << counter + << " (two end points identical)\n"; + return {false, ss.str()}; } // Exp.: // o -----> o // o --> o if (s1.x == s2.x && e1.x != e2.x) { - std::cout << "Error in op number " << counter - << " (columns not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (columns not preserved)\n"; + return {false, ss.str()}; } // Exp.: // o o @@ -162,17 +160,17 @@ auto NAComputation::validate() const -> std::pair { // o v // o if (s1.y == s2.y && e1.y != e2.y) { - std::cout << "Error in op number " << counter - << " (rows not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (rows not preserved)\n"; + return {false, ss.str()}; } // Exp.: // o -------> o // o--> o if (s1.x < s2.x && e1.x >= e2.x) { - std::cout << "Error in op number " << counter - << " (column order not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (column order not preserved)\n"; + return {false, ss.str()}; } // Exp.: // o @@ -182,17 +180,17 @@ auto NAComputation::validate() const -> std::pair { // v o // o if (s1.y < s2.y && e1.y >= e2.y) { - std::cout << "Error in op number " << counter - << " (row order not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (row order not preserved)\n"; + return {false, ss.str()}; } // Exp.: // o--> o // o -------> o if (s1.x > s2.x && e1.x <= e2.x) { - std::cout << "Error in op number " << counter - << " (column order not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (column order not preserved)\n"; + return {false, ss.str()}; } // Exp.: // o @@ -202,9 +200,9 @@ auto NAComputation::validate() const -> std::pair { // o v // o if (s1.y > s2.y && e1.y <= e2.y) { - std::cout << "Error in op number " << counter - << " (row order not preserved)\n"; - return false; + ss << "Error in op number " << counter + << " (row order not preserved)\n"; + return {false, ss.str()}; } } } @@ -229,9 +227,9 @@ auto NAComputation::validate() const -> std::pair { const auto* a = opAtoms[i]; for (std::size_t j = i + 1; j < opAtoms.size(); ++j) { if (const auto* b = opAtoms[j]; a == b) { - std::cout << "Error in op number " << counter - << " (two atoms identical)\n"; - return false; + ss << "Error in op number " << counter + << " (two atoms identical)\n"; + return {false, ss.str()}; } } } diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp index 5f9572c13..284f3cfc9 100644 --- a/src/na/operations/LoadOp.cpp +++ b/src/na/operations/LoadOp.cpp @@ -17,19 +17,19 @@ namespace na { auto LoadOp::toString() const -> std::string { std::stringstream ss; ss << "@+ load"; - if (atoms.size() == 1) { + if (atoms_.size() == 1) { if (targetLocations_) { ss << " " << targetLocations_->front(); } - ss << " " << *(atoms.front()); + ss << " " << *(atoms_.front()); } else { ss << " [\n"; - for (std::size_t i = 0; i < atoms.size(); ++i) { + for (std::size_t i = 0; i < atoms_.size(); ++i) { ss << " "; if (targetLocations_) { ss << (*targetLocations_)[i] << " "; } - ss << *(atoms[i]) << "\n"; + ss << *(atoms_[i]) << "\n"; } ss << "]"; } diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp index b31a7c018..9c786349a 100644 --- a/src/na/operations/MoveOp.cpp +++ b/src/na/operations/MoveOp.cpp @@ -17,12 +17,12 @@ namespace na { auto MoveOp::toString() const -> std::string { std::stringstream ss; ss << "@+ move"; - if (atoms.size() == 1) { - ss << " " << targetLocations_.front() << " " << *(atoms.front()); + if (atoms_.size() == 1) { + ss << " " << targetLocations_.front() << " " << *(atoms_.front()); } else { ss << " [\n"; - for (std::size_t i = 0; i < atoms.size(); ++i) { - ss << " " << targetLocations_[i] << " " << *(atoms[i]) << "\n"; + for (std::size_t i = 0; i < atoms_.size(); ++i) { + ss << " " << targetLocations_[i] << " " << *(atoms_[i]) << "\n"; } ss << "]"; } diff --git a/src/na/operations/StoreOp.cpp b/src/na/operations/StoreOp.cpp index c3155b76c..31beb4e66 100644 --- a/src/na/operations/StoreOp.cpp +++ b/src/na/operations/StoreOp.cpp @@ -17,19 +17,19 @@ namespace na { auto StoreOp::toString() const -> std::string { std::stringstream ss; ss << "@+ store"; - if (atoms.size() == 1) { - if (targetLocations) { - ss << " " << targetLocations->front(); + if (atoms_.size() == 1) { + if (targetLocations_) { + ss << " " << targetLocations_->front(); } - ss << " " << *(atoms.front()); + ss << " " << *(atoms_.front()); } else { ss << " [\n"; - for (std::size_t i = 0; i < atoms.size(); ++i) { + for (std::size_t i = 0; i < atoms_.size(); ++i) { ss << " "; - if (targetLocations) { - ss << (*targetLocations)[i] << " "; + if (targetLocations_) { + ss << (*targetLocations_)[i] << " "; } - ss << *(atoms[i]) << "\n"; + ss << *(atoms_[i]) << "\n"; } ss << "]"; } From a8aa02a34cf5565008f8ce5606bcfd468de6d107 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:11:00 +0100 Subject: [PATCH 29/39] =?UTF-8?q?=F0=9F=90=9B=20Fix=20all=20open=20constru?= =?UTF-8?q?ction=20sites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mqt-core/na/NAComputation.hpp | 15 +-- include/mqt-core/na/NAUtils.hpp | 27 +----- include/mqt-core/na/entities/Location.hpp | 16 +++- src/na/NAComputation.cpp | 8 +- test/na/test_nacomputation.cpp | 108 +++++++++++----------- 5 files changed, 82 insertions(+), 92 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index 883630171..c4d09eb08 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -115,9 +115,9 @@ class NAComputation final { /// @param atom The atom to set the initial location for. /// @param loc The location of the atom. /// @return A reference to the newly created location. - auto emplaceInitialLocation(const Atom* atom, const Location& loc) + auto emplaceInitialLocation(const Atom& atom, const Location& loc) -> const Location& { - return initialLocations_.emplace(atom, loc).first->second; + return initialLocations_.emplace(&atom, loc).first->second; } /// Emplaces a new initial location for the given atom with the given /// arguments and returns a reference to the newly created location. @@ -125,9 +125,11 @@ class NAComputation final { /// @param loc The parameters for the location of the atom. /// @return A reference to the newly created location. template - auto emplaceInitialLocation(const Atom* atom, Args&&... loc) + auto emplaceInitialLocation(const Atom& atom, Args&&... loc) -> const Location& { - return initialLocations_.emplace(atom, Location{std::forward(loc)...}) + return initialLocations_ + .emplace(&atom, + Location{static_cast(std::forward(loc))...}) .first->second; } /// Emplaces a new operation of type T with the given operation and returns a @@ -136,8 +138,7 @@ class NAComputation final { /// @param op The operation to emplace. /// @return A reference to the newly created operation. template auto emplaceBack(T&& op) -> const Op& { - return *std::vector>::emplace_back( - std::make_unique(std::forward(op))); + return *operations_.emplace_back(std::make_unique(std::forward(op))); } /// Emplaces a new operation of type T with the given arguments and returns a /// reference to the newly created operation. @@ -146,7 +147,7 @@ class NAComputation final { /// @return A reference to the newly created operation. template auto emplaceBack(Args&&... args) -> const Op& { - return *std::vector>::emplace_back( + return *operations_.emplace_back( std::make_unique(std::forward(args)...)); } /// Returns a string representation of the NAComputation. diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp index 4d06c2a1f..007ec92d9 100644 --- a/include/mqt-core/na/NAUtils.hpp +++ b/include/mqt-core/na/NAUtils.hpp @@ -9,15 +9,11 @@ #pragma once -#include "Definitions.hpp" #include "ir/operations/CompoundOperation.hpp" -#include "ir/operations/OpType.hpp" #include "ir/operations/Operation.hpp" #include #include -#include -#include namespace na { /** @@ -26,7 +22,7 @@ namespace na { * A CompoundOperation is global if all its sub-operations are * StandardOperations of the same type with the same parameters acting on all * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in - * MQT-core. All other operations are not global. + * MQT Core. All other operations are not global. * @param op The operation to check. * @param nQubits The number of qubits in the circuit. * @return True if the operation is global, false otherwise. @@ -51,24 +47,3 @@ namespace na { return false; } } // namespace na - -/// @brief Specialization of std::hash for std::pair. -template <> struct std::hash> { - /// @brief Hashes a pair of qc::OpType and size_t values. - auto operator()(const std::pair& t) const noexcept - -> size_t { - const size_t h1 = std::hash{}(t.first); - const size_t h2 = std::hash{}(t.second); - return qc::combineHash(h1, h2); - } -}; - -/// @brief Specialization of std::hash for std::pair. -template <> struct std::hash> { - /// @brief Hashes a pair of size_t values. - auto operator()(const std::pair& p) const noexcept -> size_t { - const size_t h1 = std::hash{}(p.first); - const size_t h2 = std::hash{}(p.second); - return qc::combineHash(h1, h2); - } -}; diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index eb4e55d9d..c306f09ba 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -9,14 +9,16 @@ #pragma once +#include "Definitions.hpp" + #include -#include +#include +#include #include #include #include #include #include -#include namespace na { /// Class to store two-dimensional coordinates of type double. @@ -115,3 +117,13 @@ struct Location final { } }; } // namespace na + +/// @brief Specialization of std::hash for na::Location. +template <> struct std::hash { + /// @brief Hashes a pair of qc::OpType and size_t values. + auto operator()(const na::Location& loc) const noexcept -> size_t { + const size_t h1 = std::hash{}(loc.x); + const size_t h2 = std::hash{}(loc.y); + return qc::combineHash(h1, h2); + } +}; diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index 6b55b6ab2..f01cb1873 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -54,8 +54,10 @@ auto NAComputation::getLocationOfAtomAfterOperation(const Atom& atom, } auto NAComputation::toString() const -> std::string { std::stringstream ss; - const std::map initialLocationsAsc( - initialLocations_.begin(), initialLocations_.end()); + std::map initialLocationsAsc; + for (const auto& location : initialLocations_) { + initialLocationsAsc.emplace(location.second, location.first); + } for (const auto& [loc, atom] : initialLocationsAsc) { ss << "atom " << loc << " " << *atom << "\n"; } @@ -235,6 +237,6 @@ auto NAComputation::validate() const -> std::pair { } } } - return true; + return {true, ""}; } } // namespace na diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 5ceffdebf..49b019d9b 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -46,9 +46,9 @@ TEST(NAComputation, Location) { std::stringstream ss; ss << loc; EXPECT_EQ(ss.str(), "(3.000, 4.000)"); - EXPECT_DOUBLE_EQ(loc.getEuclideanDistance(loc), 5.0); - EXPECT_DOUBLE_EQ(loc.getManhattanDistanceX(loc), 3); - EXPECT_DOUBLE_EQ(loc.getManhattanDistanceX(loc), 4); + EXPECT_DOUBLE_EQ((Location{0, 0}).getEuclideanDistance(loc), 5.0); + EXPECT_DOUBLE_EQ((Location{0, 0}).getManhattanDistanceX(loc), 3); + EXPECT_DOUBLE_EQ((Location{0, 0}).getManhattanDistanceY(loc), 4); } TEST(NAComputation, General) { @@ -60,14 +60,14 @@ TEST(NAComputation, General) { qc.emplaceInitialLocation(atom0, 0, 0); qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 2, 0); - qc.emplaceBack(qc::PI_2, atom0); - qc.emplaceBack(qc::PI_2, std::vector{atom1, atom2}); - qc.emplaceBack(qc::PI_2, globalZone); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(atom0, qc::PI_2); + qc.emplaceBack(std::vector{&atom1, &atom2}, qc::PI_2); + qc.emplaceBack(globalZone, qc::PI_2); + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{0, 1}, Location{1, 1}}); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{4, 1}, Location{5, 1}}); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{4, 0}, Location{5, 0}}); qc.emplaceBack(GlobalCZOp(globalZone)); std::stringstream ss; @@ -113,92 +113,92 @@ TEST(NAComputation, ValidateAODConstraints) { qc.emplaceInitialLocation(atom1, 1, 0); qc.emplaceInitialLocation(atom2, 0, 2); qc.emplaceInitialLocation(atom3, 1, 2); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{0, 1}, Location{1, 1}}); - EXPECT_TRUE(qc.validate()); + EXPECT_TRUE(qc.validate().first); // atom already loaded - qc.emplaceBack(std::vector{atom0}, std::vector{Location{0, 1}}); - EXPECT_FALSE(qc.validate()); + qc.emplaceBack(atom0, Location{0, 1}); + EXPECT_FALSE(qc.validate().first); qc.clear(); // atom not loaded - qc.emplaceBack(std::vector{atom0}, std::vector{Location{0, 1}}); - EXPECT_FALSE(qc.validate()); + qc.emplaceBack(atom0, Location{0, 1}); + EXPECT_FALSE(qc.validate().first); qc.clear(); // two atoms identical - qc.emplaceBack(std::vector{atom0, atom0}); - qc.emplaceBack(std::vector{atom0, atom0}, + qc.emplaceBack(std::vector{&atom0, &atom0}); + qc.emplaceBack(std::vector{&atom0, &atom0}, std::vector{Location{0, 1}, Location{1, 1}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // two end points identical - qc.emplaceBack(std::vector{atom0, atom1}); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{&atom0, &atom1}); + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{0, 1}, Location{0, 1}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // columns not preserved - qc.emplaceBack(std::vector{atom1, atom3}); - qc.emplaceBack(std::vector{atom1, atom3}, + qc.emplaceBack(std::vector{&atom1, &atom3}); + qc.emplaceBack(std::vector{&atom1, &atom3}, std::vector{Location{0, 1}, Location{2, 2}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // rows not preserved - qc.emplaceBack(std::vector{atom0, atom1}); - qc.emplaceBack(std::vector{atom0, atom1}, + qc.emplaceBack(std::vector{&atom0, &atom1}); + qc.emplaceBack(std::vector{&atom0, &atom1}, std::vector{Location{0, 1}, Location{1, -1}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // column order not preserved - qc.emplaceBack(std::vector{atom0, atom3}); - qc.emplaceBack(std::vector{atom0, atom3}, + qc.emplaceBack(std::vector{&atom0, &atom3}); + qc.emplaceBack(std::vector{&atom0, &atom3}, std::vector{Location{1, 1}, Location{0, 1}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // row order not preserved - qc.emplaceBack(std::vector{atom0, atom3}); - qc.emplaceBack(std::vector{atom0, atom3}, + qc.emplaceBack(std::vector{&atom0, &atom3}); + qc.emplaceBack(std::vector{&atom0, &atom3}, std::vector{Location{0, 1}, Location{2, 0}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // column order not preserved - qc.emplaceBack(std::vector{atom2, atom1}); - qc.emplaceBack(std::vector{atom1, atom2}, + qc.emplaceBack(std::vector{&atom2, &atom1}); + qc.emplaceBack(std::vector{&atom1, &atom2}, std::vector{Location{0, 1}, Location{1, 3}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // row order not preserved - qc.emplaceBack(std::vector{atom2, atom1}); - qc.emplaceBack(std::vector{atom2, atom1}, + qc.emplaceBack(std::vector{&atom2, &atom1}); + qc.emplaceBack(std::vector{&atom2, &atom1}, std::vector{Location{0, 1}, Location{2, 2}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); // two atoms identical - qc.emplaceBack(qc::PI_2, std::vector{atom0, atom0}); - EXPECT_FALSE(qc.validate()); + qc.emplaceBack(std::vector{&atom0, &atom0}, qc::PI_2); + EXPECT_FALSE(qc.validate().first); qc.clear(); // store unloaded atom - qc.emplaceBack(std::vector{atom0}); - EXPECT_FALSE(qc.validate()); + qc.emplaceBack(atom0); + EXPECT_FALSE(qc.validate().first); qc.clear(); - qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{&atom2, &atom1}); // row order not preserved - qc.emplaceBack(std::vector{atom2, atom1}, + qc.emplaceBack(std::vector{&atom2, &atom1}, std::vector{Location{0, 1}, Location{2, 2}}); - EXPECT_FALSE(qc.validate()); + EXPECT_FALSE(qc.validate().first); qc.clear(); - qc.emplaceBack(std::vector{atom1}); - qc.emplaceBack(std::vector{atom1}); - qc.emplaceBack(std::vector{atom1}); - EXPECT_FALSE(qc.validate()); + qc.emplaceBack(atom1); + qc.emplaceBack(atom1); + qc.emplaceBack(atom1); + EXPECT_FALSE(qc.validate().first); } TEST(NAComputation, GetPositionOfAtomAfterOperation) { auto qc = NAComputation(); - const auto* const atom0 = qc.emplaceBackAtom("atom0"); + const auto& atom0 = qc.emplaceBackAtom("atom0"); qc.emplaceInitialLocation(atom0, 0, 0); - qc.emplaceBack(std::vector{atom0}); - qc.emplaceBack(std::vector{atom0}, std::vector{Location{1, 1}}); - qc.emplaceBack(std::vector{atom0}); + qc.emplaceBack(atom0); + qc.emplaceBack(atom0, Location{1, 1}); + qc.emplaceBack(atom0); EXPECT_EQ(qc.getLocationOfAtomAfterOperation(atom0, qc[0]), (Location{0, 0})); EXPECT_EQ(qc.getLocationOfAtomAfterOperation(atom0, qc[2]), (Location{1, 1})); } From 4edea4a5793ff0c72916170fb59c6035f3934d0e Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:47:19 +0100 Subject: [PATCH 30/39] =?UTF-8?q?=F0=9F=8E=A8=20Move=20isGLobal=20to=20qc:?= =?UTF-8?q?:Operation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ir/operations/CompoundOperation.hpp | 2 + include/mqt-core/ir/operations/Operation.hpp | 13 ++ .../ir/operations/StandardOperation.hpp | 2 + src/ir/operations/CompoundOperation.cpp | 11 ++ src/ir/operations/StandardOperation.cpp | 3 + src/na/operations/LoadOp.cpp | 18 +-- src/na/operations/LocalOp.cpp | 20 +-- src/na/operations/MoveOp.cpp | 12 +- src/na/operations/StoreOp.cpp | 18 +-- test/ir/test_operation.cpp | 15 ++ test/na/test_nacomputation.cpp | 135 ++++++++++-------- 11 files changed, 154 insertions(+), 95 deletions(-) diff --git a/include/mqt-core/ir/operations/CompoundOperation.hpp b/include/mqt-core/ir/operations/CompoundOperation.hpp index 74c54e735..5a430b530 100644 --- a/include/mqt-core/ir/operations/CompoundOperation.hpp +++ b/include/mqt-core/ir/operations/CompoundOperation.hpp @@ -55,6 +55,8 @@ class CompoundOperation final : public Operation { [[nodiscard]] bool isCustomGate() const noexcept; + [[nodiscard]] bool isGlobal(size_t nQubits) const noexcept override; + void addControl(Control c) override; void clearControls() override; diff --git a/include/mqt-core/ir/operations/Operation.hpp b/include/mqt-core/ir/operations/Operation.hpp index 746ab175c..1d6197122 100644 --- a/include/mqt-core/ir/operations/Operation.hpp +++ b/include/mqt-core/ir/operations/Operation.hpp @@ -154,6 +154,19 @@ class Operation { [[nodiscard]] virtual bool isControlled() const { return !controls.empty(); } + /** + * @brief Checks whether a gate is global. + * @details A StandardOperation is global if it acts on all qubits. + * A CompoundOperation is global if all its sub-operations are + * StandardOperations of the same type with the same parameters acting on all + * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in + * MQT Core. All other operations are not global. + * @return True if the operation is global, false otherwise. + */ + [[nodiscard]] virtual bool isGlobal(size_t /* unused */) const { + return false; + } + [[nodiscard]] virtual bool actsOn(const Qubit i) const { for (const auto& t : targets) { if (t == i) { diff --git a/include/mqt-core/ir/operations/StandardOperation.hpp b/include/mqt-core/ir/operations/StandardOperation.hpp index 499569850..34b4b5eb3 100644 --- a/include/mqt-core/ir/operations/StandardOperation.hpp +++ b/include/mqt-core/ir/operations/StandardOperation.hpp @@ -81,6 +81,8 @@ class StandardOperation : public Operation { [[nodiscard]] bool isStandardOperation() const override { return true; } + [[nodiscard]] bool isGlobal(size_t nQubits) const override; + void addControl(const Control c) override { if (actsOn(c.qubit)) { throw QFRException("Cannot add control on qubit " + diff --git a/src/ir/operations/CompoundOperation.cpp b/src/ir/operations/CompoundOperation.cpp index cf3181283..83e959651 100644 --- a/src/ir/operations/CompoundOperation.cpp +++ b/src/ir/operations/CompoundOperation.cpp @@ -74,6 +74,17 @@ bool CompoundOperation::isCompoundOperation() const noexcept { return true; } bool CompoundOperation::isCustomGate() const noexcept { return customGate; } +bool CompoundOperation::isGlobal(const size_t nQubits) const noexcept { + const auto& type = ops.at(0)->getType(); + return getUsedQubits().size() == nQubits && + std::all_of(ops.cbegin(), ops.cend(), [&](const auto& operation) { + return operation->isStandardOperation() && + operation->getNcontrols() == 0 && + operation->getType() == type && + operation->getParameter() == parameter; + }); +} + bool CompoundOperation::isSymbolicOperation() const { return std::any_of(ops.begin(), ops.end(), [](const auto& op) { return op->isSymbolicOperation(); }); diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index f14ba6c30..70494855f 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -240,6 +240,9 @@ StandardOperation::StandardOperation(const Controls& c, const Qubit target0, const Qubit target1, const OpType g, const std::vector& params) : StandardOperation(c, {target0, target1}, g, params) {} +bool StandardOperation::isGlobal(const size_t nQubits) const { + return getUsedQubits().size() == nQubits; +} /*** * Public Methods diff --git a/src/na/operations/LoadOp.cpp b/src/na/operations/LoadOp.cpp index 284f3cfc9..e9a024d31 100644 --- a/src/na/operations/LoadOp.cpp +++ b/src/na/operations/LoadOp.cpp @@ -22,17 +22,17 @@ auto LoadOp::toString() const -> std::string { ss << " " << targetLocations_->front(); } ss << " " << *(atoms_.front()); - } else { - ss << " [\n"; - for (std::size_t i = 0; i < atoms_.size(); ++i) { - ss << " "; - if (targetLocations_) { - ss << (*targetLocations_)[i] << " "; - } - ss << *(atoms_[i]) << "\n"; + return ss.str(); + } + ss << " [\n"; + for (std::size_t i = 0; i < atoms_.size(); ++i) { + ss << " "; + if (targetLocations_) { + ss << (*targetLocations_)[i] << " "; } - ss << "]"; + ss << *(atoms_[i]) << "\n"; } + ss << "]"; return ss.str(); } } // namespace na diff --git a/src/na/operations/LocalOp.cpp b/src/na/operations/LocalOp.cpp index 533285ade..50f6e74d6 100644 --- a/src/na/operations/LocalOp.cpp +++ b/src/na/operations/LocalOp.cpp @@ -26,19 +26,19 @@ auto LocalOp::toString() const -> std::string { } } ss << " " << *(atoms_.front()); - } else { - ss << " [\n"; - for (const auto* const atom : atoms_) { - ss << " "; - if (!params_.empty()) { - for (const auto& p : params_) { - ss << p << " "; - } + return ss.str(); + } + ss << " [\n"; + for (const auto* const atom : atoms_) { + ss << " "; + if (!params_.empty()) { + for (const auto& p : params_) { + ss << p << " "; } - ss << *atom << "\n"; } - ss << "]"; + ss << *atom << "\n"; } + ss << "]"; return ss.str(); } } // namespace na diff --git a/src/na/operations/MoveOp.cpp b/src/na/operations/MoveOp.cpp index 9c786349a..cfeebd285 100644 --- a/src/na/operations/MoveOp.cpp +++ b/src/na/operations/MoveOp.cpp @@ -19,13 +19,13 @@ auto MoveOp::toString() const -> std::string { ss << "@+ move"; if (atoms_.size() == 1) { ss << " " << targetLocations_.front() << " " << *(atoms_.front()); - } else { - ss << " [\n"; - for (std::size_t i = 0; i < atoms_.size(); ++i) { - ss << " " << targetLocations_[i] << " " << *(atoms_[i]) << "\n"; - } - ss << "]"; + return ss.str(); } + ss << " [\n"; + for (std::size_t i = 0; i < atoms_.size(); ++i) { + ss << " " << targetLocations_[i] << " " << *(atoms_[i]) << "\n"; + } + ss << "]"; return ss.str(); } } // namespace na diff --git a/src/na/operations/StoreOp.cpp b/src/na/operations/StoreOp.cpp index 31beb4e66..06d219749 100644 --- a/src/na/operations/StoreOp.cpp +++ b/src/na/operations/StoreOp.cpp @@ -22,17 +22,17 @@ auto StoreOp::toString() const -> std::string { ss << " " << targetLocations_->front(); } ss << " " << *(atoms_.front()); - } else { - ss << " [\n"; - for (std::size_t i = 0; i < atoms_.size(); ++i) { - ss << " "; - if (targetLocations_) { - ss << (*targetLocations_)[i] << " "; - } - ss << *(atoms_[i]) << "\n"; + return ss.str(); + } + ss << " [\n"; + for (std::size_t i = 0; i < atoms_.size(); ++i) { + ss << " "; + if (targetLocations_) { + ss << (*targetLocations_)[i] << " "; } - ss << "]"; + ss << *(atoms_[i]) << "\n"; } + ss << "]"; return ss.str(); } } // namespace na diff --git a/test/ir/test_operation.cpp b/test/ir/test_operation.cpp index 912fa55fe..5ffda4613 100644 --- a/test/ir/test_operation.cpp +++ b/test/ir/test_operation.cpp @@ -9,6 +9,7 @@ #include "Definitions.hpp" #include "ir/Permutation.hpp" +#include "ir/QuantumComputation.hpp" #include "ir/Register.hpp" #include "ir/operations/AodOperation.hpp" #include "ir/operations/CompoundOperation.hpp" @@ -18,10 +19,12 @@ #include "ir/operations/Operation.hpp" #include "ir/operations/StandardOperation.hpp" #include "ir/operations/SymbolicOperation.hpp" +#include "qasm3/Importer.hpp" #include #include #include +#include #include #include @@ -151,6 +154,18 @@ TEST(Operation, IsDiagonalGate) { EXPECT_TRUE(op2.isDiagonalGate()); } +TEST(Operation, IsGlobalGate) { + const std::string testfile = "OPENQASM 3.0;\n" + "include \"stdgates.inc\";\n" + "qubit[3] q;\n" + "rz(pi/4) q[0];\n" + "ry(pi/2) q;\n"; + const auto qc = qasm3::Importer::imports(testfile); + EXPECT_EQ(qc.getHighestLogicalQubitIndex(), 2); + EXPECT_FALSE(qc.at(0)->isGlobal(3)); + EXPECT_TRUE(qc.at(1)->isGlobal(3)); +} + TEST(Operation, Equality) { const qc::StandardOperation op1(0, qc::Z); const qc::StandardOperation op2(1, 0, qc::Z); diff --git a/test/na/test_nacomputation.cpp b/test/na/test_nacomputation.cpp index 49b019d9b..5ebe6a8ae 100644 --- a/test/na/test_nacomputation.cpp +++ b/test/na/test_nacomputation.cpp @@ -41,7 +41,7 @@ TEST(NAComputation, Zone) { } TEST(NAComputation, Location) { - const Location loc{3, 4}; + constexpr Location loc{3, 4}; EXPECT_EQ(loc, (Location{3, 4})); std::stringstream ss; ss << loc; @@ -103,92 +103,105 @@ TEST(NAComputation, EmptyPrint) { EXPECT_EQ(ss.str(), ""); } -TEST(NAComputation, ValidateAODConstraints) { - auto qc = NAComputation(); - const auto& atom0 = qc.emplaceBackAtom("atom0"); - const auto& atom1 = qc.emplaceBackAtom("atom1"); - const auto& atom2 = qc.emplaceBackAtom("atom2"); - const auto& atom3 = qc.emplaceBackAtom("atom3"); - qc.emplaceInitialLocation(atom0, 0, 0); - qc.emplaceInitialLocation(atom1, 1, 0); - qc.emplaceInitialLocation(atom2, 0, 2); - qc.emplaceInitialLocation(atom3, 1, 2); - qc.emplaceBack(std::vector{&atom0, &atom1}, +class NAComputationValidateAODConstraints : public ::testing::Test { +protected: + NAComputation qc; + const Atom* atom0 = nullptr; + const Atom* atom1 = nullptr; + const Atom* atom2 = nullptr; + const Atom* atom3 = nullptr; + + auto SetUp() -> void override { + atom0 = &qc.emplaceBackAtom("atom0"); + atom1 = &qc.emplaceBackAtom("atom1"); + atom2 = &qc.emplaceBackAtom("atom2"); + atom3 = &qc.emplaceBackAtom("atom3"); + qc.emplaceInitialLocation(*atom0, 0, 0); + qc.emplaceInitialLocation(*atom1, 1, 0); + qc.emplaceInitialLocation(*atom2, 0, 2); + qc.emplaceInitialLocation(*atom3, 1, 2); + } +}; + +TEST_F(NAComputationValidateAODConstraints, AtomAlreadyLoaded) { + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, 1}}); EXPECT_TRUE(qc.validate().first); - // atom already loaded - qc.emplaceBack(atom0, Location{0, 1}); + qc.emplaceBack(*atom0, Location{0, 1}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // atom not loaded - qc.emplaceBack(atom0, Location{0, 1}); +} +TEST_F(NAComputationValidateAODConstraints, AtomNotLoaded) { + qc.emplaceBack(*atom0, Location{0, 1}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // two atoms identical - qc.emplaceBack(std::vector{&atom0, &atom0}); - qc.emplaceBack(std::vector{&atom0, &atom0}, +} +TEST_F(NAComputationValidateAODConstraints, DuplicateAtomsInShuttle) { + qc.emplaceBack(std::vector{atom0, atom0}); + qc.emplaceBack(std::vector{atom0, atom0}, std::vector{Location{0, 1}, Location{1, 1}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // two end points identical - qc.emplaceBack(std::vector{&atom0, &atom1}); - qc.emplaceBack(std::vector{&atom0, &atom1}, +} +TEST_F(NAComputationValidateAODConstraints, DuplicateEndPoints) { + qc.emplaceBack(std::vector{atom0, atom1}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // columns not preserved - qc.emplaceBack(std::vector{&atom1, &atom3}); - qc.emplaceBack(std::vector{&atom1, &atom3}, +} +TEST_F(NAComputationValidateAODConstraints, ColumnPreserving1) { + qc.emplaceBack(std::vector{atom1, atom3}); + qc.emplaceBack(std::vector{atom1, atom3}, std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // rows not preserved - qc.emplaceBack(std::vector{&atom0, &atom1}); - qc.emplaceBack(std::vector{&atom0, &atom1}, +} +TEST_F(NAComputationValidateAODConstraints, RowPreserving1) { + qc.emplaceBack(std::vector{atom0, atom1}); + qc.emplaceBack(std::vector{atom0, atom1}, std::vector{Location{0, 1}, Location{1, -1}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // column order not preserved - qc.emplaceBack(std::vector{&atom0, &atom3}); - qc.emplaceBack(std::vector{&atom0, &atom3}, +} +TEST_F(NAComputationValidateAODConstraints, ColumnPreserving2) { + qc.emplaceBack(std::vector{atom0, atom3}); + qc.emplaceBack(std::vector{atom0, atom3}, std::vector{Location{1, 1}, Location{0, 1}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); +} +TEST_F(NAComputationValidateAODConstraints, RowPreserving2) { // row order not preserved - qc.emplaceBack(std::vector{&atom0, &atom3}); - qc.emplaceBack(std::vector{&atom0, &atom3}, + qc.emplaceBack(std::vector{atom0, atom3}); + qc.emplaceBack(std::vector{atom0, atom3}, std::vector{Location{0, 1}, Location{2, 0}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // column order not preserved - qc.emplaceBack(std::vector{&atom2, &atom1}); - qc.emplaceBack(std::vector{&atom1, &atom2}, +} +TEST_F(NAComputationValidateAODConstraints, ColumnPreserving3) { + qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{atom1, atom2}, std::vector{Location{0, 1}, Location{1, 3}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // row order not preserved - qc.emplaceBack(std::vector{&atom2, &atom1}); - qc.emplaceBack(std::vector{&atom2, &atom1}, +} +TEST_F(NAComputationValidateAODConstraints, RowPreserving3) { + qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{atom2, atom1}, std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - // two atoms identical - qc.emplaceBack(std::vector{&atom0, &atom0}, qc::PI_2); +} +TEST_F(NAComputationValidateAODConstraints, DuplicateAtomsInRz) { + qc.emplaceBack(std::vector{atom0, atom0}, qc::PI_2); EXPECT_FALSE(qc.validate().first); - qc.clear(); +} +TEST_F(NAComputationValidateAODConstraints, DuplicateAtoms) { // store unloaded atom - qc.emplaceBack(atom0); + qc.emplaceBack(*atom0); EXPECT_FALSE(qc.validate().first); - qc.clear(); - qc.emplaceBack(std::vector{&atom2, &atom1}); - // row order not preserved - qc.emplaceBack(std::vector{&atom2, &atom1}, +} +TEST_F(NAComputationValidateAODConstraints, RowPreserving4) { + qc.emplaceBack(std::vector{atom2, atom1}); + qc.emplaceBack(std::vector{atom2, atom1}, std::vector{Location{0, 1}, Location{2, 2}}); EXPECT_FALSE(qc.validate().first); - qc.clear(); - qc.emplaceBack(atom1); - qc.emplaceBack(atom1); - qc.emplaceBack(atom1); +} +TEST_F(NAComputationValidateAODConstraints, StoreStoredAtom) { + qc.emplaceBack(*atom1); + qc.emplaceBack(*atom1); + qc.emplaceBack(*atom1); EXPECT_FALSE(qc.validate().first); } From 4279aab49e459b93d6aa835d69aa56d7b012f574 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:00:46 +0100 Subject: [PATCH 31/39] =?UTF-8?q?=F0=9F=90=9B=20Fix=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ir/operations/CompoundOperation.cpp | 7 ++++--- src/ir/operations/StandardOperation.cpp | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ir/operations/CompoundOperation.cpp b/src/ir/operations/CompoundOperation.cpp index 83e959651..37cca3f6a 100644 --- a/src/ir/operations/CompoundOperation.cpp +++ b/src/ir/operations/CompoundOperation.cpp @@ -75,13 +75,14 @@ bool CompoundOperation::isCompoundOperation() const noexcept { return true; } bool CompoundOperation::isCustomGate() const noexcept { return customGate; } bool CompoundOperation::isGlobal(const size_t nQubits) const noexcept { - const auto& type = ops.at(0)->getType(); + const auto& params = ops.front()->getParameter(); + const auto& type = ops.front()->getType(); return getUsedQubits().size() == nQubits && - std::all_of(ops.cbegin(), ops.cend(), [&](const auto& operation) { + std::all_of(ops.cbegin() + 1, ops.cend(), [&](const auto& operation) { return operation->isStandardOperation() && operation->getNcontrols() == 0 && operation->getType() == type && - operation->getParameter() == parameter; + operation->getParameter() == params; }); } diff --git a/src/ir/operations/StandardOperation.cpp b/src/ir/operations/StandardOperation.cpp index 70494855f..a966015f7 100644 --- a/src/ir/operations/StandardOperation.cpp +++ b/src/ir/operations/StandardOperation.cpp @@ -240,6 +240,7 @@ StandardOperation::StandardOperation(const Controls& c, const Qubit target0, const Qubit target1, const OpType g, const std::vector& params) : StandardOperation(c, {target0, target1}, g, params) {} + bool StandardOperation::isGlobal(const size_t nQubits) const { return getUsedQubits().size() == nQubits; } From f1f05a786093e921ad3b8f6305abdd6fa7cb9e40 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:54:20 +0100 Subject: [PATCH 32/39] =?UTF-8?q?=F0=9F=9A=A8=20Update=20clang-tidy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clang-tidy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clang-tidy b/.clang-tidy index aac721e64..ac667876f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -56,6 +56,8 @@ CheckOptions: value: camelBack - key: readability-identifier-naming.MemberIgnoredRegexp value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" + - key: readability-identifier-naming.MemberSuffix + value: "_" - key: readability-identifier-naming.MethodCase value: camelBack - key: readability-identifier-naming.ParameterCase From 21030b82469ec0a7e5fe619f854dba147fbe7272 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Tue, 4 Mar 2025 20:24:22 +0100 Subject: [PATCH 33/39] =?UTF-8?q?=F0=9F=94=A7=20Handle=20empty=20quantum?= =?UTF-8?q?=20and=20classical=20registers=20in=20qiskit=20to=20MQT=20trans?= =?UTF-8?q?lation=20(#849)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This pull request adds support for handling empty quantum and classical registers during the translation process from Qiskit to MQT. This update ensures proper translation and eliminates any potential errors caused by empty registers. This has come up while working on https://github.com/cda-tum/mqt-ddsim/pull/336 ## Checklist: - [x] The pull request only contains commits that are related to it. - [x] I have added appropriate tests and documentation. - [x] I have made sure that all CI jobs on GitHub pass. - [x] The pull request introduces no new warnings and follows the project's style guidelines. Signed-off-by: burgholzer --- src/mqt/core/plugins/qiskit.py | 4 ++++ test/python/plugins/test_qiskit.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/mqt/core/plugins/qiskit.py b/src/mqt/core/plugins/qiskit.py index a23730592..75f4dbd77 100644 --- a/src/mqt/core/plugins/qiskit.py +++ b/src/mqt/core/plugins/qiskit.py @@ -50,6 +50,8 @@ def qiskit_to_mqt(circ: QuantumCircuit) -> QuantumComputation: qubit_map: dict[Qubit, int] = {} for reg in circ.qregs: size = reg.size + if size == 0: + continue if isinstance(reg, AncillaRegister): qc.add_ancillary_register(size, reg.name) else: @@ -62,6 +64,8 @@ def qiskit_to_mqt(circ: QuantumCircuit) -> QuantumComputation: clbit_map: dict[Clbit, int] = {} for reg in circ.cregs: size = reg.size + if size == 0: + continue qc.add_classical_register(size, reg.name) for bit in reg: clbit_map[bit] = clbit_index diff --git a/test/python/plugins/test_qiskit.py b/test/python/plugins/test_qiskit.py index 4e8cce2dd..1db674a5d 100644 --- a/test/python/plugins/test_qiskit.py +++ b/test/python/plugins/test_qiskit.py @@ -394,3 +394,21 @@ def test_final_layout_with_permutation_ancilla_in_front_and_back(backend: Generi # Check that output_permutation matches the result of applying the routing permutation to input_layout assert mqt_qc.output_permutation == {idx: routing_permutation[key] for idx, key in enumerate(initial_layout)} + + +def test_empty_quantum_register() -> None: + """Test an empty quantum register (valid in Qiskit) is handled correctly.""" + qr = QuantumRegister(0) + qc = QuantumCircuit(qr) + mqt_qc = qiskit_to_mqt(qc) + assert mqt_qc.num_qubits == 0 + assert mqt_qc.num_ops == 0 + + +def test_empty_classical_register() -> None: + """Test an empty classical register (valid in Qiskit) is handled correctly.""" + cr = ClassicalRegister(0) + qc = QuantumCircuit(cr) + mqt_qc = qiskit_to_mqt(qc) + assert mqt_qc.num_classical_bits == 0 + assert mqt_qc.num_ops == 0 From ed9a5a6b3b42b75f90709063cba72ed358804576 Mon Sep 17 00:00:00 2001 From: Yannick Stade <100073938+ystade@users.noreply.github.com> Date: Wed, 5 Mar 2025 16:06:54 +0100 Subject: [PATCH 34/39] =?UTF-8?q?=F0=9F=94=A7=20Fix=20clang-tidy=20again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clang-tidy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index ac667876f..1a1e7f02e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -55,9 +55,7 @@ CheckOptions: - key: readability-identifier-naming.MemberCase value: camelBack - key: readability-identifier-naming.MemberIgnoredRegexp - value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*" - - key: readability-identifier-naming.MemberSuffix - value: "_" + value: ".*ZX.*|.*SWAP.*|.*CEX.*|.*DD.*|.*EQ.*|.*_" - key: readability-identifier-naming.MethodCase value: camelBack - key: readability-identifier-naming.ParameterCase From 9689ac319748eb34ce0a695c374eb3a963a5dd2b Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Mar 2025 23:04:10 +0100 Subject: [PATCH 35/39] =?UTF-8?q?=F0=9F=94=A5=20remove=20redundant=20test?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- test/na/test_na_utils.cpp | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 test/na/test_na_utils.cpp diff --git a/test/na/test_na_utils.cpp b/test/na/test_na_utils.cpp deleted file mode 100644 index ce64f963d..000000000 --- a/test/na/test_na_utils.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#include "ir/QuantumComputation.hpp" -#include "na/NAUtils.hpp" -#include "qasm3/Importer.hpp" - -#include -#include - -namespace na { -TEST(NADefinitions, IsGlobal) { - const std::string testfile = "OPENQASM 3.0;\n" - "include \"stdgates.inc\";\n" - "qubit[3] q;\n" - "rz(pi/4) q[0];\n" - "ry(pi/2) q;\n"; - const auto qc = qasm3::Importer::imports(testfile); - EXPECT_EQ(qc.getHighestLogicalQubitIndex(), 2); - EXPECT_FALSE(isGlobal(*qc.at(0), 3)); - EXPECT_TRUE(isGlobal(*qc.at(1), 3)); -} -} // namespace na From bd59ac3be79bf5f29b8e49a291bfc89cb35a8eaa Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Mar 2025 23:05:58 +0100 Subject: [PATCH 36/39] =?UTF-8?q?=F0=9F=9A=A8=20fix=20shadowing=20compiler?= =?UTF-8?q?=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/ir/operations/CompoundOperation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ir/operations/CompoundOperation.cpp b/src/ir/operations/CompoundOperation.cpp index 37cca3f6a..75c6efac1 100644 --- a/src/ir/operations/CompoundOperation.cpp +++ b/src/ir/operations/CompoundOperation.cpp @@ -76,12 +76,11 @@ bool CompoundOperation::isCustomGate() const noexcept { return customGate; } bool CompoundOperation::isGlobal(const size_t nQubits) const noexcept { const auto& params = ops.front()->getParameter(); - const auto& type = ops.front()->getType(); + const auto& t = ops.front()->getType(); return getUsedQubits().size() == nQubits && std::all_of(ops.cbegin() + 1, ops.cend(), [&](const auto& operation) { return operation->isStandardOperation() && - operation->getNcontrols() == 0 && - operation->getType() == type && + operation->getNcontrols() == 0 && operation->getType() == t && operation->getParameter() == params; }); } From 6d7185715f3a6b7e3e43b76b03b9bca0d6fa823a Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Mar 2025 23:06:47 +0100 Subject: [PATCH 37/39] =?UTF-8?q?=F0=9F=94=A5=20remove=20redundant=20utils?= =?UTF-8?q?=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/na/NAUtils.hpp | 49 --------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 include/mqt-core/na/NAUtils.hpp diff --git a/include/mqt-core/na/NAUtils.hpp b/include/mqt-core/na/NAUtils.hpp deleted file mode 100644 index 007ec92d9..000000000 --- a/include/mqt-core/na/NAUtils.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2025 Chair for Design Automation, TUM - * All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * Licensed under the MIT License - */ - -#pragma once - -#include "ir/operations/CompoundOperation.hpp" -#include "ir/operations/Operation.hpp" - -#include -#include - -namespace na { -/** - * @brief Checks whether a gate is global. - * @details A StandardOperation is global if it acts on all qubits. - * A CompoundOperation is global if all its sub-operations are - * StandardOperations of the same type with the same parameters acting on all - * qubits. The latter is what a QASM line like `ry(π) q;` is translated to in - * MQT Core. All other operations are not global. - * @param op The operation to check. - * @param nQubits The number of qubits in the circuit. - * @return True if the operation is global, false otherwise. - */ -[[nodiscard]] inline auto isGlobal(const qc::Operation& op, - const std::size_t nQubits) -> bool { - if (op.isStandardOperation()) { - return op.getUsedQubits().size() == nQubits; - } - if (op.isCompoundOperation()) { - const auto ops = dynamic_cast(op); - const auto& params = ops.at(0)->getParameter(); - const auto& type = ops.at(0)->getType(); - return op.getUsedQubits().size() == nQubits && - std::all_of(ops.cbegin(), ops.cend(), [&](const auto& operation) { - return operation->isStandardOperation() && - operation->getNcontrols() == 0 && - operation->getType() == type && - operation->getParameter() == params; - }); - } - return false; -} -} // namespace na From 9ff5af28c01d14235445f31ee2afd261f9a3e410 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Mar 2025 23:49:27 +0100 Subject: [PATCH 38/39] =?UTF-8?q?=F0=9F=93=9D=F0=9F=8E=A8=20Enhance=20docu?= =?UTF-8?q?mentation=20for=20NAComputation=20and=20related=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- include/mqt-core/na/NAComputation.hpp | 78 ++++++++++--------- include/mqt-core/na/entities/Atom.hpp | 15 +++- include/mqt-core/na/entities/Location.hpp | 26 ++++++- include/mqt-core/na/entities/Zone.hpp | 11 ++- include/mqt-core/na/operations/GlobalCZOp.hpp | 8 +- include/mqt-core/na/operations/GlobalOp.hpp | 21 +++-- include/mqt-core/na/operations/GlobalRYOp.hpp | 8 +- include/mqt-core/na/operations/LoadOp.hpp | 21 +++-- include/mqt-core/na/operations/LocalOp.hpp | 25 +++--- include/mqt-core/na/operations/LocalRZOp.hpp | 7 +- include/mqt-core/na/operations/MoveOp.hpp | 19 +++-- include/mqt-core/na/operations/Op.hpp | 19 ++++- .../mqt-core/na/operations/ShuttlingOp.hpp | 23 +++--- include/mqt-core/na/operations/StoreOp.hpp | 21 +++-- 14 files changed, 200 insertions(+), 102 deletions(-) diff --git a/include/mqt-core/na/NAComputation.hpp b/include/mqt-core/na/NAComputation.hpp index c4d09eb08..1d2326601 100644 --- a/include/mqt-core/na/NAComputation.hpp +++ b/include/mqt-core/na/NAComputation.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing neutral atom computations. + */ + #pragma once #include "na/entities/Atom.hpp" @@ -23,72 +27,67 @@ #include namespace na { +/// Represents a neutral atom computation. class NAComputation final { protected: + /// The operations in the NA computation. std::vector> operations_; + /// The atoms used in the NA computation. std::vector> atoms_; + /// The zones used in the NA computation. std::vector> zones_; + /// The initial locations of the atoms. std::unordered_map initialLocations_; public: /// Returns an iterator to the beginning of the operations. - /// @return An iterator to the beginning of the operations. - [[nodiscard]] auto begin() -> decltype(operations_.begin()) { - return operations_.begin(); - } + [[nodiscard]] auto begin() -> auto { return operations_.begin(); } + /// Returns an iterator to the beginning of the operations. - /// @return An iterator to the beginning of the operations. - [[nodiscard]] auto begin() const -> decltype(operations_.begin()) { - return operations_.begin(); - } + [[nodiscard]] auto begin() const -> auto { return operations_.begin(); } + /// Returns an iterator to the end of the operations. - /// @return An iterator to the end of the operations. - [[nodiscard]] auto end() -> decltype(operations_.end()) { - return operations_.end(); - } + [[nodiscard]] auto end() -> auto { return operations_.end(); } + /// Returns an iterator to the end of the operations. - /// @return An iterator to the end of the operations. - [[nodiscard]] auto end() const -> decltype(operations_.end()) { - return operations_.end(); - } + [[nodiscard]] auto end() const -> auto { return operations_.end(); } + /// Returns the number of operations in the NAComputation. - /// @return The number of operations in the NAComputation. [[nodiscard]] auto size() const -> std::size_t { return operations_.size(); } + /// Returns a reference to the operation at the given index. /// @param i The index of the operation. /// @return A reference to the operation at the given index. - [[nodiscard]] auto operator[](std::size_t i) -> Op& { + [[nodiscard]] auto operator[](const std::size_t i) -> Op& { return *operations_[i]; } - /// Returns a reference to the operation at the given index. + + /// Returns a const reference to the operation at the given index. /// @param i The index of the operation. - /// @return A reference to the operation at the given index. - [[nodiscard]] auto operator[](std::size_t i) const -> const Op& { + /// @return A const reference to the operation at the given index. + [[nodiscard]] auto operator[](const std::size_t i) const -> const Op& { return *operations_[i]; } + /// Clears the operations in the NAComputation. auto clear() -> void { operations_.clear(); } + /// Returns the number of atoms used in the NAComputation. - /// @return The number of atoms used in the NAComputation. [[nodiscard]] auto getAtomsSize() const -> std::size_t { return atoms_.size(); } + /// Returns the atoms used in the NAComputation. - /// @return The atoms used in the NAComputation. - [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { - return atoms_; - } + [[nodiscard]] auto getAtoms() const -> auto& { return atoms_; } + /// Returns the zones used in global operations within the NAComputation. - /// @return The zones used in global operations within the NAComputation. - [[nodiscard]] auto getZones() const -> const decltype(zones_)& { - return zones_; - } + [[nodiscard]] auto getZones() const -> auto& { return zones_; } + /// Returns the initial locations of the atoms. - /// @return The initial locations of the atoms. - [[nodiscard]] auto getInitialLocations() const -> const - decltype(initialLocations_)& { + [[nodiscard]] auto getInitialLocations() const -> auto& { return initialLocations_; } + /// Returns the location of the given atom after the given operation. /// @param atom The atom to get the location for. /// @param op The operation to get the location after. @@ -96,6 +95,7 @@ class NAComputation final { [[nodiscard]] auto getLocationOfAtomAfterOperation(const Atom& atom, const Op& op) const -> Location; + /// Emplaces a new atom with the given name and returns a reference to the /// newly created atom. /// @param name The name of the atom. @@ -103,6 +103,7 @@ class NAComputation final { auto emplaceBackAtom(std::string name) -> const Atom& { return *atoms_.emplace_back(std::make_unique(std::move(name))); } + /// Emplaces a new zone with the given name and returns a reference to the /// newly created zone. /// @param name The name of the zone. @@ -110,6 +111,7 @@ class NAComputation final { auto emplaceBackZone(std::string name) -> const Zone& { return *zones_.emplace_back(std::make_unique(std::move(name))); } + /// Emplaces a new initial location for the given atom with the given location /// and returns a reference to the newly created location. /// @param atom The atom to set the initial location for. @@ -119,6 +121,7 @@ class NAComputation final { -> const Location& { return initialLocations_.emplace(&atom, loc).first->second; } + /// Emplaces a new initial location for the given atom with the given /// arguments and returns a reference to the newly created location. /// @param atom The atom to set the initial location for. @@ -132,6 +135,7 @@ class NAComputation final { Location{static_cast(std::forward(loc))...}) .first->second; } + /// Emplaces a new operation of type T with the given operation and returns a /// reference to the newly created operation. /// @tparam T The concrete type of the operation. @@ -140,6 +144,7 @@ class NAComputation final { template auto emplaceBack(T&& op) -> const Op& { return *operations_.emplace_back(std::make_unique(std::forward(op))); } + /// Emplaces a new operation of type T with the given arguments and returns a /// reference to the newly created operation. /// @tparam T The concrete type of the operation. @@ -150,8 +155,8 @@ class NAComputation final { return *operations_.emplace_back( std::make_unique(std::forward(args)...)); } + /// Returns a string representation of the NAComputation. - /// @return A string representation of the NAComputation. [[nodiscard]] auto toString() const -> std::string; /// Outputs the NAComputation to the given output stream, i.e., the string /// returned by toString(). @@ -162,14 +167,15 @@ class NAComputation final { -> std::ostream& { return os << qc.toString(); } + /// Validates the NAComputation and checks whether all AOD constraints are /// fulfilled. - /// I.e., + /// Specifically, /// - each atom is loaded before it is moved /// - the relative order of loaded atoms is preserved /// - each atom is loaded before it is stored /// - each atom is stored before it is loaded (again) - /// @returns a pair of a boolean indicating whether the NAComputation is valid + /// @returns a pair of a Boolean indicating whether the NAComputation is valid /// and a string containing the error message if the NAComputation is invalid. [[nodiscard]] auto validate() const -> std::pair; }; diff --git a/include/mqt-core/na/entities/Atom.hpp b/include/mqt-core/na/entities/Atom.hpp index 16c860cd9..4ff19a7e7 100644 --- a/include/mqt-core/na/entities/Atom.hpp +++ b/include/mqt-core/na/entities/Atom.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a type for representing individual atoms. + */ + #pragma once #include @@ -14,20 +18,21 @@ #include namespace na { -/// Represents an atom in the NA computation. +/// Represents an atom in the NAComputation. /// @details The name of the atom is used for printing the NAComputation. -/// To maintain the uniqueness of atoms, the name of the atom should be unique -/// for this atom. +/// To maintain the uniqueness of atoms, the name of the atom should be unique. class Atom final { + /// The identifier of the atom. std::string name_; public: /// Creates a new atom with the given name. /// @param name The name of the atom. explicit Atom(std::string name) : name_(std::move(name)) {} + /// Returns the name of the atom. - /// @return The name of the atom. [[nodiscard]] auto getName() const -> std::string { return name_; } + /// Prints the atom to the given output stream. /// @param os The output stream to print the atom to. /// @param obj The atom to print. @@ -35,6 +40,7 @@ class Atom final { friend auto operator<<(std::ostream& os, const Atom& obj) -> std::ostream& { return os << obj.getName(); } + /// Compares two atoms for equality. /// @param other The atom to compare with. /// @return True if the atoms are equal, false otherwise. @@ -44,6 +50,7 @@ class Atom final { } return name_ == other.name_; } + /// Compares two atoms for inequality. /// @param other The atom to compare with. /// @return True if the atoms are not equal, false otherwise. diff --git a/include/mqt-core/na/entities/Location.hpp b/include/mqt-core/na/entities/Location.hpp index c306f09ba..3708eeace 100644 --- a/include/mqt-core/na/entities/Location.hpp +++ b/include/mqt-core/na/entities/Location.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a type for representing two-dimensional locations. + */ + #pragma once #include "Definitions.hpp" @@ -23,31 +27,36 @@ namespace na { /// Class to store two-dimensional coordinates of type double. struct Location final { + /// The x-coordinate of the location. double x = 0; + /// The y-coordinate of the location. double y = 0; + /// Subtracts the coordinates of the given location from this location. /// @param loc The location to subtract. /// @return The location resulting from the subtraction. Location operator-(const Location& loc) const { return {x - loc.x, y - loc.y}; } + /// Adds the coordinates of the given location to this location. /// @param loc The location to add. /// @return The location resulting from the addition. Location operator+(const Location& loc) const { return {x + loc.x, y + loc.y}; } - /// Computes the length of the vector from the origin to this location. - /// @return The length of the vector. + + /// Returns the length of the vector from the origin to this location. [[nodiscard]] auto length() const -> double { return std::hypot(x, y); } - /// Returns a string representation of the location. - /// @return The string representation of the location in the format "(x, y)". + + /// Returns a string representation of the location in the format "(x, y)". [[nodiscard]] auto toString() const -> std::string { std::stringstream ss; ss << std::setprecision(3) << std::fixed; ss << "(" << x << ", " << y << ")"; return ss.str(); } + /// Prints the location to the given output stream. /// @param os The output stream to print the location to. /// @param obj The location to print. @@ -56,42 +65,49 @@ struct Location final { -> std::ostream& { return os << obj.toString(); } + /// Compares two locations for equality. /// @param other The location to compare with. /// @return True if the locations are equal, false otherwise. [[nodiscard]] auto operator==(const Location& other) const -> bool { return x == other.x && y == other.y; } + /// Compares two locations for inequality. /// @param other The location to compare with. /// @return True if the locations are not equal, false otherwise. [[nodiscard]] auto operator!=(const Location& other) const -> bool { return !(*this == other); } + /// Compares two locations for less than. /// @param other The location to compare with. /// @return True if this location is less than the other location, false [[nodiscard]] auto operator<(const Location& other) const -> bool { return x < other.x || (x == other.x && y < other.y); } + /// Compares two locations for greater than. /// @param other The location to compare with. /// @return True if this location is greater than the other location, false [[nodiscard]] auto operator>(const Location& other) const -> bool { return other < *this; } + /// Compares two locations for greater than or equal. /// @param other The location to compare with. /// @return True if this location is greater than or equal to the other [[nodiscard]] auto operator>=(const Location& other) const -> bool { return !(other < *this); } + /// Compares two locations for less than or equal. /// @param other The location to compare with. /// @return True if this location is less than or equal to the other location, [[nodiscard]] auto operator<=(const Location& other) const -> bool { return *this >= other; } + /// Computes the Euclidean distance between this location and the given /// location. /// @param loc The location to compute the distance to. @@ -99,6 +115,7 @@ struct Location final { [[nodiscard]] auto getEuclideanDistance(const Location& loc) const -> double { return (*this - loc).length(); } + /// Computes the horizontal distance between this location and the given /// location. /// @param loc The location to compute the distance to. @@ -107,6 +124,7 @@ struct Location final { -> double { return std::abs(x - loc.x); } + /// Computes the vertical distance between this location and the given /// location. /// @param loc The location to compute the distance to. diff --git a/include/mqt-core/na/entities/Zone.hpp b/include/mqt-core/na/entities/Zone.hpp index 22d5df478..5b6f4ea2c 100644 --- a/include/mqt-core/na/entities/Zone.hpp +++ b/include/mqt-core/na/entities/Zone.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a type for representing zones in NA architectures. + */ + #pragma once #include @@ -14,19 +18,22 @@ #include namespace na { -/// Represents a zone in the NA computation. +/// Represents a zone in the NAComputation. /// @details The name of the zone is used for printing the NAComputation. /// To maintain the uniqueness of zones, the name of the zone should be unique /// for this zone. class Zone final { + /// The identifier of the zone. std::string name_; public: /// Creates a new zone with the given name. /// @param name The name of the zone. explicit Zone(std::string name) : name_(std::move(name)) {} + /// Returns the name of the zone. [[nodiscard]] auto getName() const -> std::string { return name_; } + /// Prints the zone to the given output stream. /// @param os The output stream to print the zone to. /// @param obj The zone to print. @@ -34,6 +41,7 @@ class Zone final { friend auto operator<<(std::ostream& os, const Zone& obj) -> std::ostream& { return os << obj.getName(); } + /// Compares two zones for equality. /// @param other The zone to compare with. /// @return True if the zones are equal, false otherwise. @@ -43,6 +51,7 @@ class Zone final { } return name_ == other.name_; } + /// Compares two zones for inequality. /// @param other The zone to compare with. /// @return True if the zones are not equal, false otherwise. diff --git a/include/mqt-core/na/operations/GlobalCZOp.hpp b/include/mqt-core/na/operations/GlobalCZOp.hpp index 8e8cf1467..fac05ba34 100644 --- a/include/mqt-core/na/operations/GlobalCZOp.hpp +++ b/include/mqt-core/na/operations/GlobalCZOp.hpp @@ -7,16 +7,20 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing global CZ operations. + */ + #pragma once #include "na/entities/Zone.hpp" #include "na/operations/GlobalOp.hpp" namespace na { -/// Represents a global cz operation in the NA computation. +/// Represents a global CZ operation in the NAComputation. class GlobalCZOp final : public GlobalOp { public: - /// Creates a new cz operation in the given zone. + /// Creates a new CZ operation in the given zone. /// @param zone The zone the operation is applied to. explicit GlobalCZOp(const Zone& zone) : GlobalOp(zone, {}) { name_ = "cz"; } }; diff --git a/include/mqt-core/na/operations/GlobalOp.hpp b/include/mqt-core/na/operations/GlobalOp.hpp index 0ab79b647..ba1709a8a 100644 --- a/include/mqt-core/na/operations/GlobalOp.hpp +++ b/include/mqt-core/na/operations/GlobalOp.hpp @@ -7,6 +7,11 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing global operations in the + * NAComputation. + */ + #pragma once #include "Definitions.hpp" @@ -18,14 +23,18 @@ #include namespace na { -/// Represents a global operation in the NA computation. +/// Represents a global operation in the NAComputation. /// @details Global operations are applied to entire zones instead of to /// individual atoms. class GlobalOp : public Op { protected: + /// The name of the operation. std::string name_; + /// The parameters of the operation. std::vector params_; + /// The zone the operation is applied to. const Zone* zone_; + /// Creates a new global operation in the given zone with the given /// parameters. /// @param zone The zone the operation is applied to. @@ -35,16 +44,14 @@ class GlobalOp : public Op { public: GlobalOp() = delete; + /// Returns the parameters of the operation. - /// @return The parameters of the operation. - [[nodiscard]] auto getParams() const -> const decltype(params_)& { - return params_; - } + [[nodiscard]] auto getParams() const -> auto& { return params_; } + /// Returns the zone the operation is applied to. - /// @return The zone the operation is applied to. [[nodiscard]] auto getZone() const -> const Zone& { return *zone_; } + /// Returns a string representation of the operation. - /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/GlobalRYOp.hpp b/include/mqt-core/na/operations/GlobalRYOp.hpp index 1b8b1b42d..79c32a195 100644 --- a/include/mqt-core/na/operations/GlobalRYOp.hpp +++ b/include/mqt-core/na/operations/GlobalRYOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing global RY operations. + */ + #pragma once #include "Definitions.hpp" @@ -14,10 +18,10 @@ #include "na/operations/GlobalOp.hpp" namespace na { -/// Represents a global ry operation in the NA computation. +/// Represents a global RY operation in the NAComputation. class GlobalRYOp final : public GlobalOp { public: - /// Creates a new ry operation in the given zone with the given angle. + /// Creates a new RY operation in the given zone with the given angle. /// @param zone The zone the operation is applied to. /// @param angle The angle of the operation. GlobalRYOp(const Zone& zone, qc::fp angle) : GlobalOp(zone, {angle}) { diff --git a/include/mqt-core/na/operations/LoadOp.hpp b/include/mqt-core/na/operations/LoadOp.hpp index 3661c67fb..198f0d819 100644 --- a/include/mqt-core/na/operations/LoadOp.hpp +++ b/include/mqt-core/na/operations/LoadOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing load operations. + */ + #pragma once #include "na/entities/Atom.hpp" @@ -20,11 +24,12 @@ #include namespace na { -/// Represents a load operation in the NA computation. +/// Represents a load operation in the NAComputation. /// @details Before an atom can be moved, it must be loaded, i.e., transferred /// from a static SLM to an adjustable AOD trap. class LoadOp final : public ShuttlingOp { protected: + /// The target locations to load the atoms to. std::optional> targetLocations_ = std::nullopt; public: @@ -36,17 +41,19 @@ class LoadOp final : public ShuttlingOp { LoadOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations_(std::move(targetLocations)) { - if (this->atoms_.size() != this->targetLocations_->size()) { + if (atoms_.size() != targetLocations_->size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new load operation with the given atoms. /// @details This constructor is used if the target locations are not set, /// i.e., the load operation does not incorporate any offset. /// @param atoms The atoms to load. explicit LoadOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + /// Creates a new load operation with the given atom and target location. /// @details The target locations can be set if the loading operation contains /// a certain offset. @@ -54,19 +61,19 @@ class LoadOp final : public ShuttlingOp { /// @param targetLocation The target location to load the atom to. LoadOp(const Atom& atom, const Location& targetLocation) : LoadOp({&atom}, {targetLocation}) {} + /// Creates a new load operation with the given atom. /// @details This constructor is used if the target locations are not set, /// i.e., the load operation does not incorporate any offset. /// @param atom The atom to load. explicit LoadOp(const Atom& atom) : LoadOp({&atom}) {} - /// Returns true if the load operation has target locations set. - /// @return True if the load operation has target locations set, false - /// otherwise. + + /// Returns whether the load operation has target locations set. [[nodiscard]] auto hasTargetLocations() const -> bool override { return targetLocations_.has_value(); } + /// Returns the target locations of the load operation. - /// @return The target locations of the load operation. [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { if (!targetLocations_.has_value()) { @@ -74,8 +81,8 @@ class LoadOp final : public ShuttlingOp { } return *targetLocations_; } + /// Returns a string representation of the load operation. - /// @return A string representation of the load operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalOp.hpp b/include/mqt-core/na/operations/LocalOp.hpp index 5d718e70e..2055bf0ec 100644 --- a/include/mqt-core/na/operations/LocalOp.hpp +++ b/include/mqt-core/na/operations/LocalOp.hpp @@ -7,6 +7,11 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing local operations in the + * NAComputation. + */ + #pragma once #include "Definitions.hpp" @@ -18,13 +23,17 @@ #include namespace na { -/// Represents a local operation in the NA computation. +/// Represents a local operation in the NAComputation. /// @details A local operation is applied to individual atoms. class LocalOp : public Op { protected: + /// The name of the operation. std::string name_; + /// The parameters of the operation. std::vector params_; + /// The atoms the operation is applied to. std::vector atoms_; + /// Creates a new local operation with the given atoms and parameters. /// @param atoms The atoms the operation is applied to. /// @param params The parameters of the operation. @@ -33,18 +42,14 @@ class LocalOp : public Op { public: LocalOp() = delete; + /// Returns the atoms the operation is applied to. - /// @return The atoms the operation is applied to. - [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { - return atoms_; - } + [[nodiscard]] auto getAtoms() const -> auto& { return atoms_; } + /// Returns the parameters of the operation. - /// @return The parameters of the operation. - [[nodiscard]] auto getParams() const -> const decltype(params_)& { - return params_; - } + [[nodiscard]] auto getParams() const -> auto& { return params_; } + /// Returns a string representation of the operation. - /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/LocalRZOp.hpp b/include/mqt-core/na/operations/LocalRZOp.hpp index 27251910f..26da2449d 100644 --- a/include/mqt-core/na/operations/LocalRZOp.hpp +++ b/include/mqt-core/na/operations/LocalRZOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing local RZ operations. + */ + #pragma once #include "Definitions.hpp" @@ -18,7 +22,7 @@ #include namespace na { -/// Represents a local RZ operation in the NA computation. +/// Represents a local RZ operation in the NAComputation. class LocalRZOp final : public LocalOp { public: /// Creates a new RZ operation with the given atoms and angle. @@ -28,6 +32,7 @@ class LocalRZOp final : public LocalOp { : LocalOp(std::move(atom), {angle}) { name_ = "rz"; } + /// Creates a new RZ operation with the given atom and angle. /// @param atom The atom the operation is applied to. /// @param angle The angle of the operation. diff --git a/include/mqt-core/na/operations/MoveOp.hpp b/include/mqt-core/na/operations/MoveOp.hpp index c7b612d8b..32cf76133 100644 --- a/include/mqt-core/na/operations/MoveOp.hpp +++ b/include/mqt-core/na/operations/MoveOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing move operations. + */ + #pragma once #include "na/entities/Atom.hpp" @@ -19,9 +23,10 @@ #include namespace na { -/// Represents a move operation in the NA computation. +/// Represents a move operation in the NAComputation. class MoveOp final : public ShuttlingOp { protected: + /// The target locations to move the atoms to. std::vector targetLocations_; public: @@ -31,30 +36,30 @@ class MoveOp final : public ShuttlingOp { MoveOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations_(std::move(targetLocations)) { - if (this->atoms_.size() != this->targetLocations_.size()) { + if (atoms_.size() != targetLocations_.size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new move operation with the given atom and target location. /// @param atom The atom to move. /// @param targetLocation The target location to move the atom to. MoveOp(const Atom& atom, const Location& targetLocation) : MoveOp({&atom}, {targetLocation}) {} - /// Returns true if the move operation has target locations set. - /// @return True if the move operation has target locations set, false - /// otherwise. + + /// Returns whether the move operation has target locations set. [[nodiscard]] auto hasTargetLocations() const -> bool override { return true; } + /// Returns the target locations of the move operation. - /// @return The target locations of the move operation. [[nodiscard]] auto getTargetLocations() const -> const decltype(targetLocations_)& override { return targetLocations_; } + /// Returns a string representation of the operation. - /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na diff --git a/include/mqt-core/na/operations/Op.hpp b/include/mqt-core/na/operations/Op.hpp index 6acd14ac5..833481b41 100644 --- a/include/mqt-core/na/operations/Op.hpp +++ b/include/mqt-core/na/operations/Op.hpp @@ -7,20 +7,28 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines the base class for all operations in the NAComputation. + */ + #pragma once #include #include namespace na { -/// This is the base class for all operations in the NA computation. +/// This is the base class for all operations in the NAComputation. class Op { public: + /// Default constructor. Op() = default; + + /// Virtual destructor. virtual ~Op() = default; + /// Returns a string representation of the operation. - /// @return A string representation of the operation. [[nodiscard]] virtual auto toString() const -> std::string = 0; + /// Prints the operation to the given output stream. /// @param os The output stream to print the operation to. /// @param obj The operation to print. @@ -28,21 +36,24 @@ class Op { friend auto operator<<(std::ostream& os, const Op& obj) -> std::ostream& { return os << obj.toString(); // Using toString() method } + /// Checks if the operation is of the given type. /// @tparam T The type to check for. /// @return True if the operation is of the given type, false otherwise. template [[nodiscard]] auto is() const -> bool { return dynamic_cast(this) != nullptr; } + /// Casts the operation to the given type. /// @tparam T The type to cast to. - /// @return The operation as the given type. + /// @return A reference to the operation as the given type. template [[nodiscard]] auto as() -> T& { return dynamic_cast(*this); } + /// Casts the operation to the given type. /// @tparam T The type to cast to. - /// @return The operation as the given type. + /// @return A const reference to the operation as the given type. template [[nodiscard]] auto as() const -> const T& { return dynamic_cast(*this); } diff --git a/include/mqt-core/na/operations/ShuttlingOp.hpp b/include/mqt-core/na/operations/ShuttlingOp.hpp index 6d26821b2..2c84635b8 100644 --- a/include/mqt-core/na/operations/ShuttlingOp.hpp +++ b/include/mqt-core/na/operations/ShuttlingOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a base class for representing shuttling operations. + */ + #pragma once #include "na/entities/Atom.hpp" @@ -17,12 +21,14 @@ #include namespace na { -/// Represents a shuttling operation in the NA computation. -/// @details A shuttling operation is the super class for all shuttling related +/// Represents a shuttling operation in the NAComputation. +/// @details A shuttling operation is the super class for all shuttling-related /// operations, i.e., load, store, and move operations. class ShuttlingOp : public Op { protected: + /// The atoms the operation is applied to. std::vector atoms_; + /// Creates a new shuttling operation with the given atoms. /// @param atoms The atoms the operation is applied to. explicit ShuttlingOp(std::vector atoms) @@ -30,17 +36,14 @@ class ShuttlingOp : public Op { public: ShuttlingOp() = delete; + /// Returns the atoms the operation is applied to. - /// @return The atoms the operation is applied to. - [[nodiscard]] auto getAtoms() const -> const decltype(atoms_)& { - return atoms_; - } - /// Returns true if the shuttling operation has target locations set. - /// @return True if the shuttling operation has target locations set, false - /// otherwise. + [[nodiscard]] auto getAtoms() const -> auto& { return atoms_; } + + /// Returns whether the shuttling operation has target locations set. [[nodiscard]] virtual auto hasTargetLocations() const -> bool = 0; + /// Returns the target locations of the shuttling operation. - /// @return The target locations of the shuttling operation. [[nodiscard]] virtual auto getTargetLocations() const -> const std::vector& = 0; }; diff --git a/include/mqt-core/na/operations/StoreOp.hpp b/include/mqt-core/na/operations/StoreOp.hpp index 44b3270a1..0ff2fc228 100644 --- a/include/mqt-core/na/operations/StoreOp.hpp +++ b/include/mqt-core/na/operations/StoreOp.hpp @@ -7,6 +7,10 @@ * Licensed under the MIT License */ +/** @file + * @brief Defines a class for representing store operations. + */ + #pragma once #include "na/entities/Atom.hpp" @@ -20,9 +24,10 @@ #include namespace na { -/// Represents a store operation in the NA computation. +/// Represents a store operation in the NAComputation. class StoreOp final : public ShuttlingOp { protected: + /// The target locations to store the atoms to. std::optional> targetLocations_ = std::nullopt; public: @@ -34,17 +39,19 @@ class StoreOp final : public ShuttlingOp { StoreOp(std::vector atoms, std::vector targetLocations) : ShuttlingOp(std::move(atoms)), targetLocations_(std::move(targetLocations)) { - if (this->atoms_.size() != this->targetLocations_->size()) { + if (atoms_.size() != targetLocations_->size()) { throw std::invalid_argument( "Number of atoms and target locations must be equal."); } } + /// Creates a new store operation with the given atoms and target locations. /// @details Here, the target locations are not used, i.e., this store does /// not contain any offset. /// @param atoms The atoms to store. explicit StoreOp(std::vector atoms) : ShuttlingOp(std::move(atoms)) {} + /// Creates a new store operation with the given atom and target location. /// @details The target location can be used if the store operation /// incorporates some offset. @@ -52,19 +59,19 @@ class StoreOp final : public ShuttlingOp { /// @param targetLocation The target location to store the atom to. StoreOp(const Atom& atom, const Location& targetLocation) : StoreOp({&atom}, {targetLocation}) {} + /// Creates a new store operation with the given atom and target locations. /// @details Here, the target locations are not used, i.e., this store does /// not contain any offset. /// @param atom The atom to store. explicit StoreOp(const Atom& atom) : StoreOp({&atom}) {} - /// Returns true if the store operation has target locations set. - /// @return True if the store operation has target locations set, false - /// otherwise. + + /// Returns whether the store operation has target locations set. [[nodiscard]] auto hasTargetLocations() const -> bool override { return targetLocations_.has_value(); } + /// Returns the target locations of the store operation. - /// @return The target locations of the store operation. [[nodiscard]] auto getTargetLocations() const -> const std::vector& override { if (!targetLocations_.has_value()) { @@ -72,8 +79,8 @@ class StoreOp final : public ShuttlingOp { } return *targetLocations_; } + /// Returns a string representation of the operation. - /// @return A string representation of the operation. [[nodiscard]] auto toString() const -> std::string override; }; } // namespace na From 493a50998a2e7b6cc59e4dcc2df152d2561cc3a3 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Thu, 6 Mar 2025 23:57:31 +0100 Subject: [PATCH 39/39] =?UTF-8?q?=F0=9F=8E=A8=20small=20refinements=20in?= =?UTF-8?q?=20the=20NA=20computation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/na/NAComputation.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/na/NAComputation.cpp b/src/na/NAComputation.cpp index f01cb1873..be249d6ec 100644 --- a/src/na/NAComputation.cpp +++ b/src/na/NAComputation.cpp @@ -34,7 +34,7 @@ auto NAComputation::getLocationOfAtomAfterOperation(const Atom& atom, const Op& op) const -> Location { auto currentLocation = initialLocations_.at(&atom); - for (const auto& opUniquePtr : *this) { + for (const auto& opUniquePtr : operations_) { if (opUniquePtr->is()) { const auto& moveOp = opUniquePtr->as(); const auto& opAtoms = moveOp.getAtoms(); @@ -55,13 +55,13 @@ auto NAComputation::getLocationOfAtomAfterOperation(const Atom& atom, auto NAComputation::toString() const -> std::string { std::stringstream ss; std::map initialLocationsAsc; - for (const auto& location : initialLocations_) { - initialLocationsAsc.emplace(location.second, location.first); + for (const auto& [atom, loc] : initialLocations_) { + initialLocationsAsc.emplace(loc, atom); } for (const auto& [loc, atom] : initialLocationsAsc) { ss << "atom " << loc << " " << *atom << "\n"; } - for (const auto& op : *this) { + for (const auto& op : operations_) { ss << *op << "\n"; } return ss.str(); @@ -86,7 +86,7 @@ auto NAComputation::validate() const -> std::pair { // This set is used to keep track of the atoms that are currently shuttling, // i.e., they are loaded but not yet stored again. std::unordered_set currentlyShuttling{}; - for (const auto& op : *this) { + for (const auto& op : operations_) { ++counter; if (op->is()) { //===----------------------------------------------------------------===// @@ -125,9 +125,7 @@ auto NAComputation::validate() const -> std::pair { //===----------------------------------------------------------------===// // All Shuttling Operations that move atoms //===----------------------------------------------------------------===// - if ((op->is() && op->as().hasTargetLocations()) || - (op->is() && op->as().hasTargetLocations()) || - op->is()) { + if (shuttlingOp.hasTargetLocations()) { const auto& targetLocations = shuttlingOp.getTargetLocations(); for (std::size_t i = 0; i < opAtoms.size(); ++i) { const auto* a = opAtoms[i];