From 5d8795ed145566ca1ba0de88c29e684576907498 Mon Sep 17 00:00:00 2001 From: Tom Peham Date: Thu, 9 Nov 2023 18:23:47 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=BD=20Update=20to=20latest=20`mqt-core?= =?UTF-8?q?`=20version=20(#390)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR adjusts QMAP to the latest interface changes in `mqt-core`. In a follow-up PR, the newly introduced `mqt.core` Python package that include Python bindings for the `QuantumComputation` class will be introduced. ## 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 Co-authored-by: burgholzer --- .clang-tidy | 2 + extern/mqt-core | 2 +- include/Mapper.hpp | 25 ++--- .../cliffordsynthesis/CliffordSynthesizer.hpp | 4 +- .../encoding/GateEncoder.hpp | 6 +- include/heuristic/HeuristicMapper.hpp | 4 +- include/utils.hpp | 1 + src/Mapper.cpp | 27 ++--- src/cliffordsynthesis/Tableau.cpp | 7 +- .../encoding/GateEncoder.cpp | 6 +- .../encoding/SingleGateEncoder.cpp | 2 +- .../encoding/TableauEncoder.cpp | 6 +- src/exact/ExactMapper.cpp | 76 ++++++------- src/heuristic/HeuristicMapper.cpp | 100 +++++++++--------- test/cliffordsynthesis/test_synthesis.cpp | 8 +- test/test_architecture.cpp | 14 +-- test/test_encodings.cpp | 12 +-- test/test_exact.cpp | 24 ++--- test/test_heuristic.cpp | 12 +-- test/test_tableau.cpp | 14 +-- 20 files changed, 178 insertions(+), 174 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 8f00f5036..74fa2bcad 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -6,8 +6,10 @@ Checks: | boost-*, bugprone-*, -bugprone-easily-swappable-parameters, + -bugprone-unchecked-optional-access, clang-analyzer-*, cppcoreguidelines-*, + -cppcoreguidelines-avoid-do-while, -cppcoreguidelines-non-private-member-variables-in-classes, -cppcoreguidelines-special-member-functions, -cppcoreguidelines-avoid-magic-numbers, diff --git a/extern/mqt-core b/extern/mqt-core index cb348652d..d9ed9b7c9 160000 --- a/extern/mqt-core +++ b/extern/mqt-core @@ -1 +1 @@ -Subproject commit cb348652d170978e5688959016ea15aa1157945b +Subproject commit d9ed9b7c967a63f6f853c6be456bef3a4dccd761 diff --git a/include/Mapper.hpp b/include/Mapper.hpp index 107f30dc1..e12b44bda 100644 --- a/include/Mapper.hpp +++ b/include/Mapper.hpp @@ -51,7 +51,7 @@ class Mapper { /** * @brief The quantum architecture on which to map the circuit */ - Architecture& architecture; + Architecture* architecture; /** * @brief The resulting quantum circuit after mapping @@ -183,8 +183,7 @@ class Mapper { virtual void postMappingOptimizations(const Configuration& config); public: - Mapper(const qc::QuantumComputation& quantumComputation, - Architecture& architecture); + Mapper(qc::QuantumComputation quantumComputation, Architecture& architecture); virtual ~Mapper() = default; /** @@ -239,7 +238,7 @@ class Mapper { virtual std::string csv() { return results.csv(); } std::ostream& printLayering(std::ostream& out) { - out << "---------------- Layering -------------------" << std::endl; + out << "---------------- Layering -------------------\n"; for (auto& layer : layers) { for (auto& gate : layer) { if (gate.singleQubit()) { @@ -248,33 +247,31 @@ class Mapper { out << "(" << gate.control << " " << gate.target << ") "; } } - out << std::endl; + out << "\n"; } - out << "---------------------------------------------" << std::endl; + out << "---------------------------------------------\n"; return out; } std::ostream& printLocations(std::ostream& out) { - out << "---------------- Locations -------------------" << std::endl; + out << "---------------- Locations -------------------\n"; for (std::size_t i = 0; i < qc.getNqubits(); ++i) { out << locations.at(i) << " "; } - out << std::endl; - out << "---------------------------------------------" << std::endl; + out << "\n---------------------------------------------\n"; return out; } std::ostream& printQubits(std::ostream& out) { - out << "---------------- Qubits -------------------" << std::endl; - for (std::size_t i = 0; i < architecture.getNqubits(); ++i) { + out << "---------------- Qubits -------------------\n"; + for (std::size_t i = 0; i < architecture->getNqubits(); ++i) { out << qubits.at(i) << " "; } - out << std::endl; - out << "---------------------------------------------" << std::endl; + out << "\n---------------------------------------------\n"; return out; } virtual void reset() { - architecture.reset(); + architecture->reset(); qc.reset(); layers.clear(); qubits.fill(DEFAULT_POSITION); diff --git a/include/cliffordsynthesis/CliffordSynthesizer.hpp b/include/cliffordsynthesis/CliffordSynthesizer.hpp index faa03d8f1..ecdd4ec30 100644 --- a/include/cliffordsynthesis/CliffordSynthesizer.hpp +++ b/include/cliffordsynthesis/CliffordSynthesizer.hpp @@ -31,14 +31,14 @@ class CliffordSynthesizer { : initialTableau(std::move(initial)), targetTableau(qc, 0, std::numeric_limits::max(), initialTableau.hasDestabilizers()), - initialCircuit(std::make_shared(qc.clone())), + initialCircuit(std::make_shared(qc)), results(qc, targetTableau) {} explicit CliffordSynthesizer(qc::QuantumComputation& qc, const bool useDestabilizers = false) : initialTableau(qc.getNqubits(), useDestabilizers), targetTableau(qc, 0, std::numeric_limits::max(), useDestabilizers), - initialCircuit(std::make_shared(qc.clone())), + initialCircuit(std::make_shared(qc)), results(qc, targetTableau) {} virtual ~CliffordSynthesizer() = default; diff --git a/include/cliffordsynthesis/encoding/GateEncoder.hpp b/include/cliffordsynthesis/encoding/GateEncoder.hpp index ac5f62348..d22b4182e 100644 --- a/include/cliffordsynthesis/encoding/GateEncoder.hpp +++ b/include/cliffordsynthesis/encoding/GateEncoder.hpp @@ -57,8 +57,8 @@ class GateEncoder { [[nodiscard]] auto* getVariables() { return &vars; } static constexpr std::array SINGLE_QUBIT_GATES = { - qc::OpType::None, qc::OpType::X, qc::OpType::Y, qc::OpType::Z, - qc::OpType::H, qc::OpType::S, qc::OpType::Sdag}; + qc::OpType::None, qc::OpType::X, qc::OpType::Y, qc::OpType::Z, + qc::OpType::H, qc::OpType::S, qc::OpType::Sdg}; [[nodiscard]] static constexpr std::size_t gateToIndex(const qc::OpType type) { @@ -97,7 +97,7 @@ class GateEncoder { return containsGate(); } [[nodiscard]] static constexpr bool containsSdag() { - return containsGate(); + return containsGate(); } protected: diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 35e0f6f28..fca765314 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -178,7 +178,7 @@ class HeuristicMapper : public Mapper { */ double distanceOnArchitectureOfLogicalQubits(std::uint16_t control, std::uint16_t target) { - return architecture.distance( + return architecture->distance( static_cast(locations.at(control)), static_cast(locations.at(target))); } @@ -189,7 +189,7 @@ class HeuristicMapper : public Mapper { */ double distanceOnArchitectureOfPhysicalQubits(std::uint16_t control, std::uint16_t target) { - return architecture.distance(control, target); + return architecture->distance(control, target); } /** diff --git a/include/utils.hpp b/include/utils.hpp index bcdf4796c..4cd31d2dc 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Mapper.cpp b/src/Mapper.cpp index 37495b53e..bc41e22ad 100644 --- a/src/Mapper.cpp +++ b/src/Mapper.cpp @@ -7,20 +7,21 @@ #include "CircuitOptimizer.hpp" +#include + void Mapper::initResults() { countGates(qc, results.input); results.input.name = qc.getName(); results.input.qubits = static_cast(qc.getNqubits()); - results.architecture = architecture.getName(); + results.architecture = architecture->getName(); results.output.name = qc.getName() + "_mapped"; - results.output.qubits = architecture.getNqubits(); + results.output.qubits = architecture->getNqubits(); results.output.gates = std::numeric_limits::max(); - qcMapped.addQubitRegister(architecture.getNqubits()); + qcMapped.addQubitRegister(architecture->getNqubits()); } -Mapper::Mapper(const qc::QuantumComputation& quantumComputation, - Architecture& arch) - : qc(quantumComputation.clone()), architecture(arch) { +Mapper::Mapper(qc::QuantumComputation quantumComputation, Architecture& arch) + : qc(std::move(quantumComputation)), architecture(&arch) { qubits.fill(DEFAULT_POSITION); locations.fill(DEFAULT_POSITION); fidelities.fill(INITIAL_FIDELITY); @@ -201,16 +202,16 @@ std::size_t Mapper::getNextLayer(std::size_t idx) { void Mapper::finalizeMappedCircuit() { // add additional qubits if the architecture contains more qubits than the // circuit - if (architecture.getNqubits() > qcMapped.getNqubits()) { + if (architecture->getNqubits() > qcMapped.getNqubits()) { for (auto logicalQubit = qcMapped.getNqubits(); - logicalQubit < architecture.getNqubits(); ++logicalQubit) { + logicalQubit < architecture->getNqubits(); ++logicalQubit) { std::optional physicalQubit = std::nullopt; // check if the corresponding physical qubit is already in use if (qcMapped.initialLayout.find(static_cast(logicalQubit)) != qcMapped.initialLayout.end()) { // get the next unused physical qubit - for (physicalQubit = 0; *physicalQubit < architecture.getNqubits(); + for (physicalQubit = 0; *physicalQubit < architecture->getNqubits(); ++(*physicalQubit)) { if (qcMapped.initialLayout.find(*physicalQubit) == qcMapped.initialLayout.end()) { @@ -238,8 +239,8 @@ void Mapper::finalizeMappedCircuit() { } void Mapper::placeRemainingArchitectureQubits() { - if (qc.getNqubits() < architecture.getNqubits()) { - for (auto logical = qc.getNqubits(); logical < architecture.getNqubits(); + if (qc.getNqubits() < architecture->getNqubits()) { + for (auto logical = qc.getNqubits(); logical < architecture->getNqubits(); ++logical) { std::optional physical = std::nullopt; @@ -247,7 +248,7 @@ void Mapper::placeRemainingArchitectureQubits() { if (qcMapped.initialLayout.find(static_cast(logical)) != qcMapped.initialLayout.end()) { // get the next unused physical qubit - for (physical = 0; *physical < architecture.getNqubits(); + for (physical = 0; *physical < architecture->getNqubits(); ++(*physical)) { if (qcMapped.initialLayout.find(*physical) == qcMapped.initialLayout.end()) { @@ -299,7 +300,7 @@ void Mapper::countGates(decltype(qcMapped.cbegin()) it, if (g->isStandardOperation()) { if (g->getType() == qc::SWAP) { - if (architecture.bidirectional()) { + if (architecture->bidirectional()) { info.gates += GATES_OF_BIDIRECTIONAL_SWAP; info.cnots += GATES_OF_BIDIRECTIONAL_SWAP; } else { diff --git a/src/cliffordsynthesis/Tableau.cpp b/src/cliffordsynthesis/Tableau.cpp index 34c48c1cc..132f4ccc7 100644 --- a/src/cliffordsynthesis/Tableau.cpp +++ b/src/cliffordsynthesis/Tableau.cpp @@ -65,13 +65,13 @@ void Tableau::applyGate(const qc::Operation* const gate) { case qc::OpType::S: applyS(target); break; - case qc::OpType::Sdag: + case qc::OpType::Sdg: applySdag(target); break; case qc::OpType::SX: applySx(target); break; - case qc::OpType::SXdag: + case qc::OpType::SXdg: applySxdag(target); break; case qc::OpType::X: @@ -180,8 +180,7 @@ void Tableau::fromString(const std::string& str) { if (line.empty()) { return; } - const auto rStabilizer = std::regex("([\\+-]?)([IYZX]+)"); - std::smatch m; + const auto rStabilizer = std::regex("([\\+-]?)([IYZX]+)"); if (std::regex_search(line, rStabilizer)) { // string is a list of stabilizers loadStabilizerDestabilizerString(str); diff --git a/src/cliffordsynthesis/encoding/GateEncoder.cpp b/src/cliffordsynthesis/encoding/GateEncoder.cpp index 05adcfcd8..aeff8fcf6 100644 --- a/src/cliffordsynthesis/encoding/GateEncoder.cpp +++ b/src/cliffordsynthesis/encoding/GateEncoder.cpp @@ -263,7 +263,7 @@ void GateEncoder::assertSingleQubitGateCancellationConstraints( if constexpr (containsS() && containsSdag()) { const auto gateIndexS = gateToIndex(qc::OpType::S); - const auto gateIndexSdg = gateToIndex(qc::OpType::Sdag); + const auto gateIndexSdg = gateToIndex(qc::OpType::Sdg); // -X-(S|Sd)- ~= -(Sd|S)-X- // -Y-(S|Sd)- ~= -(Sd|S)-Y- @@ -293,7 +293,7 @@ void GateEncoder::assertSingleQubitGateCancellationConstraints( auto disallowed = !gSNext[gateIndexS][qubit]; if constexpr (containsSdag()) { - constexpr auto gateIndexSdag = gateToIndex(qc::OpType::Sdag); + constexpr auto gateIndexSdag = gateToIndex(qc::OpType::Sdg); // -Sd-Sd- = -Z- // -Sd-S- = -I- @@ -308,7 +308,7 @@ void GateEncoder::assertSingleQubitGateCancellationConstraints( lb->assertFormula(LogicTerm::implies(gates, disallowed)); } else { if constexpr (containsSdag()) { - constexpr auto gateIndexSdag = gateToIndex(qc::OpType::Sdag); + constexpr auto gateIndexSdag = gateToIndex(qc::OpType::Sdg); // -S-Sd- = -I- // -Sd-S- = -I- diff --git a/src/cliffordsynthesis/encoding/SingleGateEncoder.cpp b/src/cliffordsynthesis/encoding/SingleGateEncoder.cpp index dc9b095e6..60f537398 100644 --- a/src/cliffordsynthesis/encoding/SingleGateEncoder.cpp +++ b/src/cliffordsynthesis/encoding/SingleGateEncoder.cpp @@ -205,7 +205,7 @@ void SingleGateEncoder::assertTwoQubitGateOrderConstraints( // commute. disallowed = disallowed && !gSNext[gateToIndex(qc::OpType::Z)][control] && !gSNext[gateToIndex(qc::OpType::S)][control] && - !gSNext[gateToIndex(qc::OpType::Sdag)][control]; + !gSNext[gateToIndex(qc::OpType::Sdg)][control]; // no CNOT with the same control and a lower target qubit may be placed. for (std::size_t t = 0U; t < target; ++t) { diff --git a/src/cliffordsynthesis/encoding/TableauEncoder.cpp b/src/cliffordsynthesis/encoding/TableauEncoder.cpp index b16a49b5e..12df965b4 100644 --- a/src/cliffordsynthesis/encoding/TableauEncoder.cpp +++ b/src/cliffordsynthesis/encoding/TableauEncoder.cpp @@ -83,7 +83,7 @@ TableauEncoder::Variables::singleQubitXChange(const std::size_t pos, case qc::OpType::Y: case qc::OpType::Z: case qc::OpType::S: - case qc::OpType::Sdag: + case qc::OpType::Sdg: return x[pos][qubit]; case qc::OpType::H: return z[pos][qubit]; @@ -106,7 +106,7 @@ TableauEncoder::Variables::singleQubitZChange(const std::size_t pos, case qc::OpType::H: return x[pos][qubit]; case qc::OpType::S: - case qc::OpType::Sdag: + case qc::OpType::Sdg: return (z[pos][qubit] ^ x[pos][qubit]); default: FATAL() << "Unsupported single-qubit gate: " << toString(gate); @@ -126,7 +126,7 @@ TableauEncoder::Variables::singleQubitRChange(const std::size_t pos, case qc::OpType::H: case qc::OpType::S: return x[pos][qubit] & z[pos][qubit]; - case qc::OpType::Sdag: + case qc::OpType::Sdg: return x[pos][qubit] & (x[pos][qubit] ^ z[pos][qubit]); case qc::OpType::X: return z[pos][qubit]; diff --git a/src/exact/ExactMapper.cpp b/src/exact/ExactMapper.cpp index c55da45d6..7e8f54c04 100644 --- a/src/exact/ExactMapper.cpp +++ b/src/exact/ExactMapper.cpp @@ -42,7 +42,7 @@ void ExactMapper::map(const Configuration& settings) { // quickly terminate if the circuit only contains single-qubit gates if (reducedLayerIndices.empty()) { - qcMapped = qc.clone(); + qcMapped = qc; postMappingOptimizations(config); results.output.gates = 0U; countGates(qcMapped, results.output); @@ -67,25 +67,25 @@ void ExactMapper::map(const Configuration& settings) { } CouplingMap reducedCouplingMap{}; - architecture.getReducedCouplingMap(config.subgraph, reducedCouplingMap); + architecture->getReducedCouplingMap(config.subgraph, reducedCouplingMap); // check if the subgraph is connected if (!Architecture::isConnected(config.subgraph, reducedCouplingMap)) { - std::cerr << "The subgraph is not connected." << std::endl; + std::cerr << "The subgraph is not connected.\n"; return; } - architecture.setCouplingMap(reducedCouplingMap); + architecture->setCouplingMap(reducedCouplingMap); } // 2b) If configured to use subsets, collect all k (=m over n) possibilities // to pick n qubits from m device qubits. Otherwise, consider all qubits. std::vector qubitRange = - Architecture::getQubitList(architecture.getCouplingMap()); + Architecture::getQubitList(architecture->getCouplingMap()); std::vector allPossibleQubitChoices{}; if (config.useSubsets) { - allPossibleQubitChoices = architecture.getAllConnectedSubsets( + allPossibleQubitChoices = architecture->getAllConnectedSubsets( static_cast(qc.getNqubits())); } else { allPossibleQubitChoices.emplace_back(qubitRange.begin(), qubitRange.end()); @@ -100,12 +100,12 @@ void ExactMapper::map(const Configuration& settings) { std::size_t maxLimit = 0U; const std::size_t upperLimit = config.swapLimit; if (config.useSubsets) { - maxLimit = architecture.getCouplingLimit(choice) - 1U; + maxLimit = architecture->getCouplingLimit(choice) - 1U; } else { - maxLimit = architecture.getCouplingLimit() - 1U; + maxLimit = architecture->getCouplingLimit() - 1U; } if (config.swapReduction == SwapReduction::CouplingLimit) { - if (!architecture.bidirectional()) { + if (!architecture->bidirectional()) { // on a directed architecture, one more SWAP might be needed overall // due to the directionality of the edges and direction reversal not // being possible for every gate. @@ -150,7 +150,7 @@ void ExactMapper::map(const Configuration& settings) { // 4) reduce coupling map CouplingMap reducedCouplingMap = {}; - architecture.getReducedCouplingMap(choice, reducedCouplingMap); + architecture->getReducedCouplingMap(choice, reducedCouplingMap); if (reducedCouplingMap.empty()) { break; @@ -165,7 +165,7 @@ void ExactMapper::map(const Configuration& settings) { if (config.swapReduction != SwapReduction::None) { std::cout << "SWAP limit: " << limit; } - std::cout << std::endl; + std::cout << "\n"; } // 6) call actual mapping routine @@ -175,13 +175,13 @@ void ExactMapper::map(const Configuration& settings) { if (config.verbose) { if (!choiceResults.timeout) { std::cout << "Costs: " << choiceResults.output.swaps << " SWAP(s)"; - if (!architecture.bidirectional()) { + if (!architecture->bidirectional()) { std::cout << ", " << choiceResults.output.directionReverse << " direction reverses"; } - std::cout << std::endl; + std::cout << "\n"; } else { - std::cout << "Did not yield a result" << std::endl; + std::cout << "Did not yield a result\n"; } } @@ -199,7 +199,7 @@ void ExactMapper::map(const Configuration& settings) { } } while (config.swapReduction == SwapReduction::Increasing && (limit <= upperLimit || config.swapLimit == 0) && - limit < architecture.getCouplingLimit()); + limit < architecture->getCouplingLimit()); // stop if a perfect result has been found if (!results.timeout && results.output.swaps == 0U && @@ -250,14 +250,14 @@ void ExactMapper::map(const Configuration& settings) { if (settings.verbose) { std::cout << "Qubits: "; - for (auto q = 0U; q < architecture.getNqubits(); ++q) { + for (auto q = 0U; q < architecture->getNqubits(); ++q) { std::cout << qubits.at(q) << " "; } std::cout << " Locations: "; for (std::size_t q = 0; q < qc.getNqubits(); ++q) { std::cout << locations.at(q) << " "; } - std::cout << std::endl; + std::cout << "\n"; } ++swapsIterator; } @@ -274,7 +274,7 @@ void ExactMapper::map(const Configuration& settings) { if (gate.singleQubit()) { if (settings.verbose) { std::cout << i << ": Added single qubit gate with target: " - << locations.at(gate.target) << std::endl; + << locations.at(gate.target) << "\n"; } qcMapped.emplace_back( @@ -284,11 +284,11 @@ void ExactMapper::map(const Configuration& settings) { const Edge cnot = {locations.at(static_cast(gate.control)), locations.at(gate.target)}; - if (architecture.getCouplingMap().find(cnot) == - architecture.getCouplingMap().end()) { + if (architecture->getCouplingMap().find(cnot) == + architecture->getCouplingMap().end()) { const Edge reverse = {cnot.second, cnot.first}; - if (architecture.getCouplingMap().find(reverse) == - architecture.getCouplingMap().end()) { + if (architecture->getCouplingMap().find(reverse) == + architecture->getCouplingMap().end()) { throw QMAPException( "Invalid CNOT: " + std::to_string(reverse.first) + "-" + std::to_string(reverse.second)); @@ -297,22 +297,22 @@ void ExactMapper::map(const Configuration& settings) { std::cout << i << ": Added (direction-reversed) cnot with control and target: " - << cnot.first << " " << cnot.second << std::endl; + << cnot.first << " " << cnot.second << "\n"; } qcMapped.h(reverse.first); qcMapped.h(reverse.second); - qcMapped.x(reverse.second, - qc::Control{static_cast(reverse.first)}); + qcMapped.cx(qc::Control{static_cast(reverse.first)}, + reverse.second); qcMapped.h(reverse.second); qcMapped.h(reverse.first); } else { if (settings.verbose) { std::cout << i << ": Added cnot with control and target: " << cnot.first - << " " << cnot.second << std::endl; + << " " << cnot.second << "\n"; } - qcMapped.x(cnot.second, - qc::Control{static_cast(cnot.first)}); + qcMapped.cx(qc::Control{static_cast(cnot.first)}, + cnot.second); } } } @@ -332,14 +332,14 @@ void ExactMapper::map(const Configuration& settings) { if (settings.verbose) { std::cout << "Qubits: "; - for (auto q = 0U; q < architecture.getNqubits(); ++q) { + for (auto q = 0U; q < architecture->getNqubits(); ++q) { std::cout << qubits.at(q) << " "; } std::cout << " Locations: "; for (std::size_t q = 0; q < qc.getNqubits(); ++q) { std::cout << locations.at(q) << " "; } - std::cout << std::endl; + std::cout << "\n"; } } @@ -409,7 +409,7 @@ void ExactMapper::coreMappingRoutine( ////////////////////////////////////////// if (config.swapLimitsEnabled() && !config.useBDD) { do { - auto picost = architecture.minimumNumberOfSwaps( + auto picost = architecture->minimumNumberOfSwaps( pi, static_cast(limit)); if (picost > limit) { skippedPi.insert(piCount); @@ -594,7 +594,7 @@ number of variables: (|L|-1) * m! } auto coupling = LogicTerm(false); - if (architecture.bidirectional()) { + if (architecture->bidirectional()) { for (const auto& edge : rcm) { auto indexFC = x[k][physicalQubitIndex[edge.first]] [static_cast(gate.control)]; @@ -701,8 +701,8 @@ number of variables: (|L|-1) * m! auto cost = LogicTerm(0); do { if (skippedPi.count(piCount) == 0 || !config.swapLimitsEnabled()) { - auto picost = architecture.minimumNumberOfSwaps(pi); - if (architecture.bidirectional()) { + auto picost = architecture->minimumNumberOfSwaps(pi); + if (architecture->bidirectional()) { picost *= GATES_OF_BIDIRECTIONAL_SWAP; } else { picost *= GATES_OF_UNIDIRECTIONAL_SWAP; @@ -727,7 +727,7 @@ number of variables: (|L|-1) * m! } // cost for reversed directions - if (!architecture.bidirectional()) { + if (!architecture->bidirectional()) { const auto numLayers = reducedLayerIndices.size(); for (std::size_t k = 0; k < numLayers; ++k) { for (const auto& gate : layers.at(reducedLayerIndices.at(k))) { @@ -818,9 +818,9 @@ number of variables: (|L|-1) * m! } while (std::next_permutation(pi.begin(), pi.end())); } - architecture.minimumNumberOfSwaps(pi, swaps.at(k)); + architecture->minimumNumberOfSwaps(pi, swaps.at(k)); choiceResults.output.swaps += swaps.at(k).size(); - if (architecture.bidirectional()) { + if (architecture->bidirectional()) { choiceResults.output.gates += GATES_OF_BIDIRECTIONAL_SWAP * swaps.at(k).size(); } else { @@ -830,7 +830,7 @@ number of variables: (|L|-1) * m! } // direction reverse - if (!architecture.bidirectional()) { + if (!architecture->bidirectional()) { for (std::size_t k = 0; k < reducedLayerIndices.size(); ++k) { for (const auto& gate : layers.at(reducedLayerIndices.at(k))) { if (gate.singleQubit()) { diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 4a79a98e6..b8c5adb45 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -58,10 +58,12 @@ void HeuristicMapper::map(const Configuration& configuration) { std::clog << "SWAP: " << swap.first << " <-> " << swap.second << "\n"; } - if (architecture.getCouplingMap().find({swap.first, swap.second}) == - architecture.getCouplingMap().end() && - architecture.getCouplingMap().find({swap.second, swap.first}) == - architecture.getCouplingMap().end()) { + if (architecture->getCouplingMap().find( + {swap.first, swap.second}) == + architecture->getCouplingMap().end() && + architecture->getCouplingMap().find( + {swap.second, swap.first}) == + architecture->getCouplingMap().end()) { throw QMAPException( "Invalid SWAP: " + std::to_string(swap.first) + "<->" + std::to_string(swap.second)); @@ -112,27 +114,27 @@ void HeuristicMapper::map(const Configuration& configuration) { const Edge cnot = { locations.at(static_cast(gate.control)), locations.at(gate.target)}; - if (architecture.getCouplingMap().find(cnot) == - architecture.getCouplingMap().end()) { + if (architecture->getCouplingMap().find(cnot) == + architecture->getCouplingMap().end()) { const Edge reverse = {cnot.second, cnot.first}; - if (architecture.getCouplingMap().find(reverse) == - architecture.getCouplingMap().end()) { + if (architecture->getCouplingMap().find(reverse) == + architecture->getCouplingMap().end()) { throw QMAPException( "Invalid CNOT: " + std::to_string(reverse.first) + "-" + std::to_string(reverse.second)); } qcMapped.h(reverse.first); qcMapped.h(reverse.second); - qcMapped.x(reverse.second, - qc::Control{static_cast(reverse.first)}); + qcMapped.cx(qc::Control{static_cast(reverse.first)}, + reverse.second); qcMapped.h(reverse.second); qcMapped.h(reverse.first); results.output.directionReverse++; gateidx += 5; } else { - qcMapped.x(cnot.second, - qc::Control{static_cast(cnot.first)}); + qcMapped.cx(qc::Control{static_cast(cnot.first)}, + cnot.second); gateidx++; } } @@ -155,7 +157,7 @@ void HeuristicMapper::map(const Configuration& configuration) { // infer output permutation from qubit locations qcMapped.outputPermutation.clear(); - for (std::size_t i = 0U; i < architecture.getNqubits(); ++i) { + for (std::size_t i = 0U; i < architecture->getNqubits(); ++i) { if (const auto lq = qubits.at(i); lq != -1) { const auto logicalQubit = static_cast(lq); // check whether this is a qubit from the original circuit @@ -220,7 +222,7 @@ void HeuristicMapper::map(const Configuration& configuration) { // mark every qubit that is not mapped to a logical qubit as garbage std::size_t count = 0U; - for (std::size_t i = 0U; i < architecture.getNqubits(); ++i) { + for (std::size_t i = 0U; i < architecture->getNqubits(); ++i) { if (const auto lq = qubits.at(i); lq == -1) { qcMapped.setLogicalQubitGarbage( static_cast(qc.getNqubits() + count)); @@ -244,7 +246,7 @@ void HeuristicMapper::staticInitialMapping() { continue; } - for (const auto& [q0, q1] : architecture.getCouplingMap()) { + for (const auto& [q0, q1] : architecture->getCouplingMap()) { if (qubits.at(q0) == DEFAULT_POSITION && qubits.at(q1) == DEFAULT_POSITION) { qubits.at(q0) = gate.control; @@ -263,9 +265,9 @@ void HeuristicMapper::staticInitialMapping() { } // assign remaining logical qubits - for (qc::Qubit i = 0U; i < architecture.getNqubits(); ++i) { + for (qc::Qubit i = 0U; i < architecture->getNqubits(); ++i) { if (qc.initialLayout.count(i) > 0 && locations.at(i) == DEFAULT_POSITION) { - for (qc::Qubit j = 0U; j < architecture.getNqubits(); ++j) { + for (qc::Qubit j = 0U; j < architecture->getNqubits(); ++j) { if (qubits.at(j) == DEFAULT_POSITION) { locations.at(i) = static_cast(j); qubits.at(j) = static_cast(i); @@ -299,12 +301,12 @@ void HeuristicMapper::createInitialMapping() { mt.seed(config.teleportationSeed); } - std::uniform_int_distribution<> dis(0, architecture.getNqubits() - 1); + std::uniform_int_distribution<> dis(0, architecture->getNqubits() - 1); for (std::size_t i = 0; i < config.teleportationQubits; i += 2) { Edge e{}; do { // NOLINT(cppcoreguidelines-avoid-do-while) - auto it = std::begin(architecture.getCouplingMap()); + auto it = std::begin(architecture->getCouplingMap()); std::advance(it, dis(mt)); e = *it; } while (qubits.at(e.first) != -1 || qubits.at(e.second) != -1); @@ -323,7 +325,7 @@ void HeuristicMapper::createInitialMapping() { switch (config.initialLayout) { case InitialLayout::Identity: - for (qc::Qubit i = 0; i < architecture.getNqubits(); ++i) { + for (qc::Qubit i = 0; i < architecture->getNqubits(); ++i) { if (qc.initialLayout.count(i) > 0) { locations.at(i) = static_cast(i); qubits.at(i) = static_cast(i); @@ -354,7 +356,7 @@ void HeuristicMapper::mapUnmappedGates( if (q1Location == DEFAULT_POSITION && q2Location == DEFAULT_POSITION) { std::set possibleEdges{}; // gather all edges in the architecture for which both qubits are unmapped - for (const auto& edge : architecture.getCouplingMap()) { + for (const auto& edge : architecture->getCouplingMap()) { if (qubits.at(edge.first) == DEFAULT_POSITION && qubits.at(edge.second) == DEFAULT_POSITION) { possibleEdges.emplace(edge); @@ -366,11 +368,11 @@ void HeuristicMapper::mapUnmappedGates( // map to 2 qubits with minimal distance double bestScore = std::numeric_limits::max(); - for (std::uint16_t i = 0; i < architecture.getNqubits(); i++) { - for (std::uint16_t j = i + 1; j < architecture.getNqubits(); j++) { + for (std::uint16_t i = 0; i < architecture->getNqubits(); i++) { + for (std::uint16_t j = i + 1; j < architecture->getNqubits(); j++) { if (qubits.at(i) == DEFAULT_POSITION && qubits.at(j) == DEFAULT_POSITION) { - const double dist = architecture.distance(i, j); + const double dist = architecture->distance(i, j); if (dist < bestScore) { bestScore = dist; chosenEdge = std::make_pair(i, j); @@ -407,7 +409,7 @@ void HeuristicMapper::mapToMinDistance(const std::uint16_t source, const std::uint16_t target) { auto min = std::numeric_limits::max(); std::optional pos = std::nullopt; - for (std::uint16_t i = 0; i < architecture.getNqubits(); ++i) { + for (std::uint16_t i = 0; i < architecture->getNqubits(); ++i) { if (qubits.at(i) == DEFAULT_POSITION) { // TODO: Consider fidelity here if available auto distance = distanceOnArchitectureOfPhysicalQubits( @@ -460,8 +462,8 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer) { node.locations = locations; node.qubits = qubits; - node.recalculateFixedCost(architecture); - node.updateHeuristicCost(architecture, twoQubitGateMultiplicity, + node.recalculateFixedCost(*architecture); + node.updateHeuristicCost(*architecture, twoQubitGateMultiplicity, results.config.admissibleHeuristic); nodes.push(node); @@ -522,27 +524,27 @@ void HeuristicMapper::expandNode( const std::unordered_set& consideredQubits, Node& node, std::size_t layer, const TwoQubitMultiplicity& twoQubitGateMultiplicity) { std::vector> usedSwaps; - usedSwaps.reserve(architecture.getNqubits()); - for (int p = 0; p < architecture.getNqubits(); ++p) { - usedSwaps.emplace_back(architecture.getNqubits()); + usedSwaps.reserve(architecture->getNqubits()); + for (int p = 0; p < architecture->getNqubits(); ++p) { + usedSwaps.emplace_back(architecture->getNqubits()); } // set up new teleportation qubits - std::set perms = architecture.getCouplingMap(); - architecture.getCurrentTeleportations().clear(); - architecture.getTeleportationQubits().clear(); + std::set perms = architecture->getCouplingMap(); + architecture->getCurrentTeleportations().clear(); + architecture->getTeleportationQubits().clear(); for (std::size_t i = 0; i < results.config.teleportationQubits; i += 2) { - architecture.getTeleportationQubits().emplace_back( + architecture->getTeleportationQubits().emplace_back( node.locations.at(qc.getNqubits() + i), node.locations.at(qc.getNqubits() + i + 1)); Edge e; - for (auto const& g : architecture.getCouplingMap()) { + for (auto const& g : architecture->getCouplingMap()) { if (g.first == node.locations.at(qc.getNqubits() + i) && g.second != node.locations.at(qc.getNqubits() + i + 1)) { e.first = g.second; e.second = static_cast( node.locations.at(qc.getNqubits() + i + 1)); - architecture.getCurrentTeleportations().insert(e); + architecture->getCurrentTeleportations().insert(e); perms.insert(e); } if (g.second == node.locations.at(qc.getNqubits() + i) && @@ -550,7 +552,7 @@ void HeuristicMapper::expandNode( e.first = g.first; e.second = static_cast( node.locations.at(qc.getNqubits() + i + 1)); - architecture.getCurrentTeleportations().insert(e); + architecture->getCurrentTeleportations().insert(e); perms.insert(e); } if (g.first == node.locations.at(qc.getNqubits() + i + 1) && @@ -558,7 +560,7 @@ void HeuristicMapper::expandNode( e.first = g.second; e.second = static_cast(node.locations.at(qc.getNqubits() + i)); - architecture.getCurrentTeleportations().insert(e); + architecture->getCurrentTeleportations().insert(e); perms.insert(e); } if (g.second == node.locations.at(qc.getNqubits() + i + 1) && @@ -566,7 +568,7 @@ void HeuristicMapper::expandNode( e.first = g.first; e.second = static_cast(node.locations.at(qc.getNqubits() + i)); - architecture.getCurrentTeleportations().insert(e); + architecture->getCurrentTeleportations().insert(e); perms.insert(e); } } @@ -601,16 +603,16 @@ void HeuristicMapper::expandNodeAddOneSwap( Node newNode = Node(node.qubits, node.locations, node.swaps, node.costFixed, node.depth + 1); - if (architecture.getCouplingMap().find(swap) != - architecture.getCouplingMap().end() || - architecture.getCouplingMap().find(Edge{swap.second, swap.first}) != - architecture.getCouplingMap().end()) { - newNode.applySWAP(swap, architecture); + if (architecture->getCouplingMap().find(swap) != + architecture->getCouplingMap().end() || + architecture->getCouplingMap().find(Edge{swap.second, swap.first}) != + architecture->getCouplingMap().end()) { + newNode.applySWAP(swap, *architecture); } else { - newNode.applyTeleportation(swap, architecture); + newNode.applyTeleportation(swap, *architecture); } - newNode.updateHeuristicCost(architecture, twoQubitGateMultiplicity, + newNode.updateHeuristicCost(*architecture, twoQubitGateMultiplicity, results.config.admissibleHeuristic); // calculate heuristics for the cost of the following layers @@ -644,7 +646,7 @@ void HeuristicMapper::lookahead(const std::size_t layer, // no penalty } else if (loc1 == DEFAULT_POSITION) { auto min = std::numeric_limits::max(); - for (std::uint16_t j = 0; j < architecture.getNqubits(); ++j) { + for (std::uint16_t j = 0; j < architecture->getNqubits(); ++j) { if (node.qubits.at(j) == DEFAULT_POSITION) { // TODO: Consider fidelity here if available min = std::min(min, distanceOnArchitectureOfPhysicalQubits( @@ -655,7 +657,7 @@ void HeuristicMapper::lookahead(const std::size_t layer, penalty = heuristicAddition(penalty, min); } else if (loc2 == DEFAULT_POSITION) { auto min = std::numeric_limits::max(); - for (std::uint16_t j = 0; j < architecture.getNqubits(); ++j) { + for (std::uint16_t j = 0; j < architecture->getNqubits(); ++j) { if (node.qubits.at(j) == DEFAULT_POSITION) { // TODO: Consider fidelity here if available min = std::min(min, @@ -667,7 +669,7 @@ void HeuristicMapper::lookahead(const std::size_t layer, } penalty = heuristicAddition(penalty, min); } else { - auto cost = architecture.distance( + auto cost = architecture->distance( static_cast( node.locations.at(static_cast(gate.control))), static_cast(node.locations.at(gate.target))); diff --git a/test/cliffordsynthesis/test_synthesis.cpp b/test/cliffordsynthesis/test_synthesis.cpp index 71b17ed09..6361b570c 100644 --- a/test/cliffordsynthesis/test_synthesis.cpp +++ b/test/cliffordsynthesis/test_synthesis.cpp @@ -50,12 +50,14 @@ inline void from_json(const nlohmann::json& j, TestConfiguration& test) { .get(); } -static std::vector getTests(const std::string& path) { +namespace { +std::vector getTests(const std::string& path) { std::ifstream input(path); nlohmann::json j; input >> j; return j; } +} // namespace class SynthesisTest : public ::testing::TestWithParam { protected: @@ -372,7 +374,7 @@ TEST(HeuristicTest, identity) { qc.h(0); qc.s(1); qc.h(0); - qc.sdag(1); + qc.sdg(1); config.heuristic = true; config.splitSize = 2; config.target = TargetMetric::Depth; @@ -386,7 +388,7 @@ TEST(HeuristicTest, threeLayers) { auto qc = qc::QuantumComputation(2); qc.h(0); qc.h(1); - qc.x(1, 0_pc); + qc.cx(0_pc, 1); qc.h(0); qc.h(1); config.heuristic = true; diff --git a/test/test_architecture.cpp b/test/test_architecture.cpp index 5aabacb67..66bd3fc14 100644 --- a/test/test_architecture.cpp +++ b/test/test_architecture.cpp @@ -176,18 +176,18 @@ TEST(TestArchitecture, opTypeFromString) { {"y", qc::OpType::Y}, {"z", qc::OpType::Z}, {"sx", qc::OpType::SX}, - {"sxdg", qc::OpType::SXdag}, + {"sxdg", qc::OpType::SXdg}, {"h", qc::OpType::H}, {"s", qc::OpType::S}, - {"sdg", qc::OpType::Sdag}, + {"sdg", qc::OpType::Sdg}, {"t", qc::OpType::T}, - {"tdg", qc::OpType::Tdag}, + {"tdg", qc::OpType::Tdg}, {"rx", qc::OpType::RX}, {"ry", qc::OpType::RY}, {"rz", qc::OpType::RZ}, - {"u1", qc::OpType::Phase}, + {"u1", qc::OpType::P}, {"u2", qc::OpType::U2}, - {"u3", qc::OpType::U3}, + {"u3", qc::OpType::U}, {"reset", qc::OpType::Reset}, {"measure", qc::OpType::Measure}}; @@ -207,9 +207,9 @@ TEST(TestArchitecture, opTypeFromString) { {"crx", qc::OpType::RX}, {"ry", qc::OpType::RY}, {"crz", qc::OpType::RZ}, - {"cu1", qc::OpType::Phase}, + {"cu1", qc::OpType::P}, {"cu2", qc::OpType::U2}, - {"cu3", qc::OpType::U3}, + {"cu3", qc::OpType::U}, {"iswap", qc::OpType::iSWAP}, {"ecr", qc::OpType::ECR}, {"dcx", qc::OpType::DCX}, diff --git a/test/test_encodings.cpp b/test/test_encodings.cpp index 5dd9b60b1..bc0529652 100644 --- a/test/test_encodings.cpp +++ b/test/test_encodings.cpp @@ -36,8 +36,8 @@ TEST_P(TestEncodings, ThreeToSevenQubits) { using namespace qc::literals; qc = qc::QuantumComputation(3U); - qc.x(2, 1_pc); - qc.x(1, 0_pc); + qc.cx(1_pc, 2); + qc.cx(0_pc, 1); arch.loadCouplingMap(AvailableArchitecture::IbmqCasablanca); @@ -58,10 +58,10 @@ TEST_P(TestEncodings, FiveToSevenQubits) { using namespace qc::literals; qc = qc::QuantumComputation(5U); - qc.x(1, 0_pc); - qc.x(2, 0_pc); - qc.x(3, 0_pc); - qc.x(4, 0_pc); + qc.cx(0_pc, 1); + qc.cx(0_pc, 2); + qc.cx(0_pc, 3); + qc.cx(0_pc, 4); arch.loadCouplingMap(AvailableArchitecture::IbmqCasablanca); diff --git a/test/test_exact.cpp b/test/test_exact.cpp index 460bda1d8..1fd7d92dc 100644 --- a/test/test_exact.cpp +++ b/test/test_exact.cpp @@ -31,9 +31,9 @@ class ExactTest : public testing::TestWithParam { qc.import(testExampleDir + GetParam() + ".qasm"); } else { qc.addQubitRegister(3U); - qc.x(0, 1_pc); - qc.x(1, 2_pc); - qc.x(2, 0_pc); + qc.cx(1_pc, 0); + qc.cx(2_pc, 1); + qc.cx(0_pc, 2); } ibmqYorktown.loadCouplingMap(AvailableArchitecture::IbmqYorktown); ibmqLondon.loadCouplingMap(testArchitectureDir + "ibmq_london.arch"); @@ -436,10 +436,10 @@ TEST_F(ExactTest, WCNFNotAvailable) { auto circ = qc::QuantumComputation(5U); circ.h(0); - circ.x(1, 0_pc); - circ.x(2, 0_pc); - circ.x(3, 0_pc); - circ.x(4, 0_pc); + circ.cx(0_pc, 1); + circ.cx(0_pc, 2); + circ.cx(0_pc, 3); + circ.cx(0_pc, 4); auto mapper = ExactMapper(circ, ibmqLondon); @@ -546,11 +546,11 @@ TEST_F(ExactTest, RegressionTestDirectionReverseCost) { Architecture::printCouplingMap(cm, std::cout); qc = qc::QuantumComputation(4); - qc.x(0, 1_pc); - qc.x(1, 0_pc); - qc.x(1, 2_pc); - qc.x(2, 1_pc); - qc.x(2, 3_pc); + qc.cx(1_pc, 0); + qc.cx(0_pc, 1); + qc.cx(2_pc, 1); + qc.cx(1_pc, 2); + qc.cx(3_pc, 2); auto mapper = ExactMapper(qc, arch); mapper.map(settings); diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 7f747e7a3..04e738581 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -99,9 +99,9 @@ TEST(Functionality, HeuristicBenchmark) { architecture.loadCouplingMap(5, cm); qc::QuantumComputation qc{5, 5}; - qc.x(2, qc::Control{4}); - qc.x(1, qc::Control{3}); - qc.x(1, qc::Control{4}); + qc.cx(qc::Control{4}, 2); + qc.cx(qc::Control{3}, 1); + qc.cx(qc::Control{4}, 1); qc.barrier({0, 1, 2, 3, 4}); for (size_t i = 0; i < 5; ++i) { @@ -182,9 +182,9 @@ TEST(Functionality, NoMeasurmentsAdded) { using namespace qc::literals; // construct circuit qc::QuantumComputation qc{4U}; - qc.x(1, 0_pc); - qc.x(1, 2_pc); - qc.x(1, 3_pc); + qc.cx(0_pc, 1); + qc.cx(2_pc, 1); + qc.cx(3_pc, 1); // load architecture Architecture arch{}; diff --git a/test/test_tableau.cpp b/test/test_tableau.cpp index 5c6a1a803..03bc3b3af 100644 --- a/test/test_tableau.cpp +++ b/test/test_tableau.cpp @@ -506,12 +506,12 @@ TEST_F(TestTableau, CircuitTranslation) { qc.z(0); qc.h(0); qc.s(0); - qc.sdag(0); + qc.sdg(0); qc.sx(0); - qc.sxdag(0); - qc.x(1, 0_pc); - qc.y(1, 0_pc); - qc.z(1, 0_pc); + qc.sxdg(0); + qc.cx(0_pc, 1); + qc.cy(0_pc, 1); + qc.cz(0_pc, 1); qc.swap(0, 1); qc.iswap(0, 1); qc.dcx(0, 1); @@ -532,7 +532,7 @@ TEST_F(TestTableau, UnsupportedOperations) { qc::QuantumComputation qc(3U); // three-qubit operation not supported - qc.x(0, {1_pc, 2_pc}); + qc.mcx({1_pc, 2_pc}, 0); EXPECT_THROW(tableau = cs::Tableau(qc), std::runtime_error); // single-qubit gate not supported @@ -542,7 +542,7 @@ TEST_F(TestTableau, UnsupportedOperations) { // controlled two-qubit gate not supported qc.clear(); - qc.s(0, 1_pc); + qc.cs(1_pc, 0); EXPECT_THROW(tableau = cs::Tableau(qc), std::runtime_error); }