Skip to content

Commit

Permalink
💚 Work on ci warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
ystade committed Mar 3, 2025
1 parent fe38f0f commit 0bf5318
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 12 deletions.
7 changes: 7 additions & 0 deletions include/mqt-core/na/NAComputation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class NAComputation final : protected std::vector<std::unique_ptr<Op>> {
-> 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
1 change: 0 additions & 1 deletion include/mqt-core/na/entities/Location.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#pragma once

#include <cmath>
#include <cstddef>
#include <cstdint>
#include <iomanip>
#include <ios>
Expand Down
33 changes: 31 additions & 2 deletions src/na/NAComputation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const Atom*, Location> 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<const Atom*> currentlyShuttling{};
for (const auto& op : *this) {
++counter;
if (op->is<ShuttlingOp>()) {
//===----------------------------------------------------------------===//
// Shuttling Operations
//===----------------------------------------------------------------===//
const auto& shuttlingOp = op->as<ShuttlingOp>();
const auto& opAtoms = shuttlingOp.getAtoms();
if (shuttlingOp.is<LoadOp>()) {
//===-----------------------------------------------------------------//
// Load Operations
//-----------------------------------------------------------------===//
if (std::any_of(opAtoms.begin(), opAtoms.end(),
[&currentlyShuttling](const auto* atom) {
return currentlyShuttling.find(atom) !=
Expand All @@ -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(),
[&currentlyShuttling](const auto* atom) {
return currentlyShuttling.find(atom) ==
Expand All @@ -102,8 +121,12 @@ auto NAComputation::validate() const -> bool {
return false;
}
}
//===----------------------------------------------------------------===//
// All Shuttling Operations that move atoms
//===----------------------------------------------------------------===//
if ((op->is<LoadOp>() && op->as<LoadOp>().hasTargetLocations()) ||
(op->is<StoreOp>() && op->as<StoreOp>().hasTargetLocations())) {
(op->is<StoreOp>() && op->as<StoreOp>().hasTargetLocations()) ||
op->is<MoveOp>()) {
const auto& targetLocations = shuttlingOp.getTargetLocations();
for (std::size_t i = 0; i < opAtoms.size(); ++i) {
const auto* a = opAtoms[i];
Expand Down Expand Up @@ -160,11 +183,17 @@ auto NAComputation::validate() const -> bool {
}
}
if (shuttlingOp.is<StoreOp>()) {
//===-----------------------------------------------------------------//
// Store Operations
//-----------------------------------------------------------------===//
std::for_each(opAtoms.begin(), opAtoms.end(), [&](const auto* atom) {
currentlyShuttling.erase(atom);
});
}
} else if (op->is<LocalOp>()) {
//===----------------------------------------------------------------===//
// Local Operations
//===----------------------------------------------------------------===//
const auto& opAtoms = op->as<LocalOp>().getAtoms();
for (std::size_t i = 0; i < opAtoms.size(); ++i) {
const auto* a = opAtoms[i];
Expand Down
41 changes: 32 additions & 9 deletions test/na/test_nacomputation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,47 +90,70 @@ TEST(NAComputation, ValidateAODConstraints) {
EXPECT_FALSE(qc.validate());
qc.clear();
// two atoms identical
qc.emplaceBack<LoadOp>(std::vector{atom0, atom0},
qc.emplaceBack<LoadOp>(std::vector{atom0, atom0});
qc.emplaceBack<MoveOp>(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>(std::vector{atom0, atom1},
qc.emplaceBack<LoadOp>(std::vector{atom0, atom1});
qc.emplaceBack<MoveOp>(std::vector{atom0, atom1},
std::vector{Location{0, 1}, Location{0, 1}});
EXPECT_FALSE(qc.validate());
qc.clear();
// columns not preserved
qc.emplaceBack<LoadOp>(std::vector{atom1, atom3},
qc.emplaceBack<LoadOp>(std::vector{atom1, atom3});
qc.emplaceBack<MoveOp>(std::vector{atom1, atom3},
std::vector{Location{0, 1}, Location{2, 2}});
EXPECT_FALSE(qc.validate());
qc.clear();
// rows not preserved
qc.emplaceBack<LoadOp>(std::vector{atom0, atom1},
qc.emplaceBack<LoadOp>(std::vector{atom0, atom1});
qc.emplaceBack<MoveOp>(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>(std::vector{atom0, atom3},
qc.emplaceBack<LoadOp>(std::vector{atom0, atom3});
qc.emplaceBack<MoveOp>(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>(std::vector{atom0, atom3},
qc.emplaceBack<LoadOp>(std::vector{atom0, atom3});
qc.emplaceBack<MoveOp>(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>(std::vector{atom2, atom1},
std::vector{Location{1, 3}, Location{0, 1}});
qc.emplaceBack<LoadOp>(std::vector{atom2, atom1});
qc.emplaceBack<MoveOp>(std::vector{atom1, atom2},
std::vector{Location{0, 1}, Location{1, 3}});
EXPECT_FALSE(qc.validate());
qc.clear();
// row order not preserved
qc.emplaceBack<LoadOp>(std::vector{atom2, atom1},
qc.emplaceBack<LoadOp>(std::vector{atom2, atom1});
qc.emplaceBack<MoveOp>(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, std::vector{atom0, atom0});
EXPECT_FALSE(qc.validate());
qc.clear();
// store unloaded atom
qc.emplaceBack<StoreOp>(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<LoadOp>(std::vector{atom0});
qc.emplaceBack<MoveOp>(std::vector{atom0}, std::vector{Location{1, 1}});
qc.emplaceBack<StoreOp>(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

0 comments on commit 0bf5318

Please sign in to comment.