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

🐛 ensure typeinfo and vtable information is present for CompoundOperation #548

Merged
merged 3 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
177 changes: 27 additions & 150 deletions include/mqt-core/operations/CompoundOperation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,160 +2,60 @@

#include "Operation.hpp"

#include <algorithm>

namespace qc {

class CompoundOperation final : public Operation {
private:
std::vector<std::unique_ptr<Operation>> ops{};

public:
explicit CompoundOperation(const std::size_t nq) {
name = "Compound operation:";
nqubits = nq;
type = Compound;
}

explicit CompoundOperation(
const std::size_t nq,
std::vector<std::unique_ptr<Operation>>&& operations)
: CompoundOperation(nq) {
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
ops = std::move(operations);
}
explicit CompoundOperation(std::size_t nq);

CompoundOperation(const CompoundOperation& co)
: Operation(co), ops(co.ops.size()) {
for (std::size_t i = 0; i < co.ops.size(); ++i) {
ops[i] = co.ops[i]->clone();
}
}
CompoundOperation(std::size_t nq,
std::vector<std::unique_ptr<Operation>>&& operations);

CompoundOperation& operator=(const CompoundOperation& co) {
if (this != &co) {
Operation::operator=(co);
ops.resize(co.ops.size());
for (std::size_t i = 0; i < co.ops.size(); ++i) {
ops[i] = co.ops[i]->clone();
}
}
return *this;
}
CompoundOperation(const CompoundOperation& co);

[[nodiscard]] std::unique_ptr<Operation> clone() const override {
return std::make_unique<CompoundOperation>(*this);
}
CompoundOperation& operator=(const CompoundOperation& co);

void setNqubits(const std::size_t nq) override {
nqubits = nq;
for (auto& op : ops) {
op->setNqubits(nq);
}
}
[[nodiscard]] std::unique_ptr<Operation> clone() const override;

[[nodiscard]] bool isCompoundOperation() const override { return true; }
void setNqubits(std::size_t nq) override;

[[nodiscard]] bool isNonUnitaryOperation() const override {
return std::any_of(ops.cbegin(), ops.cend(), [](const auto& op) {
return op->isNonUnitaryOperation();
});
}
[[nodiscard]] bool isCompoundOperation() const override;

[[nodiscard]] inline bool isSymbolicOperation() const override {
return std::any_of(ops.begin(), ops.end(), [](const auto& op) {
return op->isSymbolicOperation();
});
}
[[nodiscard]] bool isNonUnitaryOperation() const override;

void addControl(const Control c) override {
controls.insert(c);
// we can just add the controls to each operation, as the operations will
// check if they already act on the control qubits.
for (auto& op : ops) {
op->addControl(c);
}
}
[[nodiscard]] inline bool isSymbolicOperation() const override;

void clearControls() override {
// we remove just our controls from nested operations
removeControls(controls);
}
void addControl(Control c) override;

void removeControl(const Control c) override {
// first we iterate over our controls and check if we are actually allowed
// to remove them
if (controls.erase(c) == 0) {
throw QFRException("Cannot remove control from compound operation as it "
"is not a control.");
}

for (auto& op : ops) {
op->removeControl(c);
}
}
void clearControls() override;

Controls::iterator removeControl(const Controls::iterator it) override {
for (auto& op : ops) {
op->removeControl(*it);
}
void removeControl(Control c) override;

return controls.erase(it);
}
Controls::iterator removeControl(Controls::iterator it) override;

[[nodiscard]] bool equals(const Operation& op, const Permutation& perm1,
const Permutation& perm2) const override {
if (const auto* comp = dynamic_cast<const CompoundOperation*>(&op)) {
if (comp->ops.size() != ops.size()) {
return false;
}

auto it = comp->ops.cbegin();
for (const auto& operation : ops) {
if (!operation->equals(**it, perm1, perm2)) {
return false;
}
++it;
}
return true;
}
return false;
}
[[nodiscard]] bool equals(const Operation& operation) const override {
return equals(operation, {}, {});
}
const Permutation& perm2) const override;
[[nodiscard]] bool equals(const Operation& operation) const override;

std::ostream& print(std::ostream& os, const Permutation& permutation,
const std::size_t prefixWidth) const override {
const auto prefix = std::string(prefixWidth - 1, ' ');
os << std::string(4 * nqubits, '-') << "\n";
for (const auto& op : ops) {
os << prefix << ":";
op->print(os, permutation, prefixWidth);
os << "\n";
}
os << prefix << std::string(4 * nqubits + 1, '-');
return os;
}
std::size_t prefixWidth) const override;

[[nodiscard]] bool actsOn(const Qubit i) const override {
return std::any_of(ops.cbegin(), ops.cend(),
[&i](const auto& op) { return op->actsOn(i); });
}
[[nodiscard]] bool actsOn(Qubit i) const override;

void addDepthContribution(std::vector<std::size_t>& depths) const override {
for (const auto& op : ops) {
op->addDepthContribution(depths);
}
}
void addDepthContribution(std::vector<std::size_t>& depths) const override;

void dumpOpenQASM(std::ostream& of, const RegisterNames& qreg,
const RegisterNames& creg, size_t indent,
bool openQASM3) const override {
for (const auto& op : ops) {
op->dumpOpenQASM(of, qreg, creg, indent, openQASM3);
}
}
bool openQASM3) const override;

std::vector<std::unique_ptr<Operation>>& getOps() { return ops; }

[[nodiscard]] std::set<Qubit> getUsedQubits() const override;

void invert() override;

/**
* Pass-Through
Expand Down Expand Up @@ -230,34 +130,11 @@ class CompoundOperation final : public Operation {
}

[[nodiscard]] const auto& at(std::size_t i) const { return ops.at(i); }

std::vector<std::unique_ptr<Operation>>& getOps() { return ops; }

[[nodiscard]] std::set<Qubit> getUsedQubits() const override {
std::set<Qubit> usedQubits{};
for (const auto& op : ops) {
usedQubits.merge(op->getUsedQubits());
}
return usedQubits;
}

void invert() override {
for (auto& op : ops) {
op->invert();
}
std::reverse(ops.begin(), ops.end());
}
};
} // namespace qc

namespace std {
template <> struct hash<qc::CompoundOperation> {
std::size_t operator()(const qc::CompoundOperation& co) const noexcept {
std::size_t seed = 0U;
for (const auto& op : co) {
qc::hashCombine(seed, std::hash<qc::Operation>{}(*op));
}
return seed;
}
std::size_t operator()(const qc::CompoundOperation& co) const noexcept;
};
} // namespace std
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ if(NOT TARGET ${MQT_CORE_TARGET_NAME})
algorithms/WState.cpp
CircuitOptimizer.cpp
operations/ClassicControlledOperation.cpp
operations/CompoundOperation.cpp
operations/Expression.cpp
operations/NonUnitaryOperation.cpp
operations/Operation.cpp
Expand Down
Loading
Loading