Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎨 Refactor NAComputation with concrete base classes for every operation and ouput new .naviz format #846

Merged
merged 40 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c570770
♻️ Refactor NACOmputation, output new format
ystade Feb 8, 2025
3404c85
🧪 Work on tests
ystade Feb 8, 2025
a8758e7
🐛 Use unique pointers to avoid invalidated pointers
ystade Feb 8, 2025
5d28e53
🎨 Add hash for pair replacing FullOpType
ystade Feb 8, 2025
2975642
🐛 Fix bug in validate function
ystade Feb 8, 2025
1ab3262
🎨 Improve validation
ystade Feb 10, 2025
45514c8
🎨 Improve inteface of NAComputation
ystade Feb 10, 2025
35f8683
🎨 Pre-commit fixes
ystade Feb 10, 2025
c7b542d
🎨 Change function name
ystade Feb 10, 2025
bb59ce8
🎨 Implement clone function
ystade Feb 10, 2025
6bb958f
🎨 Add getter for initial locations
ystade Feb 10, 2025
9e8bf8c
🎨 Good stuff from try to make it copyable
ystade Feb 11, 2025
fce9539
🎨 Add getZones
ystade Feb 11, 2025
3b65ad3
🔥 Remove clone()
ystade Feb 11, 2025
ad6bb26
🎨 Remove superfluous link targets
ystade Feb 11, 2025
71a5fd1
🎨 Offer more constructors for locations
ystade Feb 11, 2025
dbcf43f
🐛 Fix creation of Location
ystade Feb 12, 2025
cd8ad9c
✅ Cover GlobalCZOp with tests
ystade Mar 3, 2025
779abd6
🐛 Add missing header
ystade Mar 3, 2025
db68ced
🐛 Link against missing target
ystade Mar 3, 2025
efe341d
🎨 Add missing header
ystade Mar 3, 2025
7caeb30
🎨 Add missing header
ystade Mar 3, 2025
fe38f0f
🩹 Fix header includes
ystade Mar 3, 2025
0bf5318
💚 Work on ci warnings
ystade Mar 3, 2025
878c01a
📝 Add more comments
ystade Mar 3, 2025
d1efe8f
💚 Work on CI warnings
ystade Mar 3, 2025
6552eb1
🎨 WIP incorporate feedback
ystade Mar 5, 2025
21f311e
📝 Add mostly docs
ystade Mar 5, 2025
a8aa02a
🐛 Fix all open construction sites
ystade Mar 5, 2025
4edea4a
🎨 Move isGLobal to qc::Operation
ystade Mar 5, 2025
4279aab
🐛 Fix test
ystade Mar 5, 2025
f1f05a7
🚨 Update clang-tidy
ystade Mar 5, 2025
21030b8
🔧 Handle empty quantum and classical registers in qiskit to MQT trans…
burgholzer Mar 4, 2025
ed9a5a6
🔧 Fix clang-tidy again
ystade Mar 5, 2025
3f3aea5
Merge branch 'refs/heads/main' into refactor-na-computation
burgholzer Mar 6, 2025
9689ac3
🔥 remove redundant test file
burgholzer Mar 6, 2025
bd59ac3
🚨 fix shadowing compiler warning
burgholzer Mar 6, 2025
6d71857
🔥 remove redundant utils file
burgholzer Mar 6, 2025
9ff5af2
📝🎨 Enhance documentation for NAComputation and related classes
burgholzer Mar 6, 2025
493a509
🎨 small refinements in the NA computation
burgholzer Mar 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 70 additions & 62 deletions include/mqt-core/na/NAComputation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,94 +9,102 @@

#pragma once

#include "NADefinitions.hpp"
#include "operations/NAOperation.hpp"
#include "na/entities/Atom.hpp"
#include "na/entities/Location.hpp"
#include "na/entities/Zone.hpp"
#include "na/operations/Op.hpp"

#include <algorithm>
#include <cstddef>
#include <iterator>
#include <memory>
#include <ostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

