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

✨ Support for Neutral Atom Mapper #596

Merged
merged 85 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
f7f9116
:sparkles: Add GlobalOperation as subclass of CompoundOperation
ystade Jan 29, 2024
9d2cb17
:sparkles: Add ShuttelingOperation class
ystade Jan 29, 2024
7633b7c
:recycle: Move code in subdir
ystade Feb 6, 2024
a299ead
🎨 Improve CMake structure for na
ystade Feb 12, 2024
381f6a7
🐛 Fix undefined symbols in GlobalOperation
ystade Feb 12, 2024
857fe71
🎨 Improve the validity check in the global operation
ystade Feb 13, 2024
eec54a2
⏪️ Remove unnecessary code
ystade Mar 7, 2024
76d39a0
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Mar 8, 2024
a4e104e
🐛 Add empty file to fix cmake process
ystade Mar 8, 2024
55e1c07
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Mar 13, 2024
0711cf8
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Apr 17, 2024
b7cf3e4
♻️ Incorporate NADefinitions in core infrastructure
ystade Apr 18, 2024
c38f4a2
♻️ Rename tests
ystade Apr 18, 2024
7315bd1
♻️ Incorporate NA operations into MQT-core
ystade Apr 18, 2024
5c03216
♻️ Incorporate graph in MQT-core
ystade Apr 18, 2024
8b775f4
♻️ Incoporate Layer into MQT core
ystade Apr 19, 2024
92f548c
♻️ Add DisjointSet, Fix CMakeLists
ystade Apr 19, 2024
577d862
🐛 Include source files in subdir
ystade Apr 22, 2024
a7967b0
🐛 Fix no archive memeber bug for target mqt-core-test-na
ystade Apr 22, 2024
d5bf73f
♻️ Remove the Pre-/suffix Test from tests
ystade Apr 22, 2024
ee9c105
♻️ Add disjoint set to MQT core
ystade Apr 22, 2024
29c6c5c
✨ Add Directed and Directed Acyclic Graph
ystade Apr 23, 2024
dfda6ce
✨ Add new functionality to undirected graph
ystade Apr 23, 2024
e254d78
🎨 Adopt graph structures
ystade Apr 23, 2024
3e513d8
♻️ Resolve some CLion warnings
ystade Apr 23, 2024
7c4556a
✏️ Fix bug in undirected graph
ystade Apr 23, 2024
9efe89b
🐛 Fix bug with degrees when adding existing edge again
ystade Apr 23, 2024
6c91138
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 23, 2024
7772321
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Apr 23, 2024
cb05f4a
🎨 Satisfy spellchekcer
ystade Apr 24, 2024
2d838e3
🎨Revert removal of as superfluous shown header files
ystade Apr 24, 2024
25c81ad
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 24, 2024
4653ac3
🎨 Satisfy linter
ystade Apr 24, 2024
b9c6673
🎨 Try to satisfy windows build
ystade Apr 24, 2024
5b8a893
✅ Add test for interaction graph from layer
ystade Apr 24, 2024
8d5bc9a
🎨 Convert long condition into smaler ones
ystade Apr 24, 2024
d08ee3f
✅ Cover more lines of OpType with tests
ystade Apr 24, 2024
a5a1324
✅ Increse test coverage
ystade Apr 24, 2024
d14a79c
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 24, 2024
c444348
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Apr 24, 2024
6a73aed
🙈 Exclude code coverage files
ystade Apr 24, 2024
823df8e
✅ Increase test coverage
ystade Apr 24, 2024
56368f0
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 24, 2024
e047a7a
🐛 Fix QL complaints
ystade Apr 25, 2024
08d2a4e
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 25, 2024
1509541
🎨 Satisfy QL complaints
ystade Apr 25, 2024
4ac47a2
🐛 Fix overflow in Layer
ystade Apr 26, 2024
216ab05
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 26, 2024
3bf560f
Apply first suggestions from code review
ystade Apr 26, 2024
1896d09
Apply next suggestions from code review
ystade Apr 26, 2024
fedd656
Apply further suggestions from code review
ystade Apr 26, 2024
2ffda97
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 26, 2024
d0d6ea5
Update test/test_layer.cpp
ystade Apr 26, 2024
5b594f9
Update src/Layer.cpp
ystade Apr 26, 2024
018e55d
🎨 Improve readability
ystade Apr 26, 2024
80401bc
🎨 Remove file headers
ystade Apr 26, 2024
fa54af3
🎨 Replace mandatory nullptr in Undirected Graph with optional
ystade Apr 26, 2024
b1cade4
🎨 Incoporate Feedback
ystade Apr 26, 2024
5d908b0
🎨 Incorporate Feedback
ystade Apr 26, 2024
7129ba0
🎨 Adopt to suggested changes
ystade Apr 26, 2024
a91f92f
🎨 Rename OpType to FullOpType and use na namepsace in tests
ystade Apr 26, 2024
924f752
🎨 Add cpp files for header in na subdir
ystade Apr 26, 2024
4fd3109
🎨 Introduce == operator
ystade Apr 26, 2024
4d1e519
✅ Fix test
ystade Apr 26, 2024
aa82900
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 26, 2024
5f61bf2
🐛 Remove shared_ptr in Layer
ystade Apr 26, 2024
8628acd
🐛 Fix inverseOf
ystade Apr 29, 2024
71e1c6a
🎨 Remove indirection and fix
ystade Apr 29, 2024
c0ef7bb
🎨 Make isInverseOf more general using the invert functionality
ystade Apr 29, 2024
9340e28
🐛 Fix isInverseOf for CompoundOperations and adopt tests (exclude fal…
ystade Apr 29, 2024
98091ee
🐛 Fix commutesAt
ystade Apr 29, 2024
1264f5d
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 29, 2024
0b8e88c
✏️ Fix spell-error
ystade Apr 29, 2024
e14ee8b
🎨 Add member functions to FullOpType
ystade Apr 29, 2024
a6c8c0f
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade Apr 30, 2024
fd2525b
🎨 pre-commit fixes
pre-commit-ci[bot] Apr 30, 2024
11a7089
Apply suggestions from code review
burgholzer Apr 30, 2024
df425d3
Update include/mqt-core/na/NADefinitions.hpp
burgholzer Apr 30, 2024
6322bb9
Update src/datastructures/Layer.cpp
ystade Apr 30, 2024
0f2d7be
🚨 fix a couple of compiler and newer clang-tidy warnings
burgholzer Apr 30, 2024
ac0900f
🚨 some more clang-tidy fixes
burgholzer May 1, 2024
74e8bae
🎨 Add flag to clear method
ystade May 4, 2024
74c31e8
🎨 pre-commit fixes
pre-commit-ci[bot] May 4, 2024
7e64073
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade May 6, 2024
ee52b77
Merge remote-tracking branch 'origin/main' into wip-na-qmap
ystade May 9, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ coverage.xml
.hypothesis/
.pytest_cache/
cover/
*.profraw

# Translations
*.mo
Expand Down
3 changes: 0 additions & 3 deletions include/mqt-core/CircuitOptimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
#include <unordered_set>

namespace qc {
static constexpr std::array<qc::OpType, 10> DIAGONAL_GATES = {
qc::Barrier, qc::I, qc::Z, qc::S, qc::Sdg,
qc::T, qc::Tdg, qc::P, qc::RZ, qc::RZZ};

class CircuitOptimizer {
protected:
Expand Down
7 changes: 7 additions & 0 deletions include/mqt-core/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ constexpr void hashCombine(std::size_t& hash, const std::size_t with) noexcept {
hash = combineHash(hash, with);
}

/// Pairs do not provide a hash function by default, this is the replacement
template <class T, class U> struct PairHash {
size_t operator()(const std::pair<T, U>& x) const {
return combineHash(std::hash<T>{}(x.first), std::hash<U>{}(x.second));
}
};

/**
* @brief Function used to mark unreachable code
* @details Uses compiler specific extensions if possible. Even if no extension
Expand Down
107 changes: 107 additions & 0 deletions include/mqt-core/datastructures/DirectedAcyclicGraph.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#pragma once

#include "Definitions.hpp"
#include "DirectedGraph.hpp"

#include <algorithm>
#include <cassert>
#include <iostream>
#include <sstream>
#include <stack>
#include <stdexcept>

namespace qc {

template <class V> class DirectedAcyclicGraph final : public DirectedGraph<V> {
protected:
// transitive closure matrix to detect cycles
std::vector<std::vector<bool>> closureMatrix;

public:
auto addVertex(const V& v) -> void override {
DirectedGraph<V>::addVertex(v);
for (auto& row : closureMatrix) {
row.emplace_back(false);
}
closureMatrix.emplace_back(this->nVertices, false);
const auto i = this->mapping.at(v);
closureMatrix[i][i] = true;
}
auto addEdge(const V& u, const V& v) -> void override {
if (this->mapping.find(u) == this->mapping.end()) {
addVertex(u);
}
if (this->mapping.find(v) == this->mapping.end()) {
addVertex(v);
}
std::size_t const i = this->mapping.at(u);
std::size_t const j = this->mapping.at(v);
if (closureMatrix[j][i]) {
std::ostringstream oss;
oss << "Adding edge (" << u << ", " << v << ") would create a cycle.";
throw std::logic_error(oss.str());
}
DirectedGraph<V>::addEdge(u, v);
for (std::size_t k = 0; k < this->nVertices; ++k) {
if (closureMatrix[k][i]) {
closureMatrix[k][j] = true;
}
if (closureMatrix[j][k]) {
closureMatrix[i][k] = true;
}
}
}
[[nodiscard]] auto isReachable(const V& u, const V& v) const -> bool {
if (this->mapping.find(u) == this->mapping.end()) {
throw std::invalid_argument("Vertex u not in graph.");
}
if (this->mapping.find(v) == this->mapping.end()) {
throw std::invalid_argument("Vertex v not in graph.");
}
return closureMatrix[this->mapping.at(u)][this->mapping.at(v)];
}
/// Perform a depth-first search on the graph and return the nodes in a
/// topological order
[[nodiscard]] auto orderTopologically() const -> std::vector<V> {
std::stack<std::size_t> stack{};
std::vector<std::size_t> result;
result.reserve(this->nVertices);
std::vector visited(this->nVertices, false);
// visitedInDegree is used to count the incoming edges that have been
// visited already such that the resulting order of the nodes is one that
// satisfies a topological ordering
std::vector<std::size_t> visitedInDegree(this->nVertices, 0);
// Push nodes with 0 indegree onto the stack
for (std::size_t k = 0; k < this->nVertices; ++k) {
if (this->inDegrees[k] == 0) {
stack.push(k);
visited[k] = true;
}
}
// Perform DFS
while (!stack.empty()) {
const auto u = stack.top();
stack.pop();
result.emplace_back(u);

for (std::size_t k = 0; k < this->nVertices; ++k) {
if (this->adjacencyMatrix[u][k]) {
if (!visited[k]) {
if (++visitedInDegree[k] == this->inDegrees[k]) {
stack.push(k);
visited[k] = true;
}
}
}
}
}
// Otherwise graph has a cycle
assert(result.size() == this->nVertices);
std::vector<V> vertices;
vertices.reserve(this->nVertices);
std::transform(result.cbegin(), result.cend(), std::back_inserter(vertices),
[&](const auto i) { return this->invMapping.at(i); });
return vertices;
}
};
} // namespace qc
138 changes: 138 additions & 0 deletions include/mqt-core/datastructures/DirectedGraph.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#pragma once

#include "Definitions.hpp"

#include <numeric>
#include <sstream>
#include <unordered_set>

namespace qc {

/**
* Class representing generic directed graphs.
*
* @tparam V the type of the vertices in the graph. Must implement `operator<<`.
*/
template <class V> class DirectedGraph {
static_assert(
std::is_same<decltype(std::declval<std::ostream&>() << std::declval<V>()),
std::ostream&>::value,
"V must support `operator<<`.");

protected:
// the adjecency matrix works with indices
std::vector<std::vector<bool>> adjacencyMatrix;
// the mapping of vertices to indices in the graph are stored in a map
std::unordered_map<V, std::size_t> mapping;
// the inverse mapping is used to get the vertex from the index
std::vector<V> invMapping;
// the number of vertices in the graph
std::size_t nVertices = 0;
// the number of edges in the graph
std::size_t nEdges = 0;
// the in-degrees of the vertices in the graph
std::vector<std::size_t> inDegrees;
// the out-degrees of the vertices in the graph
std::vector<std::size_t> outDegrees;

public:
virtual ~DirectedGraph() = default;
virtual auto addVertex(const V& v) -> void {
// check whether the vertex is already in the graph, if so do nothing
if (mapping.find(v) != mapping.end()) {
std::stringstream ss;
ss << "The vertex " << v << " is already in the graph.";
throw std::invalid_argument(ss.str());
}
mapping[v] = nVertices;
invMapping.emplace_back(v);
++nVertices;
for (auto& row : adjacencyMatrix) {
row.emplace_back(false);
}
adjacencyMatrix.emplace_back(nVertices, false);
inDegrees.emplace_back(0);
outDegrees.emplace_back(0);
}
virtual auto addEdge(const V& u, const V& v) -> void {
if (mapping.find(u) == mapping.end()) {
addVertex(u);
}
if (mapping.find(v) == mapping.end()) {
addVertex(v);
}
const auto i = mapping.at(u);
const auto j = mapping.at(v);
if (!adjacencyMatrix[i][j]) {
adjacencyMatrix[i][j] = true;
++outDegrees[i];
++inDegrees[j];
++nEdges;
}
}
[[nodiscard]] auto getNVertices() const -> std::size_t { return nVertices; }
[[nodiscard]] auto getNEdges() const -> std::size_t { return nEdges; }
[[nodiscard]] auto getInDegree(const V& v) const -> std::size_t {
if (mapping.find(v) == mapping.end()) {
std::stringstream ss;
ss << "The vertex " << v << " is not in the graph.";
throw std::invalid_argument(ss.str());
}
const auto i = mapping.at(v);
return inDegrees[i];
}
[[nodiscard]] auto getOutDegree(const V& v) const -> std::size_t {
if (mapping.find(v) == mapping.end()) {
std::stringstream ss;
ss << "The vertex " << v << " is not in the graph.";
throw std::invalid_argument(ss.str());
}
const auto i = mapping.at(v);
return outDegrees[i];
}
[[nodiscard]] auto getVertices() const -> std::unordered_set<V> {
return std::accumulate(mapping.cbegin(), mapping.cend(),
std::unordered_set<V>(),
[](auto& acc, const auto& v) {
acc.emplace(v.first);
return acc;
});
}
[[nodiscard]] auto isEdge(const V& u, const V& v) const -> bool {
if (mapping.find(u) == mapping.end()) {
std::stringstream ss;
ss << "The vertex " << u << " is not in the graph.";
throw std::invalid_argument(ss.str());
}
if (mapping.find(v) == mapping.end()) {
std::stringstream ss;
ss << "The vertex " << v << " is not in the graph.";
throw std::invalid_argument(ss.str());
}
const auto i = mapping.at(u);
const auto j = mapping.at(v);
return adjacencyMatrix[i][j];
}
/// Outputs a string representation of the graph in the DOT format
[[nodiscard]] auto toString() const -> std::string {
std::stringstream ss;
ss << "digraph {\n";
for (const auto& [v, i] : mapping) {
ss << " " << i << " [label=\"" << v << "\"];\n";
}
for (std::size_t i = 0; i < nVertices; ++i) {
for (std::size_t j = 0; j < nVertices; ++j) {
if (adjacencyMatrix[i][j]) {
ss << " " << i << " -> " << j << ";\n";
}
}
}
ss << "}\n";
return ss.str();
}
friend auto operator<<(std::ostream& os,
const DirectedGraph& g) -> std::ostream& {
return os << g.toString(); // Using toString() method
}
};
} // namespace qc
39 changes: 39 additions & 0 deletions include/mqt-core/datastructures/DisjointSet.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include <algorithm>
#include <unordered_map>

namespace qc {
template <class T> struct DisjointSet {
std::unordered_map<T, T> parent;
std::unordered_map<T, std::size_t> rank;

template <class Iterator>
explicit DisjointSet(const Iterator& begin, const Iterator& end) {
std::for_each(begin, end, [&](const auto& element) {
parent[element] = element;
rank[element] = 0;
});
}

T findSet(const T& v) {
if (parent[v] != v) {
parent[v] = findSet(parent[v]);
}
return parent[v];
}

void unionSet(const T& x, const T& y) {
const auto& xSet = findSet(x);
const auto& ySet = findSet(y);
if (rank[xSet] > rank[ySet]) {
parent[ySet] = xSet;
} else {
parent[xSet] = ySet;
if (rank[xSet] == rank[ySet]) {
++rank[ySet];
}
}
}
};
} // namespace qc
Loading
Loading