namespace na {
class NAComputation {
class NAComputation final : protected std::vector<std::unique_ptr<Op>> {
protected:
std::vector<std::shared_ptr<Point>> initialPositions;
std::vector<std::unique_ptr<NAOperation>> operations;
std::vector<std::unique_ptr<Atom>> atoms;
std::vector<std::unique_ptr<Zone>> zones;
std::unordered_map<const Atom*, Location> initialLocations;

public:
using std::vector<std::unique_ptr<Op>>::begin;
using std::vector<std::unique_ptr<Op>>::clear;
using std::vector<std::unique_ptr<Op>>::end;
using std::vector<std::unique_ptr<Op>>::size;
using std::vector<std::unique_ptr<Op>>::operator[];
NAComputation() = default;
NAComputation(NAComputation&& qc) noexcept = 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(); });
[[nodiscard]] auto getAtomsSize() const -> std::size_t {
return atoms.size();
}
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;
[[nodiscard]] auto getAtoms() const -> const decltype(atoms)& {
return atoms;
}
virtual ~NAComputation() = default;
template <class T> auto emplaceBack(std::unique_ptr<T>&& op) -> void {
static_assert(std::is_base_of_v<NAOperation, T>,
"T must be a subclass of NAOperation.");
operations.emplace_back(std::move(op));
[[nodiscard]] auto getZones() const -> const decltype(zones)& {
return zones;
}
template <class T> auto emplaceBack(const std::unique_ptr<T>& op) -> void {
static_assert(std::is_base_of_v<NAOperation, T>,
"T must be a subclass of NAOperation.");
operations.emplace_back(std::move(op));
[[nodiscard]] auto getInitialLocations() const -> const
decltype(initialLocations)& {
return initialLocations;
}
template <class T, class... Args> auto emplaceBack(Args&&... args) -> void {
static_assert(std::is_base_of_v<NAOperation, T>,
"T must be a subclass of NAOperation.");
operations.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
[[nodiscard]] auto
getLocationOfAtomAfterOperation(const std::unique_ptr<Atom>& atom,
const std::unique_ptr<Op>& op) const
-> Location {
return getLocationOfAtomAfterOperation(atom.get(), op.get());
}
auto clear(const bool clearInitialPositions = true) -> void {
operations.clear();
if (clearInitialPositions) {
initialPositions.clear();
}
[[nodiscard]] auto
getLocationOfAtomAfterOperation(const std::unique_ptr<Atom>& atom,
const Op* op) const -> Location {
return getLocationOfAtomAfterOperation(atom.get(), op);
}
[[nodiscard]] auto size() const -> std::size_t { return operations.size(); }
[[nodiscard]] auto getInitialPositions() const
-> const std::vector<std::shared_ptr<Point>>& {
return initialPositions;
[[nodiscard]] auto getLocationOfAtomAfterOperation(
const Atom* atom, const std::unique_ptr<Op>& op) const -> Location {
return getLocationOfAtomAfterOperation(atom, op.get());
}
auto emplaceInitialPosition(std::shared_ptr<Point> p) -> void {
initialPositions.emplace_back(std::move(p));
[[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<Atom>(std::move(name))).get();
}
auto emplaceBackZone(std::string name) -> const Zone* {
return zones.emplace_back(std::make_unique<Zone>(std::move(name))).get();
}
auto emplaceInitialLocation(const Atom* atom, const Location& loc) -> void {
initialLocations.emplace(atom, loc);
}
template <typename... Args>
auto emplaceInitialLocation(const Atom* atom, Args&&... loc) -> void {
initialLocations.emplace(atom, Location{std::forward<Args>(loc)...});
}
template <class T> auto emplaceBack(T&& op) -> const Op* {
return std::vector<std::unique_ptr<Op>>::emplace_back(
std::make_unique<T>(std::forward<T>(op)))
.get();
}
template <class T, typename... Args>
auto emplaceBack(Args&&... args) -> const Op* {
return std::vector<std::unique_ptr<Op>>::emplace_back(
std::make_unique<T>(std::forward<Args>(args)...))
.get();
}
[[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;
/// 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
143 changes: 0 additions & 143 deletions include/mqt-core/na/NADefinitions.hpp

This file was deleted.

68 changes: 68 additions & 0 deletions include/mqt-core/na/NAUtils.hpp
Original file line number Diff line number Diff line change
@@ -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 "Definitions.hpp"
#include "ir/operations/CompoundOperation.hpp"
#include "ir/operations/OpType.hpp"
#include "ir/operations/Operation.hpp"

#include <algorithm>
#include <cstddef>
#include <functional>
#include <utility>

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<const qc::CompoundOperation&>(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

template <> struct std::hash<std::pair<qc::OpType, std::size_t>> {
std::size_t
operator()(const std::pair<qc::OpType, std::size_t>& t) const noexcept {
const std::size_t h1 = std::hash<qc::OpType>{}(t.first);
const std::size_t h2 = std::hash<std::size_t>{}(t.second);
return qc::combineHash(h1, h2);
}
};

template <> struct std::hash<std::pair<std::size_t, std::size_t>> {
std::size_t
operator()(const std::pair<std::size_t, std::size_t>& p) const noexcept {
const std::size_t h1 = std::hash<std::size_t>{}(p.first);
const std::size_t h2 = std::hash<std::size_t>{}(p.second);
return qc::combineHash(h1, h2);
}
};
Loading
Loading