From 8603bfd6610240aed3893c394fb15a6b1c70bd6d Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Tue, 26 Dec 2023 09:52:13 +0100 Subject: [PATCH 01/47] first implementation --- include/heuristic/HeuristicMapper.hpp | 5 +++- src/heuristic/HeuristicMapper.cpp | 42 +++++++++++++-------------- test/test_heuristic.cpp | 4 +-- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 8df353fc4..ea01dd1c8 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -61,6 +61,8 @@ class HeuristicMapper : public Mapper { /** number of swaps used to get from mapping after last layer to the current * mapping */ std::size_t nswaps = 0; + /** number of swaps that were shared with another considered qubit */ + std::size_t sharedSwaps = 0; /** depth in search tree (starting with 0 at the root) */ std::size_t depth = 0; std::size_t parent = 0; @@ -111,7 +113,8 @@ class HeuristicMapper : public Mapper { */ void applySWAP(const Edge& swap, Architecture& arch, const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity); + const TwoQubitMultiplicity& twoQubitGateMultiplicity, + const std::unordered_set& consideredQubits); /** * @brief applies an in-place teleportation of 2 qubits in `qubits` and diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 2fb9831b7..d89d8fb27 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -747,7 +747,7 @@ void HeuristicMapper::expandNodeAddOneSwap( if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { newNode.applySWAP(swap, *architecture, singleQubitMultiplicities.at(layer), - twoQubitMultiplicities.at(layer)); + twoQubitMultiplicities.at(layer), consideredQubits); } else { newNode.applyTeleportation(swap, *architecture); } @@ -834,11 +834,17 @@ void HeuristicMapper::lookahead(const std::size_t layer, void HeuristicMapper::Node::applySWAP( const Edge& swap, Architecture& arch, const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity) { + const TwoQubitMultiplicity& twoQubitGateMultiplicity, + const std::unordered_set& consideredQubits) { ++nswaps; swaps.emplace_back(); const auto q1 = qubits.at(swap.first); const auto q2 = qubits.at(swap.second); + + if (consideredQubits.find(swap.first) != consideredQubits.end() && + consideredQubits.find(swap.second) != consideredQubits.end()) { + ++sharedSwaps; + } qubits.at(swap.first) = q2; qubits.at(swap.second) = q1; @@ -1106,7 +1112,10 @@ void HeuristicMapper::Node::updateHeuristicCost( done = false; } - if (considerFidelity) { + if (!considerFidelity) { + costHeur += arch.distance(static_cast(locations.at(q1)), + static_cast(locations.at(q2))); + } else { // find the optimal edge, to which to remap the given virtual qubit // pair and take the cost of moving it there via swaps plus the // fidelity cost of executing all their shared gates on that edge @@ -1149,26 +1158,17 @@ void HeuristicMapper::Node::updateHeuristicCost( } else { costHeur += swapCost; } + } + } + + if(!considerFidelity && admissibleHeuristic){ + auto n = consideredQubits.size(); + if (arch.bidirectional()) { + costHeur -= ((n-1)*n/2 - sharedSwaps)*COST_BIDIRECTIONAL_SWAP; } else { - const double swapCostStraight = - arch.distance(static_cast(locations.at(q1)), - static_cast(locations.at(q2))); - const double swapCostReverse = - arch.distance(static_cast(locations.at(q2)), - static_cast(locations.at(q1))); - - if (admissibleHeuristic) { - if (straightMultiplicity > 0) { - costHeur = std::max(costHeur, swapCostStraight); - } - if (reverseMultiplicity > 0) { - costHeur = std::max(costHeur, swapCostReverse); - } - } else { - costHeur += swapCostStraight * straightMultiplicity + - swapCostReverse * reverseMultiplicity; - } + costHeur -= ((n-1)*n/2 - sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; } } + costHeur -= savingsPotential; } diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index fb63ce849..abe262d11 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -41,7 +41,7 @@ TEST(Functionality, NodeCostCalculation) { node.updateHeuristicCost(arch, empty1Mult, multiplicity, consideredQubits); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); - node.applySWAP({3, 4}, arch, empty1Mult, multiplicity); + node.applySWAP({3, 4}, arch, empty1Mult, multiplicity, consideredQubits); node.updateHeuristicCost(arch, empty1Mult, multiplicity, consideredQubits); EXPECT_NEAR(node.costFixed, 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, @@ -289,7 +289,7 @@ TEST(Functionality, HeuristicAdmissibility) { auto newNode = HeuristicMapper::Node(1, 0, node.qubits, node.locations, node.swaps, node.costFixed, node.depth + 1, false, true); - newNode.applySWAP(perm, architecture, empty1Mult, multiplicity); + newNode.applySWAP(perm, architecture, empty1Mult, multiplicity, consideredQubits); newNode.updateHeuristicCost(architecture, empty1Mult, multiplicity, consideredQubits); nodeStack.emplace_back(newNode); From 4204205cbb24cd39b9fd84fba23734b871204597 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Tue, 26 Dec 2023 12:14:58 +0100 Subject: [PATCH 02/47] take max of old and new heuristic --- src/heuristic/HeuristicMapper.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index d89d8fb27..92d9c5d0d 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -1065,6 +1065,7 @@ void HeuristicMapper::Node::updateHeuristicCost( const std::unordered_set& consideredQubits) { costHeur = 0.; done = true; + double costSum = 0.; // single qubit gate savings potential by moving them to different physical // qubits with higher fidelity @@ -1113,8 +1114,10 @@ void HeuristicMapper::Node::updateHeuristicCost( } if (!considerFidelity) { - costHeur += arch.distance(static_cast(locations.at(q1)), + const double swapCost = arch.distance(static_cast(locations.at(q1)), static_cast(locations.at(q2))); + costHeur = std::max(costHeur, swapCost); + costSum += swapCost; } else { // find the optimal edge, to which to remap the given virtual qubit // pair and take the cost of moving it there via swaps plus the @@ -1161,12 +1164,18 @@ void HeuristicMapper::Node::updateHeuristicCost( } } - if(!considerFidelity && admissibleHeuristic){ - auto n = consideredQubits.size(); - if (arch.bidirectional()) { - costHeur -= ((n-1)*n/2 - sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + if(!considerFidelity){ + if (!admissibleHeuristic) { + costHeur = costSum; } else { - costHeur -= ((n-1)*n/2 - sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + std::size_t n = consideredQubits.size(); + double sharedSwapCostReduction = 0; + if (arch.bidirectional()) { + sharedSwapCostReduction = ((n-1)*n/2 - sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + } else { + sharedSwapCostReduction = ((n-1)*n/2 - sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + } + costHeur = std::max(costHeur, costSum - sharedSwapCostReduction); } } From f395749f6a82be8f45a685cb39a86953affcfe07 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Sun, 31 Dec 2023 18:25:44 +0100 Subject: [PATCH 03/47] introduce setting to choose heuristic and lookahead heuristic --- include/DataLogger.hpp | 4 +- include/configuration/Configuration.hpp | 13 +- include/configuration/Heuristic.hpp | 128 +++ include/configuration/LookaheadHeuristic.hpp | 56 ++ include/heuristic/HeuristicMapper.hpp | 227 ++++-- src/DataLogger.cpp | 34 +- src/configuration/Configuration.cpp | 14 +- src/heuristic/HeuristicMapper.cpp | 786 +++++++++++-------- src/mqt/qmap/compile.py | 18 +- src/mqt/qmap/pyqmap.pyi | 53 +- src/python/bindings.cpp | 30 +- test/test_heuristic.cpp | 81 +- 12 files changed, 951 insertions(+), 493 deletions(-) create mode 100644 include/configuration/Heuristic.hpp create mode 100644 include/configuration/LookaheadHeuristic.hpp diff --git a/include/DataLogger.hpp b/include/DataLogger.hpp index 417214cab..c783af3b2 100644 --- a/include/DataLogger.hpp +++ b/include/DataLogger.hpp @@ -37,7 +37,7 @@ class DataLogger { double lookaheadPenalty, const std::array& qubits, bool validMapping, - const std::vector>& swaps, + const std::vector& swaps, std::size_t depth); void logFinalizeLayer( std::size_t layer, const qc::CompoundOperation& ops, @@ -49,7 +49,7 @@ class DataLogger { std::size_t finalNodeId, double finalCostFixed, double finalCostHeur, double finalLookaheadPenalty, const std::array& finalLayout, - const std::vector>& finalSwaps, + const std::vector& finalSwaps, std::size_t finalSearchDepth); void splitLayer(); void logMappingResult(MappingResults& result); diff --git a/include/configuration/Configuration.hpp b/include/configuration/Configuration.hpp index 741c811fa..2efbf78e9 100644 --- a/include/configuration/Configuration.hpp +++ b/include/configuration/Configuration.hpp @@ -7,8 +7,10 @@ #include "CommanderGrouping.hpp" #include "Encoding.hpp" +#include "Heuristic.hpp" #include "InitialLayout.hpp" #include "Layering.hpp" +#include "LookaheadHeuristic.hpp" #include "Method.hpp" #include "SwapReduction.hpp" #include "nlohmann/json.hpp" @@ -21,8 +23,7 @@ struct Configuration { // which method to use Method method = Method::Heuristic; - bool admissibleHeuristic = true; - bool considerFidelity = false; + Heuristic heuristic = Heuristic::SwapCountMaxDistance; bool preMappingOptimizations = true; bool postMappingOptimizations = true; @@ -58,10 +59,10 @@ struct Configuration { std::size_t iterativeBidirectionalRoutingPasses = 0; // lookahead scheme settings - bool lookahead = true; - std::size_t nrLookaheads = 15; - double firstLookaheadFactor = 0.75; - double lookaheadFactor = 0.5; + LookaheadHeuristic lookaheadHeuristic = LookaheadHeuristic::None; + std::size_t nrLookaheads = 15; + double firstLookaheadFactor = 0.75; + double lookaheadFactor = 0.5; // teleportation settings bool useTeleportation = false; diff --git a/include/configuration/Heuristic.hpp b/include/configuration/Heuristic.hpp new file mode 100644 index 000000000..2141f70f9 --- /dev/null +++ b/include/configuration/Heuristic.hpp @@ -0,0 +1,128 @@ +// +// This file is part of the MQT QMAP library released under the MIT license. +// See README.md or go to https://github.com/cda-tum/qmap for more information. +// + +#pragma once + +#include + +enum class Heuristic { + /** maximum over all distances between any virtual qubit pair in the current layer; optimizing gate-count; admissible; tight */ + GateCountMaxDistance, + /** sum over all distances between any virtual qubit pair in the current layer; optimizing gate-count; not admissible; tight */ + GateCountSumDistance, + /** sum over all distances between any virtual qubit pair in the current layer minus the upper limit of viable shared swaps; optimizing gate-count; admissible; tight */ + GateCountSumDistanceMinusSharedSwaps, + /** maximum of `Heuristic::GateCountMaxDistance` and `Heuristic::GateCountSumDistanceMinusSharedSwaps`; optimizing gate-count; admissible; tight */ + GateCountMaxDistanceOrSumDistanceMinusSharedSwaps, + /** minimum cost if each virtual qubit pair/qubit is mapped to its individually best physical edge/qubit; optimizing fidelity; admissible; tight */ + FidelityBestLocation +}; + +/** + * A heuristic is admissible if it never overestimates the cost of the best + * reachable goal node, i.e. c(n*) <= c(n) + h(n) for cost function c, + * heuristic h, any node n in the search graph, and n* the best reachable goal + * node from n. + */ +[[maybe_unused]] static inline bool isAdmissible(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::GateCountMaxDistance: + case Heuristic::FidelityBestLocation: + return true; + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + case Heuristic::GateCountSumDistance: + return false; + } + return false; +} + +/** + * A heuristic is principally admissible if it never overestimates the cost of the + * globally optimal solution along the solution path, i.e. c(n*) <= c(n) + h(n) + * for cost function c, heuristic h, any node n along the optimal solution path, + * and n* the globally optimal solution node. + */ +[[maybe_unused]] static inline bool isPrincipallyAdmissible(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::GateCountMaxDistance: + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + case Heuristic::FidelityBestLocation: + return true; + case Heuristic::GateCountSumDistance: + return false; + } + return false; +} + +/** + * A heuristic is tight if it is 0 in all goal nodes, i.e. h(n*) = 0 for any + * goal node n*. + */ +[[maybe_unused]] static inline bool isTight(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::GateCountMaxDistance: + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + case Heuristic::GateCountSumDistance: + return true; + case Heuristic::FidelityBestLocation: + return false; + } + return false; +} + +/** + * A heuristic is fidelity aware if it takes into account the error rates of + * physical qubits and minimizes the total error of the mapped circuit. + */ +[[maybe_unused]] static inline bool isFidelityAware(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::FidelityBestLocation: + return true; + case Heuristic::GateCountMaxDistance: + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + case Heuristic::GateCountSumDistance: + return false; + } + return false; +} + +[[maybe_unused]] static inline std::string toString(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::GateCountMaxDistance: + return "gate_count_max_distance"; + case Heuristic::GateCountSumDistance: + return "gate_count_sum_distance"; + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + return "gate_count_sum_distance_minus_shared_swaps"; + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + return "gate_count_max_distance_or_sum_distance_minus_shared_swaps"; + case Heuristic::FidelityBestLocation: + return "fidelity_best_location"; + } + return " "; +} + +[[maybe_unused]] static Heuristic heuristicFromString(const std::string& heuristic) { + if (heuristic == "gate_count_max_distance" || heuristic == "0") { + return Heuristic::GateCountMaxDistance; + } + if (heuristic == "gate_count_sum_distance" || heuristic == "1") { + return Heuristic::GateCountSumDistance; + } + if (heuristic == "gate_count_sum_distance_minus_shared_swaps" || heuristic == "2") { + return Heuristic::GateCountSumDistanceMinusSharedSwaps; + } + if (heuristic == "gate_count_max_distance_or_sum_distance_minus_shared_swaps" || heuristic == "3") { + return Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps; + } + if (heuristic == "fidelity_best_location" || heuristic == "4") { + return Heuristic::FidelityBestLocation; + } + throw std::invalid_argument("Invalid heuristic value: " + heuristic); +} \ No newline at end of file diff --git a/include/configuration/LookaheadHeuristic.hpp b/include/configuration/LookaheadHeuristic.hpp new file mode 100644 index 000000000..8694648b6 --- /dev/null +++ b/include/configuration/LookaheadHeuristic.hpp @@ -0,0 +1,56 @@ +// +// This file is part of the MQT QMAP library released under the MIT license. +// See README.md or go to https://github.com/cda-tum/qmap for more information. +// + +#pragma once + +#include + +enum class LookaheadHeuristic { + /** no lookahead */ + None, + /** maximum over all distances between any virtual qubit pair in the given layer; optimizing gate-count */ + GateCountMaxDistance, + /** sum over all distances between any virtual qubit pair in the given layer; optimizing gate-count */ + GateCountSumDistance +}; + +/** + * A heuristic is fidelity aware if it takes into account the error rates of + * physical qubits and minimizes the total error of the mapped circuit. + */ +[[maybe_unused]] static inline bool isFidelityAware(const LookaheadHeuristic heuristic) { + switch (heuristic) { + case LookaheadHeuristic::None: + case LookaheadHeuristic::GateCountMaxDistance: + case LookaheadHeuristic::GateCountSumDistance: + return false; + } + return false; +} + +[[maybe_unused]] static inline std::string toString(const LookaheadHeuristic heuristic) { + switch (heuristic) { + case LookaheadHeuristic::None: + return "none"; + case LookaheadHeuristic::GateCountMaxDistance: + return "gate_count_max_distance"; + case LookaheadHeuristic::GateCountSumDistance: + return "gate_count_sum_distance"; + } + return " "; +} + +[[maybe_unused]] static LookaheadHeuristic lookaheadHeuristicFromString(const std::string& heuristic) { + if (heuristic == "none" || heuristic == "0") { + return LookaheadHeuristic::None; + } + if (heuristic == "gate_count_max_distance" || heuristic == "1") { + return LookaheadHeuristic::GateCountMaxDistance; + } + if (heuristic == "gate_count_sum_distance" || heuristic == "2") { + return LookaheadHeuristic::GateCountSumDistance; + } + throw std::invalid_argument("Invalid lookahead heuristic value: " + heuristic); +} \ No newline at end of file diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index ea01dd1c8..dfe3a0f44 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -32,9 +32,9 @@ class HeuristicMapper : public Mapper { struct Node { /** gates (pair of logical qubits) currently mapped next to each other */ std::set validMappedTwoQubitGates = {}; - /** swaps used to get from mapping after last layer to the current mapping; - * each search node begins a new entry in the outer vector */ - std::vector> swaps = {}; + /** swaps used so far to get from the initial mapping of the current layer + * to the current mapping in this node */ + std::vector swaps = {}; /** * containing the logical qubit currently mapped to each physical qubit. * `qubits[physical_qubit] = logical_qubit` @@ -69,25 +69,18 @@ class HeuristicMapper : public Mapper { std::size_t id; /** true if all qubit pairs are mapped next to each other on the * architecture */ - bool done = true; - /** controls if fidelity-aware heuristic should be used */ - bool considerFidelity = false; - /** controls if admissible heuristic should be used */ - bool admissibleHeuristic = true; - - explicit Node(std::size_t nodeId, const bool considerFid = false, - const bool admissibleHeur = true) - : id(nodeId), considerFidelity(considerFid), - admissibleHeuristic(admissibleHeur){}; + bool validMapping = true; + + + explicit Node(std::size_t nodeId) + : id(nodeId) {}; Node(std::size_t nodeId, std::size_t parentId, const std::array& q, const std::array& loc, - const std::vector>& sw = {}, - const double initCostFixed = 0, const std::size_t searchDepth = 0, - const bool considerFid = false, const bool admissibleHeur = true) + const std::vector& sw = {}, + const double initCostFixed = 0, const std::size_t searchDepth = 0) : costFixed(initCostFixed), depth(searchDepth), parent(parentId), - id(nodeId), considerFidelity(considerFid), - admissibleHeuristic(admissibleHeur) { + id(nodeId) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); std::copy(sw.begin(), sw.end(), std::back_inserter(swaps)); @@ -107,56 +100,9 @@ class HeuristicMapper : public Mapper { return costFixed + lookaheadPenalty; } - /** - * @brief applies an in-place swap of 2 qubits in `qubits` and `locations` - * of the node - */ - void applySWAP(const Edge& swap, Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity, - const std::unordered_set& consideredQubits); - - /** - * @brief applies an in-place teleportation of 2 qubits in `qubits` and - * `locations` of the node - */ - void applyTeleportation(const Edge& swap, Architecture& arch); - - /** - * @brief recalculates the fixed cost of the node from current mapping and - * swaps - * - * @param arch the architecture for calculating distances between physical - * qubits and supplying qubit information such as fidelity - */ - void recalculateFixedCost( - const Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity); - - /** - * @brief calculates the heuristic cost of the current mapping in the node - * for some given layer and writes it to `Node::costHeur` additional - * `Node::done` is set to true if all qubits shared by a gate in the layer - * are mapped next to each other - * - * @param arch the architecture for calculating distances between physical - * qubits and supplying qubit information such as fidelity - * @param twoQubitGateMultiplicity number of two qubit gates acting on pairs - * of logical qubits in the current layer - * @param admissibleHeuristic controls if the heuristic should be calculated - * such that it is admissible (i.e. A*-search should yield the optimal - * solution using this heuristic) - */ - void updateHeuristicCost( - const Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity, - const std::unordered_set& consideredQubits); - std::ostream& print(std::ostream& out) const { out << "{\n"; - out << "\t\"done\": " << done << ",\n"; + out << "\t\"valid_mapping\": " << validMapping << ",\n"; out << "\t\"cost\": {\n"; out << "\t\t\"fixed\": " << costFixed << ",\n"; out << "\t\t\"heuristic\": " << costHeur << ",\n"; @@ -171,6 +117,9 @@ class HeuristicMapper : public Mapper { UniquePriorityQueue nodes{}; std::unique_ptr dataLogger; std::size_t nextNodeId = 0; + bool principallyAdmissibleHeur = true; + bool tightHeur = true; + bool fidelityAwareHeur = false; /** * @brief creates an initial mapping of logical qubits to physical qubits with @@ -249,7 +198,7 @@ class HeuristicMapper : public Mapper { * * uses `HeuristicMapper::nodes` as a priority queue for the A*-search, * assumed to be empty (or at least containing only nodes compliant with the - * current layer in their fields `costHeur` and `done`) + * current layer in their fields `costHeur` and `validMapping`) * * @param layer index of the current circuit layer * @param reverse if true, the circuit is mapped from the end to the beginning @@ -284,22 +233,142 @@ class HeuristicMapper : public Mapper { void expandNodeAddOneSwap( const Edge& swap, Node& node, std::size_t layer, const std::unordered_set& consideredQubits); + + /** + * @brief applies an in-place swap of 2 virtual qubits in the given node and recalculates all costs accordingly + * + * @param swap physical edge on which to perform a swap + * @param layer index of current circuit layer + * @param node search node in which to apply the swap + */ + void applySWAP(const Edge& swap, std::size_t layer, Node& node); /** - * @brief calculates the heuristic cost for the following layers and saves it - * in the node as `lookaheadPenalty` + * @brief applies an in-place teleportation of 2 virtual qubits in the given node and recalculates all costs accordingly + * + * @param swap pair of physical qubits on which to perform a teleportation + * @param layer index of current circuit layer + * @param node search node in which to apply the swap + */ + void applyTeleportation(const Edge& swap, std::size_t layer, Node& node); + + /** + * @brief recalculates the fixed cost of the node from the current mapping and swaps * * @param layer index of current circuit layer - * @param node search node for which to calculate lookahead penalty + * @param node search node for which to recalculate the fixed cost */ - void lookahead(std::size_t layer, Node& node); + void recalculateFixedCost(std::size_t layer, Node& node); - double heuristicAddition(const double currentCost, const double newCost) { - if (results.config.admissibleHeuristic) { - return std::max(currentCost, newCost); - } - return currentCost + newCost; - } + /** + * @brief recalculates the fidelity-aware fixed cost of the node from the current mapping and swaps + * + * @param layer index of current circuit layer + * @param node search node for which to recalculate the fixed cost + */ + void recalculateFixedCostFidelity(std::size_t layer, Node& node); + + /** + * @brief recalculates the gate-count-optimizing fixed cost of the node from the current mapping and swaps + * + * @param layer index of current circuit layer + * @param node search node for which to recalculate the fixed cost + */ + void recalculateFixedCostNonFidelity(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic cost of the current mapping in the node + * for some given layer and writes it to `Node::costHeur`, additionally + * `Node::validMapping` is set to true if all qubit pairs sharing a gate in + * the current layer are mapped next to each other + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + */ + void updateHeuristicCost(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic using `Heuristic::GateCountMaxDistance` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + * + * @return heuristic cost + */ + double heuristicGateCountMaxDistance(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic using `Heuristic::GateCountSumDistance` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + * + * @return heuristic cost + */ + double heuristicGateCountSumDistance(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic using + * `Heuristic::GateCountSumDistanceMinusSharedSwaps` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + * + * @return heuristic cost + */ + double heuristicGateCountSumDistanceMinusSharedSwaps(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic using + * `Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + * + * @return heuristic cost + */ + double heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(std::size_t layer, Node& node); + + /** + * @brief calculates the heuristic using + * `Heuristic::FidelityBestLocation` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate the heuristic cost + * + * @return heuristic cost + */ + double heuristicFidelityBestLocation(std::size_t layer, Node& node); + + /** + * @brief calculates an estimation of the heuristic cost for the following + * layers (depreciated by a constant factor growing with each layer) and + * saves it in the node as `Node::lookaheadPenalty` + * + * @param layer index of current circuit layer + * @param node search node for which to calculate lookahead penalty + */ + void updateLookaheadPenalty(std::size_t layer, Node& node); + + /** + * @brief calculates the lookahead penalty for one layer using `LookaheadHeuristic::GateCountMaxDistance` + * + * @param layer index of the circuit layer for which to calculate the lookahead penalty + * @param node search node for which to calculate the heuristic cost + * + * @return lookahead penalty + */ + double lookaheadGateCountMaxDistance(std::size_t layer, Node& node); + + /** + * @brief calculates the lookahead penalty for one layer using `LookaheadHeuristic::GateCountSumDistance` + * + * @param layer index of the circuit layer for which to calculate the lookahead penalty + * @param node search node for which to calculate the heuristic cost + * + * @return lookahead penalty + */ + double lookaheadGateCountSumDistance(std::size_t layer, Node& node); static double computeEffectiveBranchingRate(std::size_t nodesProcessed, const std::size_t solutionDepth) { @@ -350,10 +419,10 @@ inline bool operator>(const HeuristicMapper::Node& x, return xcost > ycost; } - if (x.done) { + if (x.validMapping) { return false; } - if (y.done) { + if (y.validMapping) { return true; } diff --git a/src/DataLogger.cpp b/src/DataLogger.cpp index e20c5d2e1..bfbc32b97 100644 --- a/src/DataLogger.cpp +++ b/src/DataLogger.cpp @@ -87,7 +87,7 @@ void DataLogger::logFinalizeLayer( std::size_t finalNodeId, double finalCostFixed, double finalCostHeur, double finalLookaheadPenalty, const std::array& finalLayout, - const std::vector>& finalSwaps, + const std::vector& finalSwaps, std::size_t finalSearchDepth) { if (deactivated) { return; @@ -142,13 +142,11 @@ void DataLogger::logFinalizeLayer( json["final_swaps"] = nlohmann::json::array(); } else { auto& finalSwapsJSON = json["final_swaps"]; - for (const auto& swaps : finalSwaps) { - std::size_t i = 0; - for (const auto& swap : swaps) { - finalSwapsJSON[i][0] = swap.first; - finalSwapsJSON[i][1] = swap.second; - ++i; - } + std::size_t i = 0; + for (const auto& swap : finalSwaps) { + finalSwapsJSON[i][0] = swap.first; + finalSwapsJSON[i][1] = swap.second; + ++i; } } json["final_search_depth"] = finalSearchDepth; @@ -188,7 +186,7 @@ void DataLogger::logSearchNode( std::size_t layerIndex, std::size_t nodeId, std::size_t parentId, double costFixed, double costHeur, double lookaheadPenalty, const std::array& qubits, - bool validMapping, const std::vector>& swaps, + bool validMapping, const std::vector& swaps, std::size_t depth) { if (deactivated) { return; @@ -214,18 +212,16 @@ void DataLogger::logSearchNode( of.seekp(-1, std::ios_base::cur); // remove last comma } of << ";"; - for (const auto& sw : swaps) { - for (const auto& s : sw) { - of << s.first << " " << s.second; - if (s.op != qc::OpType::SWAP) { - of << " " << s.op; - if (s.middleAncilla != - std::numeric_limits::max()) { - of << " " << s.middleAncilla; - } + for (const auto& s : swaps) { + of << s.first << " " << s.second; + if (s.op != qc::OpType::SWAP) { + of << " " << s.op; + if (s.middleAncilla != + std::numeric_limits::max()) { + of << " " << s.middleAncilla; } - of << ","; } + of << ","; } if (!swaps.empty()) { of.seekp(-1, std::ios_base::cur); // remove last comma diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index 475fdb302..ae47fc955 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -19,18 +19,18 @@ nlohmann::json Configuration::json() const { config["debug"] = debug; if (method == Method::Heuristic) { - auto& heuristic = config["settings"]; - heuristic["initial_layout"] = ::toString(initialLayout); - heuristic["admissible_heuristic"] = admissibleHeuristic; - heuristic["consider_fidelity"] = considerFidelity; - if (lookahead) { - auto& lookaheadSettings = heuristic["lookahead"]; + auto& heuristicJson = config["settings"]; + heuristicJson["heuristic"] = ::toString(heuristic); + heuristicJson["initial_layout"] = ::toString(initialLayout); + if (lookaheadHeuristic != LookaheadHeuristic::None) { + auto& lookaheadSettings = heuristicJson["lookahead"]; + lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); lookaheadSettings["lookaheads"] = nrLookaheads; lookaheadSettings["first_factor"] = firstLookaheadFactor; lookaheadSettings["factor"] = lookaheadFactor; } if (useTeleportation) { - auto& teleportation = heuristic["teleportation"]; + auto& teleportation = heuristicJson["teleportation"]; teleportation["qubits"] = teleportationQubits; teleportation["seed"] = teleportationSeed; teleportation["fake"] = teleportationFake; diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 92d9c5d0d..1364b9f04 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -14,6 +14,11 @@ void HeuristicMapper::map(const Configuration& configuration) { dataLogger = std::make_unique(configuration.dataLoggingPath, *architecture, qc); } + + principallyAdmissibleHeur = isPrincipallyAdmissible(configuration.heuristic); + tightHeur = isTight(configuration.heuristic); + fidelityAwareHeur = isFidelityAware(configuration.heuristic); + results = MappingResults{}; results.config = configuration; auto& config = results.config; @@ -22,14 +27,15 @@ void HeuristicMapper::map(const Configuration& configuration) { throw QMAPException("Layering strategy " + toString(config.layering) + " not suitable for heuristic mapper!"); } - if (config.considerFidelity && !architecture->isFidelityAvailable()) { + if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { throw QMAPException("No calibration data available for this architecture!"); } - if (config.considerFidelity && config.lookahead) { - throw QMAPException("Lookahead is not yet supported for heuristic mapper " - "using fidelity-aware mapping!"); + if (fidelityAwareHeur && !(isFidelityAware(config.lookaheadHeuristic) || config.lookaheadHeuristic == LookaheadHeuristic::None)) { + throw QMAPException("Fidelity-aware heuristics may only be used with " + "fidelity-aware lookahead heuristics (or no " + "lookahead)!"); } - if (config.considerFidelity && config.teleportationQubits > 0) { + if (fidelityAwareHeur && config.teleportationQubits > 0) { throw QMAPException("Teleportation is not yet supported for heuristic " "mapper using fidelity-aware mapping!"); } @@ -193,7 +199,7 @@ void HeuristicMapper::createInitialMapping() { } void HeuristicMapper::mapUnmappedGates(std::size_t layer) { - if (results.config.considerFidelity) { + if (fidelityAwareHeur) { for (std::size_t q = 0; q < singleQubitMultiplicities.at(layer).size(); ++q) { if (singleQubitMultiplicities.at(layer).at(q) == 0) { @@ -355,36 +361,34 @@ void HeuristicMapper::routeCircuit() { // initial layer needs no swaps if (layerIndex != 0 || config.swapOnFirstLayer) { - for (const auto& swaps : result.swaps) { - for (const auto& swap : swaps) { - if (swap.op == qc::SWAP) { - if (config.verbose) { - std::clog << "SWAP: " << swap.first << " <-> " << swap.second - << "\n"; - } - if (!architecture->isEdgeConnected({swap.first, swap.second}) && - !architecture->isEdgeConnected({swap.second, swap.first})) { - throw QMAPException( - "Invalid SWAP: " + std::to_string(swap.first) + "<->" + - std::to_string(swap.second)); - } - qcMapped.swap(swap.first, swap.second); - results.output.swaps++; - } else if (swap.op == qc::Teleportation) { - if (config.verbose) { - std::clog << "TELE: " << swap.first << " <-> " << swap.second - << "\n"; - } - qcMapped.emplace_back( - qcMapped.getNqubits(), - qc::Targets{static_cast(swap.first), - static_cast(swap.second), - static_cast(swap.middleAncilla)}, - qc::Teleportation); - results.output.teleportations++; + for (const auto& swap : result.swaps) { + if (swap.op == qc::SWAP) { + if (config.verbose) { + std::clog << "SWAP: " << swap.first << " <-> " << swap.second + << "\n"; } - gateidx++; + if (!architecture->isEdgeConnected({swap.first, swap.second}) && + !architecture->isEdgeConnected({swap.second, swap.first})) { + throw QMAPException( + "Invalid SWAP: " + std::to_string(swap.first) + "<->" + + std::to_string(swap.second)); + } + qcMapped.swap(swap.first, swap.second); + results.output.swaps++; + } else if (swap.op == qc::Teleportation) { + if (config.verbose) { + std::clog << "TELE: " << swap.first << " <-> " << swap.second + << "\n"; + } + qcMapped.emplace_back( + qcMapped.getNqubits(), + qc::Targets{static_cast(swap.first), + static_cast(swap.second), + static_cast(swap.middleAncilla)}, + qc::Teleportation); + results.output.teleportations++; } + gateidx++; } } @@ -531,32 +535,30 @@ void HeuristicMapper::routeCircuit() { HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { auto& config = results.config; - const bool considerFidelity = config.considerFidelity; nextNodeId = 0; const std::unordered_set& consideredQubits = - (considerFidelity ? activeQubits[layer] : activeQubits2QGates[layer]); + (fidelityAwareHeur ? activeQubits[layer] : activeQubits2QGates[layer]); const SingleQubitMultiplicity& singleQubitMultiplicity = singleQubitMultiplicities.at(layer); const TwoQubitMultiplicity& twoQubitMultiplicity = twoQubitMultiplicities.at(layer); - Node node(nextNodeId++, considerFidelity, config.admissibleHeuristic); + Node node(nextNodeId++); Node bestDoneNode(0); - bool done = false; + bool validMapping = false; mapUnmappedGates(layer); node.locations = locations; node.qubits = qubits; - node.recalculateFixedCost(*architecture, singleQubitMultiplicity, - twoQubitMultiplicity); - node.updateHeuristicCost(*architecture, singleQubitMultiplicity, - twoQubitMultiplicity, consideredQubits); + recalculateFixedCost(layer, node); + updateHeuristicCost(layer, node); + updateLookaheadPenalty(layer, node); if (config.dataLoggingEnabled()) { dataLogger->logSearchNode(layer, node.id, node.parent, node.costFixed, node.costHeur, node.lookaheadPenalty, node.qubits, - node.done, node.swaps, node.depth); + node.validMapping, node.swaps, node.depth); } nodes.push(node); @@ -566,7 +568,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { const bool splittable = config.automaticLayerSplits ? isLayerSplittable(layer) : false; - while (!nodes.empty() && (!done || nodes.top().getTotalCost() < + while (!nodes.empty() && (!validMapping || nodes.top().getTotalCost() < bestDoneNode.getTotalFixedCost())) { if (splittable && expandedNodes >= config.automaticLayerSplitsNodeLimit) { if (config.dataLoggingEnabled()) { @@ -591,13 +593,13 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { return aStarMap(reverse ? layer + 1 : layer, reverse); } Node current = nodes.top(); - if (current.done) { - if (!done || + if (current.validMapping) { + if (!validMapping || current.getTotalFixedCost() < bestDoneNode.getTotalFixedCost()) { bestDoneNode = current; } - done = true; - if (!considerFidelity) { + validMapping = true; + if (tightHeur) { break; } } @@ -606,7 +608,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { ++expandedNodes; } - if (!done) { + if (!validMapping) { throw QMAPException("No viable mapping found."); } @@ -741,24 +743,13 @@ void HeuristicMapper::expandNodeAddOneSwap( const auto& config = results.config; Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, - node.swaps, node.costFixed, node.depth + 1, - node.considerFidelity, node.admissibleHeuristic); + node.swaps, node.costFixed, node.depth + 1); if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { - newNode.applySWAP(swap, *architecture, singleQubitMultiplicities.at(layer), - twoQubitMultiplicities.at(layer), consideredQubits); + applySWAP(swap, layer, newNode); } else { - newNode.applyTeleportation(swap, *architecture); - } - - newNode.updateHeuristicCost( - *architecture, singleQubitMultiplicities.at(layer), - twoQubitMultiplicities.at(layer), consideredQubits); - - // calculate heuristics for the cost of the following layers - if (config.lookahead) { - lookahead(getNextLayer(layer), newNode); + applyTeleportation(swap, layer, newNode); } nodes.push(newNode); @@ -766,88 +757,26 @@ void HeuristicMapper::expandNodeAddOneSwap( dataLogger->logSearchNode(layer, newNode.id, newNode.parent, newNode.costFixed, newNode.costHeur, newNode.lookaheadPenalty, newNode.qubits, - newNode.done, newNode.swaps, newNode.depth); + newNode.validMapping, newNode.swaps, newNode.depth); } } -void HeuristicMapper::lookahead(const std::size_t layer, - HeuristicMapper::Node& node) { - const auto& config = results.config; - auto nextLayer = layer; - double factor = config.firstLookaheadFactor; - - for (std::size_t i = 0; i < config.nrLookaheads; ++i) { - if (nextLayer == std::numeric_limits::max()) { - break; - } - - double penalty = 0.; - for (const auto& gate : layers.at(nextLayer)) { - if (gate.singleQubit()) { - continue; - } - - auto loc1 = node.locations.at(static_cast(gate.control)); - auto loc2 = node.locations.at(gate.target); - if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { - // no penalty - } else if (loc1 == DEFAULT_POSITION) { - auto min = std::numeric_limits::max(); - 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( - j, static_cast( - node.locations.at(gate.target)))); - } - } - 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) { - if (node.qubits.at(j) == DEFAULT_POSITION) { - // TODO: Consider fidelity here if available - min = std::min(min, - distanceOnArchitectureOfPhysicalQubits( - static_cast(node.locations.at( - static_cast(gate.control))), - j)); - } - } - penalty = heuristicAddition(penalty, min); - } else { - auto cost = architecture->distance( - static_cast( - node.locations.at(static_cast(gate.control))), - static_cast(node.locations.at(gate.target))); - penalty = heuristicAddition(penalty, cost); - } - } - node.lookaheadPenalty += factor * penalty; - factor *= config.lookaheadFactor; - nextLayer = getNextLayer(nextLayer); // TODO: consider single qubits here - // for better fidelity lookahead - } -} - -void HeuristicMapper::Node::applySWAP( - const Edge& swap, Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity, - const std::unordered_set& consideredQubits) { - ++nswaps; - swaps.emplace_back(); +void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { + auto& consideredQubits = activeQubits.at(layer); + auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + + ++node.nswaps; const auto q1 = qubits.at(swap.first); const auto q2 = qubits.at(swap.second); - - if (consideredQubits.find(swap.first) != consideredQubits.end() && - consideredQubits.find(swap.second) != consideredQubits.end()) { - ++sharedSwaps; - } qubits.at(swap.first) = q2; qubits.at(swap.second) = q1; + if (consideredQubits.find(swap.first) != consideredQubits.end() && + consideredQubits.find(swap.second) != consideredQubits.end()) { + ++node.sharedSwaps; + } if (q1 != -1) { locations.at(static_cast(q1)) = @@ -858,14 +787,14 @@ void HeuristicMapper::Node::applySWAP( static_cast(swap.first); } - if (arch.isEdgeConnected(swap) || - arch.isEdgeConnected(Edge{swap.second, swap.first})) { - swaps.back().emplace_back(swap.first, swap.second, qc::SWAP); + if (architecture->isEdgeConnected(swap) || + architecture->isEdgeConnected(Edge{swap.second, swap.first})) { + node.swaps.emplace_back(swap.first, swap.second, qc::SWAP); } else { throw QMAPException("Something wrong in applySWAP."); } - if (considerFidelity) { + if (fidelityAwareHeur) { std::uint16_t q1Mult = 0; std::uint16_t q2Mult = 0; if (q1 != -1) { @@ -876,11 +805,11 @@ void HeuristicMapper::Node::applySWAP( } // accounting for fidelity difference of single qubit gates (two qubit // gates are handled in the heuristic) - costFixed += - ((q2Mult - q1Mult) * arch.getSingleQubitFidelityCost(swap.first) + - (q1Mult - q2Mult) * arch.getSingleQubitFidelityCost(swap.second)); + node.costFixed += + ((q2Mult - q1Mult) * architecture->getSingleQubitFidelityCost(swap.first) + + (q1Mult - q2Mult) * architecture->getSingleQubitFidelityCost(swap.second)); // adding cost of the swap gate itself - costFixed += arch.getSwapFidelityCost(swap.first, swap.second); + node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); // add cost of newly validly mapped gates and // remove cost of now no longer validly mapped gates for (const auto& [edge, mult] : twoQubitGateMultiplicity) { @@ -888,19 +817,19 @@ void HeuristicMapper::Node::applySWAP( if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { auto physQ3 = static_cast(locations.at(q3)); auto physQ4 = static_cast(locations.at(q4)); - if (arch.isEdgeConnected(Edge{physQ3, physQ4}) || - arch.isEdgeConnected(Edge{physQ4, physQ3})) { + if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || + architecture->isEdgeConnected(Edge{physQ4, physQ3})) { // validly mapped now - if (validMappedTwoQubitGates.find(edge) == - validMappedTwoQubitGates.end()) { // not mapped validly before - costFixed += - mult.first * arch.getTwoQubitFidelityCost(physQ3, physQ4) + - mult.second * arch.getTwoQubitFidelityCost(physQ4, physQ3); - validMappedTwoQubitGates.emplace(edge); + if (node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { // not mapped validly before + node.costFixed += + mult.first * architecture->getTwoQubitFidelityCost(physQ3, physQ4) + + mult.second * architecture->getTwoQubitFidelityCost(physQ4, physQ3); + node.validMappedTwoQubitGates.emplace(edge); } } else { // not mapped validly now - if (validMappedTwoQubitGates.find(edge) != - validMappedTwoQubitGates.end()) { // mapped validly before + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { // mapped validly before auto prevPhysQ3 = physQ3; if (prevPhysQ3 == swap.first) { prevPhysQ3 = swap.second; @@ -913,28 +842,32 @@ void HeuristicMapper::Node::applySWAP( } else if (prevPhysQ4 == swap.second) { prevPhysQ4 = swap.first; } - costFixed -= mult.first * arch.getTwoQubitFidelityCost(prevPhysQ3, + node.costFixed -= mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, prevPhysQ4) + - mult.second * arch.getTwoQubitFidelityCost(prevPhysQ4, + mult.second * architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); - validMappedTwoQubitGates.erase(edge); + node.validMappedTwoQubitGates.erase(edge); } } } } } else { - if (arch.bidirectional()) { - costFixed += COST_BIDIRECTIONAL_SWAP; + if (architecture->bidirectional()) { + node.costFixed += COST_BIDIRECTIONAL_SWAP; } else { - costFixed += COST_UNIDIRECTIONAL_SWAP; + node.costFixed += COST_UNIDIRECTIONAL_SWAP; } } + + updateHeuristicCost(layer, node); + if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { + updateLookaheadPenalty(layer, node); + } } -void HeuristicMapper::Node::applyTeleportation(const Edge& swap, - Architecture& arch) { - nswaps++; - swaps.emplace_back(); + +void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { + node.nswaps++; const auto q1 = qubits.at(swap.first); const auto q2 = qubits.at(swap.second); @@ -951,7 +884,7 @@ void HeuristicMapper::Node::applyTeleportation(const Edge& swap, } std::uint16_t middleAnc = std::numeric_limits::max(); - for (const auto& qpair : arch.getTeleportationQubits()) { + for (const auto& qpair : architecture->getTeleportationQubits()) { if (swap.first == qpair.first || swap.second == qpair.first) { middleAnc = static_cast(qpair.second); } else if (swap.first == qpair.second || swap.second == qpair.second) { @@ -967,8 +900,8 @@ void HeuristicMapper::Node::applyTeleportation(const Edge& swap, std::uint16_t source = std::numeric_limits::max(); std::uint16_t target = std::numeric_limits::max(); - if (arch.isEdgeConnected({swap.first, middleAnc}) || - arch.isEdgeConnected({middleAnc, swap.first})) { + if (architecture->isEdgeConnected({swap.first, middleAnc}) || + architecture->isEdgeConnected({middleAnc, swap.first})) { source = swap.first; target = swap.second; } else { @@ -983,116 +916,202 @@ void HeuristicMapper::Node::applyTeleportation(const Edge& swap, "ancillary in teleportation."); } - swaps.back().emplace_back(source, target, middleAnc, qc::Teleportation); + node.swaps.emplace_back(source, target, middleAnc, qc::Teleportation); - costFixed += COST_TELEPORTATION; + node.costFixed += COST_TELEPORTATION; + + updateHeuristicCost(layer, node); + if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { + updateLookaheadPenalty(layer, node); + } } -void HeuristicMapper::Node::recalculateFixedCost( - const Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity) { - costFixed = 0; - if (considerFidelity) { - // adding costs of single qubit gates - for (std::uint16_t i = 0U; i < arch.getNqubits(); ++i) { - if (singleQubitGateMultiplicity.at(i) == 0) { - continue; + +void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { + if (fidelityAwareHeur) { + recalculateFixedCostFidelity(layer, node); + } else { + recalculateFixedCostNonFidelity(layer, node); + } +} + + +void HeuristicMapper::recalculateFixedCostNonFidelity(std::size_t layer, Node& node) { + node.costFixed = 0; + + for (auto& swap : node.swaps) { + if (swap.op == qc::SWAP) { + if (architecture->bidirectional()) { + node.costFixed += COST_BIDIRECTIONAL_SWAP; + } else { + node.costFixed += COST_UNIDIRECTIONAL_SWAP; } - costFixed += singleQubitGateMultiplicity.at(i) * - arch.getSingleQubitFidelityCost( - static_cast(locations.at(i))); + } else if (swap.op == qc::Teleportation) { + node.costFixed += COST_TELEPORTATION; } - // adding cost of the swap gates - for (auto& swapNode : swaps) { - for (auto& swap : swapNode) { - if (swap.op == qc::SWAP) { - costFixed += arch.getSwapFidelityCost(swap.first, swap.second); - } else if (swap.op == qc::Teleportation) { - throw QMAPException("Teleportation currently not supported for " - "noise-aware mapping"); - } - } + } +} + + +void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node) { + auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + + node.costFixed = 0; + // adding costs of single qubit gates + for (std::uint16_t i = 0U; i < architecture->getNqubits(); ++i) { + if (singleQubitGateMultiplicity.at(i) == 0) { + continue; } - validMappedTwoQubitGates.clear(); - // adding cost of two qubit gates that are already mapped next to each other - for (const auto& edgeMultiplicity : twoQubitGateMultiplicity) { - const auto& q1 = edgeMultiplicity.first.first; - const auto& q2 = edgeMultiplicity.first.second; - const auto& straightMultiplicity = edgeMultiplicity.second.first; - const auto& reverseMultiplicity = edgeMultiplicity.second.second; - - if (arch.isEdgeConnected( - {static_cast(locations.at(q1)), - static_cast(locations.at(q2))}) || - arch.isEdgeConnected({static_cast(locations.at(q2)), - static_cast( - locations.at(q1))})) { // validly mapped - costFixed += (straightMultiplicity * - arch.getTwoQubitFidelityCost( - static_cast(locations.at(q1)), - static_cast(locations.at(q2))) + - reverseMultiplicity * - arch.getTwoQubitFidelityCost( - static_cast(locations.at(q2)), - static_cast(locations.at(q1)))); - validMappedTwoQubitGates.emplace(q1, q2); - } + node.costFixed += singleQubitGateMultiplicity.at(i) * + architecture->getSingleQubitFidelityCost( + static_cast(locations.at(i))); + } + // adding cost of the swap gates + for (auto& swap : node.swaps) { + if (swap.op == qc::SWAP) { + node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); + } else if (swap.op == qc::Teleportation) { + throw QMAPException("Teleportation currently not supported for " + "noise-aware mapping"); } - // 2-qubit-gates not yet mapped next to each other are handled in the - // heuristic - } else { - for (auto& swapNode : swaps) { - for (auto& swap : swapNode) { - if (swap.op == qc::SWAP) { - if (arch.bidirectional()) { - costFixed += COST_BIDIRECTIONAL_SWAP; - } else { - costFixed += COST_UNIDIRECTIONAL_SWAP; - } - } else if (swap.op == qc::Teleportation) { - costFixed += COST_TELEPORTATION; - } - } + } + node.validMappedTwoQubitGates.clear(); + // adding cost of two qubit gates that are already mapped next to each other + for (const auto& edgeMultiplicity : twoQubitGateMultiplicity) { + const auto& q1 = edgeMultiplicity.first.first; + const auto& q2 = edgeMultiplicity.first.second; + const auto& straightMultiplicity = edgeMultiplicity.second.first; + const auto& reverseMultiplicity = edgeMultiplicity.second.second; + + if (architecture->isEdgeConnected( + {static_cast(locations.at(q1)), + static_cast(locations.at(q2))}) || + architecture->isEdgeConnected({static_cast(locations.at(q2)), + static_cast( + locations.at(q1))})) { // validly mapped + node.costFixed += (straightMultiplicity * + architecture->getTwoQubitFidelityCost( + static_cast(locations.at(q1)), + static_cast(locations.at(q2))) + + reverseMultiplicity * + architecture->getTwoQubitFidelityCost( + static_cast(locations.at(q2)), + static_cast(locations.at(q1)))); + node.validMappedTwoQubitGates.emplace(q1, q2); } } + // 2-qubit-gates not yet validly mapped are handled in the heuristic } -void HeuristicMapper::Node::updateHeuristicCost( - const Architecture& arch, - const SingleQubitMultiplicity& singleQubitGateMultiplicity, - const TwoQubitMultiplicity& twoQubitGateMultiplicity, - const std::unordered_set& consideredQubits) { - costHeur = 0.; - done = true; + +double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, Node& node) { + double costHeur = 0.; + + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + costHeur = std::max(costHeur, architecture->distance(static_cast(locations.at(q1)), + static_cast(locations.at(q2)))); + } + + return costHeur; +} + + +double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, Node& node) { + double costHeur = 0.; + + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + costHeur += architecture->distance(static_cast(locations.at(q1)), + static_cast(locations.at(q2))); + } + + return costHeur; +} + + +double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps(std::size_t layer, Node& node) { + double costHeur = 0.; + + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + costHeur += architecture->distance(static_cast(locations.at(q1)), + static_cast(locations.at(q2))); + } + + // TODO: improve heuristic further by using number of 2Q blocks (for + // gate-count-optimizing mapping qubit pairs will only travel towards + // each other, i.e. a qubit can only share 1 swap per qubit pair) + std::size_t n = activeQubits.size(); + double sharedSwapCostReduction = 0; + if (architecture->bidirectional()) { + sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + } else { + sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + } + + return std::max(0., costHeur - sharedSwapCostReduction); +} + + +double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(std::size_t layer, Node& node) { + double costMax = 0.; double costSum = 0.; + + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + const double swapCost = architecture->distance(static_cast(locations.at(q1)), static_cast(locations.at(q2))); + costSum += swapCost; + costMax = std::max(costMax, swapCost); + } + + // TODO: improve heuristic further by using number of 2Q blocks (for + // gate-count-optimizing mapping qubit pairs will only travel towards + // each other, i.e. a qubit can only share 1 swap per qubit pair) + std::size_t n = activeQubits.size(); + double sharedSwapCostReduction = 0; + if (architecture->bidirectional()) { + sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + } else { + sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + } + + return std::max(costMax, costSum - sharedSwapCostReduction); +} + +double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& node) { + auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + auto& consideredQubits = activeQubits.at(layer); + + double costHeur = 0.; + // single qubit gate savings potential by moving them to different physical // qubits with higher fidelity double savingsPotential = 0.; - if (considerFidelity) { - for (std::uint16_t logQbit = 0U; logQbit < arch.getNqubits(); ++logQbit) { - if (singleQubitGateMultiplicity.at(logQbit) == 0) { + for (std::uint16_t logQbit = 0U; logQbit < architecture->getNqubits(); ++logQbit) { + if (singleQubitGateMultiplicity.at(logQbit) == 0) { + continue; + } + double qbitSavings = 0; + const double currFidelity = architecture->getSingleQubitFidelityCost( + static_cast(locations.at(logQbit))); + for (std::uint16_t physQbit = 0U; physQbit < architecture->getNqubits(); + ++physQbit) { + if (architecture->getSingleQubitFidelityCost(physQbit) >= currFidelity) { continue; } - double qbitSavings = 0; - const double currFidelity = arch.getSingleQubitFidelityCost( - static_cast(locations.at(logQbit))); - for (std::uint16_t physQbit = 0U; physQbit < arch.getNqubits(); - ++physQbit) { - if (arch.getSingleQubitFidelityCost(physQbit) >= currFidelity) { - continue; - } - const double curSavings = - singleQubitGateMultiplicity.at(logQbit) * - (currFidelity - arch.getSingleQubitFidelityCost(physQbit)) - - arch.fidelityDistance( - static_cast(locations.at(logQbit)), physQbit, - consideredQubits.size()); - qbitSavings = std::max(qbitSavings, curSavings); - } - savingsPotential += qbitSavings; + const double curSavings = + singleQubitGateMultiplicity.at(logQbit) * + (currFidelity - architecture->getSingleQubitFidelityCost(physQbit)) - + architecture->fidelityDistance( + static_cast(locations.at(logQbit)), physQbit, + consideredQubits.size()); + qbitSavings = std::max(qbitSavings, curSavings); } + savingsPotential += qbitSavings; } // iterating over all virtual qubit pairs, that share a gate on the @@ -1102,82 +1121,199 @@ void HeuristicMapper::Node::updateHeuristicCost( const auto& [straightMultiplicity, reverseMultiplicity] = multiplicity; - const bool edgeDone = - (arch.isEdgeConnected({static_cast(locations.at(q1)), - static_cast(locations.at(q2))}) || - arch.isEdgeConnected({static_cast(locations.at(q2)), - static_cast(locations.at(q1))})); - // only if all qubit pairs are mapped next to each other the mapping - // is complete - if (!edgeDone) { - done = false; + const bool edgeDone = (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end() || + node.validMappedTwoQubitGates.find({q1, q2}) != + node.validMappedTwoQubitGates.end()); + + // find the optimal edge, to which to remap the given virtual qubit + // pair and take the cost of moving it there via swaps plus the + // fidelity cost of executing all their shared gates on that edge + // as the qubit pairs cost + double swapCost = std::numeric_limits::max(); + for (const auto& [q3, q4] : architecture->getCouplingMap()) { + swapCost = std::min( + swapCost, + straightMultiplicity * architecture->getTwoQubitFidelityCost(q3, q4) + + reverseMultiplicity * architecture->getTwoQubitFidelityCost(q4, q3) + + architecture->fidelityDistance( + static_cast(locations.at(q1)), q3, + consideredQubits.size()) + + architecture->fidelityDistance( + static_cast(locations.at(q2)), q4, + consideredQubits.size())); + swapCost = std::min( + swapCost, + straightMultiplicity * architecture->getTwoQubitFidelityCost(q4, q3) + + reverseMultiplicity * architecture->getTwoQubitFidelityCost(q3, q4) + + architecture->fidelityDistance( + static_cast(locations.at(q2)), q3, + consideredQubits.size()) + + architecture->fidelityDistance( + static_cast(locations.at(q1)), q4, + consideredQubits.size())); } - if (!considerFidelity) { - const double swapCost = arch.distance(static_cast(locations.at(q1)), - static_cast(locations.at(q2))); - costHeur = std::max(costHeur, swapCost); - costSum += swapCost; + if (edgeDone) { + const double currEdgeCost = + (straightMultiplicity * + architecture->getTwoQubitFidelityCost( + static_cast(locations.at(q1)), + static_cast(locations.at(q2))) + + reverseMultiplicity * + architecture->getTwoQubitFidelityCost( + static_cast(locations.at(q2)), + static_cast(locations.at(q1)))); + savingsPotential += (currEdgeCost - swapCost); } else { - // find the optimal edge, to which to remap the given virtual qubit - // pair and take the cost of moving it there via swaps plus the - // fidelity cost of executing all their shared gates on that edge - // as the qubit pairs cost - double swapCost = std::numeric_limits::max(); - for (const auto& [q3, q4] : arch.getCouplingMap()) { - swapCost = std::min( - swapCost, - straightMultiplicity * arch.getTwoQubitFidelityCost(q3, q4) + - reverseMultiplicity * arch.getTwoQubitFidelityCost(q4, q3) + - arch.fidelityDistance( - static_cast(locations.at(q1)), q3, - consideredQubits.size()) + - arch.fidelityDistance( - static_cast(locations.at(q2)), q4, - consideredQubits.size())); - swapCost = std::min( - swapCost, - straightMultiplicity * arch.getTwoQubitFidelityCost(q4, q3) + - reverseMultiplicity * arch.getTwoQubitFidelityCost(q3, q4) + - arch.fidelityDistance( - static_cast(locations.at(q2)), q3, - consideredQubits.size()) + - arch.fidelityDistance( - static_cast(locations.at(q1)), q4, - consideredQubits.size())); - } + costHeur += swapCost; + } + } + + return costHeur - savingsPotential; +} - if (edgeDone) { - const double currEdgeCost = - (straightMultiplicity * - arch.getTwoQubitFidelityCost( - static_cast(locations.at(q1)), - static_cast(locations.at(q2))) + - reverseMultiplicity * - arch.getTwoQubitFidelityCost( - static_cast(locations.at(q2)), - static_cast(locations.at(q1)))); - savingsPotential += (currEdgeCost - swapCost); - } else { - costHeur += swapCost; - } + +void HeuristicMapper::updateHeuristicCost(std::size_t layer, Node& node) { + // the mapping is valid, only if all qubit pairs are mapped next to each other + node.validMapping = (node.validMappedTwoQubitGates.size() == + twoQubitMultiplicities.at(layer).size()); + + switch (results.config.heuristic) { + case Heuristic::GateCountMaxDistance: + node.costHeur = heuristicGateCountMaxDistance(layer, node); + break; + case Heuristic::GateCountSumDistance: + node.costHeur = heuristicGateCountSumDistance(layer, node); + break; + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + node.costHeur = heuristicGateCountSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + node.costHeur = heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::FidelityBestLocation: + node.costHeur = heuristicFidelityBestLocation(layer, node); + break; + default: + throw QMAPException("Unknown heuristic."); + } +} + + +void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicMapper::Node& node) { + const auto& config = results.config; + auto nextLayer = getNextLayer(layer); + double factor = config.firstLookaheadFactor; + + for (std::size_t i = 0; i < config.nrLookaheads; ++i) { + if (nextLayer == std::numeric_limits::max()) { + break; } + + double penalty = 0.; + switch (config.lookaheadHeuristic) + { + case LookaheadHeuristic::GateCountMaxDistance: + penalty = lookaheadGateCountMaxDistance(nextLayer, node); + break; + case LookaheadHeuristic::GateCountSumDistance: + penalty = lookaheadGateCountSumDistance(nextLayer, node); + break; + default: + break; + } + + node.lookaheadPenalty += factor * penalty; + factor *= config.lookaheadFactor; + nextLayer = getNextLayer(nextLayer); // TODO: consider single qubits here + // for better fidelity lookahead } +} + +double HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, HeuristicMapper::Node& node) { + double penalty = 0.; - if(!considerFidelity){ - if (!admissibleHeuristic) { - costHeur = costSum; - } else { - std::size_t n = consideredQubits.size(); - double sharedSwapCostReduction = 0; - if (arch.bidirectional()) { - sharedSwapCostReduction = ((n-1)*n/2 - sharedSwaps)*COST_BIDIRECTIONAL_SWAP; - } else { - sharedSwapCostReduction = ((n-1)*n/2 - sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + + auto loc1 = node.locations.at(q1); + auto loc2 = node.locations.at(q2); + if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { + // no penalty + } else if (loc1 == DEFAULT_POSITION) { + auto min = std::numeric_limits::max(); + 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( + j, static_cast(loc2))); + } + } + penalty = std::max(penalty, min); + } else if (loc2 == DEFAULT_POSITION) { + auto min = std::numeric_limits::max(); + 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( + static_cast(loc1), + j)); + } } - costHeur = std::max(costHeur, costSum - sharedSwapCostReduction); + penalty = std::max(penalty, min); + } else { + auto cost = architecture->distance( + static_cast(loc1), + static_cast(loc2)); + penalty = std::max(penalty, cost); } } - costHeur -= savingsPotential; + return penalty; } + + +double HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, HeuristicMapper::Node& node) { + double penalty = 0.; + + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + const auto& [q1, q2] = edge; + + auto loc1 = node.locations.at(q1); + auto loc2 = node.locations.at(q2); + if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { + // no penalty + } else if (loc1 == DEFAULT_POSITION) { + auto min = std::numeric_limits::max(); + 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( + j, static_cast(loc2))); + } + } + penalty += min; + } else if (loc2 == DEFAULT_POSITION) { + auto min = std::numeric_limits::max(); + 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( + static_cast(loc1), + j)); + } + } + penalty = min; + } else { + auto cost = architecture->distance( + static_cast(loc1), + static_cast(loc2)); + penalty = cost; + } + } + + return penalty; +} \ No newline at end of file diff --git a/src/mqt/qmap/compile.py b/src/mqt/qmap/compile.py index 569e939a7..e406778c5 100644 --- a/src/mqt/qmap/compile.py +++ b/src/mqt/qmap/compile.py @@ -23,7 +23,9 @@ Configuration, Encoding, InitialLayout, + Heuristic, Layering, + LookaheadHeuristic, MappingResults, Method, SwapReduction, @@ -60,12 +62,13 @@ def compile( # noqa: A001 arch: str | Arch | Architecture | Backend | None, calibration: str | BackendProperties | Target | None = None, method: str | Method = "heuristic", - consider_fidelity: bool = False, + heuristic: str | Heuristic = "gate_count_max_distance", initial_layout: str | InitialLayout = "dynamic", iterative_bidirectional_routing_passes: int | None = None, layering: str | Layering = "individual_gates", automatic_layer_splits_node_limit: int | None = 5000, - lookaheads: int | None = 15, + lookahead_heuristic: str | LookaheadHeuristic | None = "gate_count_max_distance", + lookaheads: int = 15, lookahead_factor: float = 0.5, use_teleportation: bool = False, teleportation_fake: bool = False, @@ -93,11 +96,12 @@ def compile( # noqa: A001 arch: The architecture to map to. calibration: The calibration to use. method: The mapping method to use. Either "heuristic" or "exact". Defaults to "heuristic". - consider_fidelity: Whether to consider the fidelity of the gates. Defaults to False. + heuristic: The heuristic function to use for the routing search. Defaults to "gate_count_max_distance". initial_layout: The initial layout to use. Defaults to "dynamic". iterative_bidirectional_routing_passes: Number of iterative bidirectional routing passes to perform or None to disable. Defaults to None. layering: The layering strategy to use. Defaults to "individual_gates". automatic_layer_splits_node_limit: The number of expanded nodes after which to split a layer or None to disable automatic layer splitting. Defaults to 5000. + lookahead_heuristic: The heuristic function to use as a lookahead penalty during search or None to disable lookahead. Defaults to "gate_count_max_distance". lookaheads: The number of lookaheads to be used or None if no lookahead should be used. Defaults to 15. lookahead_factor: The rate at which the contribution of future layers to the lookahead decreases. Defaults to 0.5. encoding: The encoding to use for the AMO and exactly one constraints. Defaults to "naive". @@ -134,7 +138,7 @@ def compile( # noqa: A001 config = Configuration() config.method = Method(method) - config.consider_fidelity = consider_fidelity + config.heuristic = Heuristic(heuristic) config.initial_layout = InitialLayout(initial_layout) if iterative_bidirectional_routing_passes is None: config.iterative_bidirectional_routing = False @@ -166,12 +170,12 @@ def compile( # noqa: A001 config.debug = debug if visualizer is not None and visualizer.data_logging_path is not None: config.data_logging_path = visualizer.data_logging_path - if lookaheads is None: + if lookahead_heuristic is None: + config.lookahead_heuristic = LookaheadHeuristic.none config.lookaheads = 0 - config.lookahead = False else: + config.lookahead_heuristic = LookaheadHeuristic(lookahead_heuristic) config.lookaheads = lookaheads - config.lookahead = True config.lookahead_factor = lookahead_factor results = map(circ, architecture, config) diff --git a/src/mqt/qmap/pyqmap.pyi b/src/mqt/qmap/pyqmap.pyi index 7d13daa8e..c9b761ceb 100644 --- a/src/mqt/qmap/pyqmap.pyi +++ b/src/mqt/qmap/pyqmap.pyi @@ -111,8 +111,7 @@ class CommanderGrouping: class Configuration: add_measurements_to_mapped_circuit: bool add_barriers_between_layers: bool - admissible_heuristic: bool - consider_fidelity: bool + heuristic: Heuristic commander_grouping: CommanderGrouping enable_limits: bool encoding: Encoding @@ -124,7 +123,7 @@ class Configuration: layering: Layering automatic_layer_splits: bool automatic_layer_splits_node_limit: int - lookahead: bool + lookahead_heuristic: LookaheadHeuristic lookahead_factor: float lookaheads: int method: Method @@ -192,6 +191,54 @@ class InitialLayout: @property def value(self) -> int: ... +class Heuristic: + __members__: ClassVar[dict[InitialLayout, int]] = ... # read-only + gate_count_max_distance: ClassVar[InitialLayout] = ... + gate_count_sum_distance: ClassVar[InitialLayout] = ... + gate_count_sum_distance_minus_shared_swaps: ClassVar[InitialLayout] = ... + gate_count_max_distance_or_sum_distance_minus_shared_swaps: ClassVar[InitialLayout] = ... + fidelity_best_location: ClassVar[InitialLayout] = ... + @overload + def __init__(self, value: int) -> None: ... + @overload + def __init__(self, arg0: str) -> None: ... + @overload + def __init__(self, arg0: InitialLayout) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __getstate__(self) -> int: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __int__(self) -> int: ... + def __ne__(self, other: object) -> bool: ... + def __setstate__(self, state: int) -> None: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + +class LookaheadHeuristic: + __members__: ClassVar[dict[InitialLayout, int]] = ... # read-only + none: ClassVar[InitialLayout] = ... + gate_count_max_distance: ClassVar[InitialLayout] = ... + gate_count_sum_distance: ClassVar[InitialLayout] = ... + @overload + def __init__(self, value: int) -> None: ... + @overload + def __init__(self, arg0: str) -> None: ... + @overload + def __init__(self, arg0: InitialLayout) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __getstate__(self) -> int: ... + def __hash__(self) -> int: ... + def __index__(self) -> int: ... + def __int__(self) -> int: ... + def __ne__(self, other: object) -> bool: ... + def __setstate__(self, state: int) -> None: ... + @property + def name(self) -> str: ... + @property + def value(self) -> int: ... + class Layering: __members__: ClassVar[dict[Layering, int]] = ... # read-only disjoint_qubits: ClassVar[Layering] = ... diff --git a/src/python/bindings.cpp b/src/python/bindings.cpp index 32ca48b41..1ce4d1104 100644 --- a/src/python/bindings.cpp +++ b/src/python/bindings.cpp @@ -122,6 +122,30 @@ PYBIND11_MODULE(pyqmap, m) { .def(py::init([](const std::string& str) -> InitialLayout { return initialLayoutFromString(str); })); + + // Heuristic function + py::enum_(m, "Heuristic") + .value("gate_count_max_distance", Heuristic::GateCountMaxDistance) + .value("gate_count_sum_distance", Heuristic::GateCountSumDistance) + .value("gate_count_sum_distance_minus_shared_swaps", Heuristic::GateCountSumDistanceMinusSharedSwaps) + .value("gate_count_max_distance_or_sum_distance_minus_shared_swaps", Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps) + .value("fidelity_best_location", Heuristic::FidelityBestLocation) + .export_values() + // allow construction from string + .def(py::init([](const std::string& str) -> Heuristic { + return heuristicFromString(str); + })); + + // Lookahead heuristic function + py::enum_(m, "LookaheadHeuristic") + .value("none", LookaheadHeuristic::None) + .value("gate_count_max_distance", LookaheadHeuristic::GateCountMaxDistance) + .value("gate_count_sum_distance", LookaheadHeuristic::GateCountSumDistance) + .export_values() + // allow construction from string + .def(py::init([](const std::string& str) -> LookaheadHeuristic { + return lookaheadHeuristicFromString(str); + })); // Gate clustering / layering strategy py::enum_(m, "Layering") @@ -178,6 +202,7 @@ PYBIND11_MODULE(pyqmap, m) { "Configuration options for the MQT QMAP quantum circuit mapping tool") .def(py::init<>()) .def_readwrite("method", &Configuration::method) + .def_readwrite("heuristic", &Configuration::heuristic) .def_readwrite("verbose", &Configuration::verbose) .def_readwrite("debug", &Configuration::debug) .def_readwrite("data_logging_path", &Configuration::dataLoggingPath) @@ -191,10 +216,7 @@ PYBIND11_MODULE(pyqmap, m) { &Configuration::iterativeBidirectionalRouting) .def_readwrite("iterative_bidirectional_routing_passes", &Configuration::iterativeBidirectionalRoutingPasses) - .def_readwrite("lookahead", &Configuration::lookahead) - .def_readwrite("admissible_heuristic", - &Configuration::admissibleHeuristic) - .def_readwrite("consider_fidelity", &Configuration::considerFidelity) + .def_readwrite("lookahead_heuristic", &Configuration::lookaheadHeuristic) .def_readwrite("lookaheads", &Configuration::nrLookaheads) .def_readwrite("first_lookahead_factor", &Configuration::firstLookaheadFactor) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index abe262d11..2df8b3565 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -97,12 +97,12 @@ TEST(Functionality, HeuristicBenchmark) { const auto mapper = std::make_unique(qc, architecture); Configuration settings{}; - settings.admissibleHeuristic = true; + settings.heuristic = Heuristic::GateCountMaxDistance; settings.layering = Layering::DisjointQubits; settings.initialLayout = InitialLayout::Identity; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; - settings.lookahead = false; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.debug = true; mapper->map(settings); auto& result = mapper->getResults(); @@ -175,18 +175,23 @@ TEST(Functionality, InvalidSettings) { HeuristicMapper mapper(qc, arch); auto config = Configuration{}; config.method = Method::Heuristic; + config.heuristic = Heuristic::GateCountMaxDistance; + config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; + // invalid layering config.layering = Layering::OddGates; EXPECT_THROW(mapper.map(config), QMAPException); config.layering = Layering::QubitTriangle; EXPECT_THROW(mapper.map(config), QMAPException); config.layering = Layering::IndividualGates; - config.considerFidelity = true; - config.lookahead = true; + // fidelity-aware heuristic with non-fidelity-aware lookahead heuristic + config.heuristic = Heuristic::FidelityBestLocation; EXPECT_THROW(mapper.map(config), QMAPException); - config.lookahead = false; + config.lookaheadHeuristic = LookaheadHeuristic::None; + // fidelity-aware heuristic with teleportation config.teleportationQubits = 2; EXPECT_THROW(mapper.map(config), QMAPException); config.teleportationQubits = 0; + // valid settings EXPECT_NO_THROW(mapper.map(config)); } @@ -244,6 +249,7 @@ TEST(Functionality, InvalidCircuits) { EXPECT_THROW(mapper3.map(config), QMAPException); } +// TODO: replace with principal admissibility test TEST(Functionality, HeuristicAdmissibility) { Architecture architecture{}; const CouplingMap cm = {{0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, @@ -361,17 +367,16 @@ TEST(Functionality, DataLogger) { qc.setName("test_circ"); Configuration settings{}; - settings.admissibleHeuristic = true; + settings.heuristic = Heuristic::GateCountMaxDistance; settings.layering = Layering::IndividualGates; settings.initialLayout = InitialLayout::Identity; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; - settings.lookahead = true; + settings.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; settings.nrLookaheads = 1; settings.firstLookaheadFactor = 0.5; settings.lookaheadFactor = 0.9; settings.debug = true; - settings.considerFidelity = false; settings.useTeleportation = false; // setting data logging path to enable data logging settings.dataLoggingPath = "test_log"; @@ -460,14 +465,12 @@ TEST(Functionality, DataLogger) { EXPECT_EQ(configJson["pre_mapping_optimizations"], settings.preMappingOptimizations); const auto& heuristicSettingsJson = configJson["settings"]; - EXPECT_EQ(heuristicSettingsJson["admissible_heuristic"], - settings.admissibleHeuristic); - EXPECT_EQ(heuristicSettingsJson["consider_fidelity"], - settings.considerFidelity); + EXPECT_EQ(heuristicSettingsJson["heuristic"], toString(settings.heuristic)); EXPECT_EQ(heuristicSettingsJson["initial_layout"], toString(settings.initialLayout)); - if (settings.lookahead) { + if (settings.lookaheadHeuristic != LookaheadHeuristic::None) { const auto& lookaheadJson = heuristicSettingsJson["lookahead"]; + EXPECT_EQ(lookaheadJson["heuristic"], toString(settings.lookaheadHeuristic)); EXPECT_EQ(lookaheadJson["factor"], settings.lookaheadFactor); EXPECT_EQ(lookaheadJson["first_factor"], settings.firstLookaheadFactor); EXPECT_EQ(lookaheadJson["lookaheads"], settings.nrLookaheads); @@ -1045,10 +1048,10 @@ INSTANTIATE_TEST_SUITE_P( TEST_P(HeuristicTestFidelity, Identity) { Configuration settings{}; - settings.layering = Layering::DisjointQubits; - settings.initialLayout = InitialLayout::Identity; - settings.considerFidelity = true; - settings.lookahead = false; + settings.layering = Layering::DisjointQubits; + settings.initialLayout = InitialLayout::Identity; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; mapper->map(settings); mapper->dumpResult(GetParam() + "_heuristic_london_fidelity_identity.qasm"); mapper->printResult(std::cout); @@ -1057,10 +1060,10 @@ TEST_P(HeuristicTestFidelity, Identity) { TEST_P(HeuristicTestFidelity, Static) { Configuration settings{}; - settings.layering = Layering::DisjointQubits; - settings.initialLayout = InitialLayout::Static; - settings.considerFidelity = true; - settings.lookahead = false; + settings.layering = Layering::DisjointQubits; + settings.initialLayout = InitialLayout::Static; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; mapper->map(settings); mapper->dumpResult(GetParam() + "_heuristic_london_fidelity_static.qasm"); mapper->printResult(std::cout); @@ -1069,10 +1072,10 @@ TEST_P(HeuristicTestFidelity, Static) { TEST_P(HeuristicTestFidelity, Dynamic) { Configuration settings{}; - settings.layering = Layering::DisjointQubits; - settings.initialLayout = InitialLayout::Dynamic; - settings.considerFidelity = true; - settings.lookahead = false; + settings.layering = Layering::DisjointQubits; + settings.initialLayout = InitialLayout::Dynamic; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; mapper->map(settings); mapper->dumpResult(GetParam() + "_heuristic_london_fidelity_static.qasm"); mapper->printResult(std::cout); @@ -1081,10 +1084,10 @@ TEST_P(HeuristicTestFidelity, Dynamic) { TEST_P(HeuristicTestFidelity, NoFidelity) { Configuration settings{}; - settings.layering = Layering::DisjointQubits; - settings.initialLayout = InitialLayout::Static; - settings.considerFidelity = true; - settings.lookahead = false; + settings.layering = Layering::DisjointQubits; + settings.initialLayout = InitialLayout::Static; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; EXPECT_THROW(nonFidelityMapper->map(settings), QMAPException); } @@ -1136,15 +1139,14 @@ TEST(HeuristicTestFidelity, RemapSingleQubit) { auto mapper = std::make_unique(qc, architecture); Configuration settings{}; - settings.admissibleHeuristic = true; settings.layering = Layering::Disjoint2qBlocks; settings.initialLayout = InitialLayout::Identity; - settings.considerFidelity = true; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; settings.verbose = true; settings.swapOnFirstLayer = true; - settings.lookahead = false; mapper->map(settings); mapper->dumpResult("remap_single_qubit_mapped.qasm"); mapper->printResult(std::cout); @@ -1222,15 +1224,14 @@ TEST(HeuristicTestFidelity, QubitRideAlong) { auto mapper = std::make_unique(qc, architecture); Configuration settings{}; - settings.admissibleHeuristic = true; settings.layering = Layering::Disjoint2qBlocks; settings.initialLayout = InitialLayout::Identity; - settings.considerFidelity = true; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; settings.verbose = true; settings.swapOnFirstLayer = true; - settings.lookahead = false; mapper->map(settings); mapper->dumpResult("qubit_ride_along_mapped.qasm"); mapper->printResult(std::cout); @@ -1285,15 +1286,14 @@ TEST(HeuristicTestFidelity, SingleQubitsCompete) { auto mapper = std::make_unique(qc, architecture); Configuration settings{}; - settings.admissibleHeuristic = true; settings.layering = Layering::Disjoint2qBlocks; settings.initialLayout = InitialLayout::Identity; - settings.considerFidelity = true; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; settings.verbose = true; settings.swapOnFirstLayer = true; - settings.lookahead = false; mapper->map(settings); mapper->dumpResult("single_qubits_compete.qasm"); mapper->printResult(std::cout); @@ -1404,14 +1404,13 @@ TEST(HeuristicTestFidelity, LayerSplitting) { Configuration settings{}; settings.verbose = true; - settings.admissibleHeuristic = true; settings.layering = Layering::Disjoint2qBlocks; settings.initialLayout = InitialLayout::Identity; - settings.considerFidelity = true; + settings.heuristic = Heuristic::FidelityBestLocation; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; settings.swapOnFirstLayer = true; - settings.lookahead = false; settings.automaticLayerSplits = true; settings.automaticLayerSplitsNodeLimit = 1; // force splittings after 1st expanded node until layers are From 4bfb646243989c567d6f3675edbeb92be07956ff Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Tue, 2 Jan 2024 03:02:56 +0100 Subject: [PATCH 04/47] restructure tests --- include/configuration/Configuration.hpp | 4 +- include/heuristic/HeuristicMapper.hpp | 35 +- src/heuristic/HeuristicMapper.cpp | 268 ++++++----- test/test_heuristic.cpp | 597 ++++++++++++++++-------- 4 files changed, 577 insertions(+), 327 deletions(-) diff --git a/include/configuration/Configuration.hpp b/include/configuration/Configuration.hpp index 2efbf78e9..e608b9b32 100644 --- a/include/configuration/Configuration.hpp +++ b/include/configuration/Configuration.hpp @@ -23,7 +23,7 @@ struct Configuration { // which method to use Method method = Method::Heuristic; - Heuristic heuristic = Heuristic::SwapCountMaxDistance; + Heuristic heuristic = Heuristic::GateCountMaxDistance; bool preMappingOptimizations = true; bool postMappingOptimizations = true; @@ -59,7 +59,7 @@ struct Configuration { std::size_t iterativeBidirectionalRoutingPasses = 0; // lookahead scheme settings - LookaheadHeuristic lookaheadHeuristic = LookaheadHeuristic::None; + LookaheadHeuristic lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; std::size_t nrLookaheads = 15; double firstLookaheadFactor = 0.75; double lookaheadFactor = 0.5; diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index dfe3a0f44..9acda2e1a 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -58,32 +58,33 @@ class HeuristicMapper : public Mapper { /** heuristic cost expected for future swaps needed in later circuit layers * (further layers contribute less) */ double lookaheadPenalty = 0.; - /** number of swaps used to get from mapping after last layer to the current - * mapping */ - std::size_t nswaps = 0; /** number of swaps that were shared with another considered qubit */ std::size_t sharedSwaps = 0; /** depth in search tree (starting with 0 at the root) */ std::size_t depth = 0; std::size_t parent = 0; - std::size_t id; + std::size_t id = 0; /** true if all qubit pairs are mapped next to each other on the * architecture */ bool validMapping = true; - + explicit Node() = default; explicit Node(std::size_t nodeId) : id(nodeId) {}; Node(std::size_t nodeId, std::size_t parentId, const std::array& q, const std::array& loc, const std::vector& sw = {}, + const std::set& valid2QGates = {}, const double initCostFixed = 0, const std::size_t searchDepth = 0) : costFixed(initCostFixed), depth(searchDepth), parent(parentId), id(nodeId) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); std::copy(sw.begin(), sw.end(), std::back_inserter(swaps)); + std::copy(valid2QGates.begin(), valid2QGates.end(), + std::inserter(validMappedTwoQubitGates, + validMappedTwoQubitGates.begin())); } /** @@ -108,7 +109,11 @@ class HeuristicMapper : public Mapper { out << "\t\t\"heuristic\": " << costHeur << ",\n"; out << "\t\t\"lookahead_penalty\": " << lookaheadPenalty << "\n"; out << "\t},\n"; - out << "\t\"nswaps\": " << nswaps << "\n}\n"; + out << "\t\"swaps\": "; + for (const auto& swap : swaps) { + out << "(" << swap.first << " " << swap.second << ") "; + } + out << "\n}\n"; return out; } }; @@ -231,8 +236,7 @@ class HeuristicMapper : public Mapper { * of logical qubits in the current layer */ void expandNodeAddOneSwap( - const Edge& swap, Node& node, std::size_t layer, - const std::unordered_set& consideredQubits); + const Edge& swap, Node& node, std::size_t layer); /** * @brief applies an in-place swap of 2 virtual qubits in the given node and recalculates all costs accordingly @@ -271,10 +275,9 @@ class HeuristicMapper : public Mapper { /** * @brief recalculates the gate-count-optimizing fixed cost of the node from the current mapping and swaps * - * @param layer index of current circuit layer * @param node search node for which to recalculate the fixed cost */ - void recalculateFixedCostNonFidelity(std::size_t layer, Node& node); + void recalculateFixedCostNonFidelity(Node& node); /** * @brief calculates the heuristic cost of the current mapping in the node @@ -413,6 +416,13 @@ inline bool operator<(const HeuristicMapper::Node& x, inline bool operator>(const HeuristicMapper::Node& x, const HeuristicMapper::Node& y) { + // order nodes by costFixed + costHeur + lookaheadPenalty (increasing) + // then by validMapping (true before false) + // then by costHeur + lookaheadPenalty (increasing), + // equivalent to ordering by costFixed (decreasing) + // then by the amount of validly mapped 2q gates (decreasing) + // then by the qubit mapping (lexicographically) as an arbitrary but + // consistent tie-breaker const auto xcost = x.getTotalCost(); const auto ycost = y.getTotalCost(); if (std::abs(xcost - ycost) > 1e-6) { @@ -431,5 +441,10 @@ inline bool operator>(const HeuristicMapper::Node& x, if (std::abs(xheur - yheur) > 1e-6) { return xheur > yheur; } + + if (x.validMappedTwoQubitGates.size() != y.validMappedTwoQubitGates.size()) { + return x.validMappedTwoQubitGates.size() < y.validMappedTwoQubitGates.size(); + } + return x < y; } diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 1364b9f04..299ea230e 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -723,14 +723,14 @@ void HeuristicMapper::expandNode( auto q1 = node.qubits.at(edge.first); auto q2 = node.qubits.at(edge.second); if (q2 == -1 || q1 == -1) { - expandNodeAddOneSwap(edge, node, layer, consideredQubits); + expandNodeAddOneSwap(edge, node, layer); } else if (!usedSwaps.at(static_cast(q1)) .at(static_cast(q2))) { usedSwaps.at(static_cast(q1)) .at(static_cast(q2)) = true; usedSwaps.at(static_cast(q2)) .at(static_cast(q1)) = true; - expandNodeAddOneSwap(edge, node, layer, consideredQubits); + expandNodeAddOneSwap(edge, node, layer); } } } @@ -738,12 +738,10 @@ void HeuristicMapper::expandNode( } void HeuristicMapper::expandNodeAddOneSwap( - const Edge& swap, Node& node, const std::size_t layer, - const std::unordered_set& consideredQubits) { - const auto& config = results.config; + const Edge& swap, Node& node, const std::size_t layer) { Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, - node.swaps, node.costFixed, node.depth + 1); + node.swaps, node.validMappedTwoQubitGates, node.costFixed, node.depth + 1); if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { @@ -765,25 +763,23 @@ void HeuristicMapper::expandNodeAddOneSwap( void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { auto& consideredQubits = activeQubits.at(layer); auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - ++node.nswaps; - const auto q1 = qubits.at(swap.first); - const auto q2 = qubits.at(swap.second); + const auto q1 = node.qubits.at(swap.first); + const auto q2 = node.qubits.at(swap.second); - qubits.at(swap.first) = q2; - qubits.at(swap.second) = q1; + node.qubits.at(swap.first) = q2; + node.qubits.at(swap.second) = q1; if (consideredQubits.find(swap.first) != consideredQubits.end() && consideredQubits.find(swap.second) != consideredQubits.end()) { ++node.sharedSwaps; } if (q1 != -1) { - locations.at(static_cast(q1)) = + node.locations.at(static_cast(q1)) = static_cast(swap.second); } if (q2 != -1) { - locations.at(static_cast(q2)) = + node.locations.at(static_cast(q2)) = static_cast(swap.first); } @@ -793,6 +789,49 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) } else { throw QMAPException("Something wrong in applySWAP."); } + + // check if swap created or destroyed any valid mappings of qubit pairs + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + auto [q3, q4] = edge; + if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { + auto physQ3 = static_cast(node.locations.at(q3)); + auto physQ4 = static_cast(node.locations.at(q4)); + if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || + architecture->isEdgeConnected(Edge{physQ4, physQ3})) { + // validly mapped now + if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { // not mapped validly before + // add cost of newly validly mapped gates + node.costFixed += + mult.first * architecture->getTwoQubitFidelityCost(physQ3, physQ4) + + mult.second * architecture->getTwoQubitFidelityCost(physQ4, physQ3); + } + node.validMappedTwoQubitGates.emplace(edge); + } else { // not mapped validly now + if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { // mapped validly before + // remove cost of now no longer validly mapped gates + auto prevPhysQ3 = physQ3; + if (prevPhysQ3 == swap.first) { + prevPhysQ3 = swap.second; + } else if (prevPhysQ3 == swap.second) { + prevPhysQ3 = swap.first; + } + auto prevPhysQ4 = physQ4; + if (prevPhysQ4 == swap.first) { + prevPhysQ4 = swap.second; + } else if (prevPhysQ4 == swap.second) { + prevPhysQ4 = swap.first; + } + node.costFixed -= mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, + prevPhysQ4) + + mult.second * architecture->getTwoQubitFidelityCost(prevPhysQ4, + prevPhysQ3); + } + node.validMappedTwoQubitGates.erase(edge); + } + } + } if (fidelityAwareHeur) { std::uint16_t q1Mult = 0; @@ -810,47 +849,6 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) (q1Mult - q2Mult) * architecture->getSingleQubitFidelityCost(swap.second)); // adding cost of the swap gate itself node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); - // add cost of newly validly mapped gates and - // remove cost of now no longer validly mapped gates - for (const auto& [edge, mult] : twoQubitGateMultiplicity) { - auto [q3, q4] = edge; - if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { - auto physQ3 = static_cast(locations.at(q3)); - auto physQ4 = static_cast(locations.at(q4)); - if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || - architecture->isEdgeConnected(Edge{physQ4, physQ3})) { - // validly mapped now - if (node.validMappedTwoQubitGates.find(edge) == - node.validMappedTwoQubitGates.end()) { // not mapped validly before - node.costFixed += - mult.first * architecture->getTwoQubitFidelityCost(physQ3, physQ4) + - mult.second * architecture->getTwoQubitFidelityCost(physQ4, physQ3); - node.validMappedTwoQubitGates.emplace(edge); - } - } else { // not mapped validly now - if (node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { // mapped validly before - auto prevPhysQ3 = physQ3; - if (prevPhysQ3 == swap.first) { - prevPhysQ3 = swap.second; - } else if (prevPhysQ3 == swap.second) { - prevPhysQ3 = swap.first; - } - auto prevPhysQ4 = physQ4; - if (prevPhysQ4 == swap.first) { - prevPhysQ4 = swap.second; - } else if (prevPhysQ4 == swap.second) { - prevPhysQ4 = swap.first; - } - node.costFixed -= mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, - prevPhysQ4) + - mult.second * architecture->getTwoQubitFidelityCost(prevPhysQ4, - prevPhysQ3); - node.validMappedTwoQubitGates.erase(edge); - } - } - } - } } else { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -867,19 +865,18 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { - node.nswaps++; - const auto q1 = qubits.at(swap.first); - const auto q2 = qubits.at(swap.second); + const auto q1 = node.qubits.at(swap.first); + const auto q2 = node.qubits.at(swap.second); - qubits.at(swap.first) = q2; - qubits.at(swap.second) = q1; + node.qubits.at(swap.first) = q2; + node.qubits.at(swap.second) = q1; if (q1 != -1) { - locations.at(static_cast(q1)) = + node.locations.at(static_cast(q1)) = static_cast(swap.second); } if (q2 != -1) { - locations.at(static_cast(q2)) = + node.locations.at(static_cast(q2)) = static_cast(swap.first); } @@ -920,6 +917,22 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, No node.costFixed += COST_TELEPORTATION; + // check if swap created or destroyed any valid mappings of qubit pairs + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + auto [q3, q4] = edge; + if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { + auto physQ3 = static_cast(node.locations.at(q3)); + auto physQ4 = static_cast(node.locations.at(q4)); + if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || + architecture->isEdgeConnected(Edge{physQ4, physQ3})) { + // validly mapped now + node.validMappedTwoQubitGates.emplace(edge); + } else { // not mapped validly now + node.validMappedTwoQubitGates.erase(edge); + } + } + } + updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { updateLookaheadPenalty(layer, node); @@ -928,15 +941,29 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, No void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { + node.validMappedTwoQubitGates.clear(); + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + const auto [q1, q2] = edge; + + if (architecture->isEdgeConnected( + {static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))}) || + architecture->isEdgeConnected({static_cast(node.locations.at(q2)), + static_cast( + node.locations.at(q1))})) { // validly mapped + node.validMappedTwoQubitGates.emplace(q1, q2); + } + } + if (fidelityAwareHeur) { recalculateFixedCostFidelity(layer, node); } else { - recalculateFixedCostNonFidelity(layer, node); + recalculateFixedCostNonFidelity(node); } } -void HeuristicMapper::recalculateFixedCostNonFidelity(std::size_t layer, Node& node) { +void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { node.costFixed = 0; for (auto& swap : node.swaps) { @@ -965,7 +992,7 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node } node.costFixed += singleQubitGateMultiplicity.at(i) * architecture->getSingleQubitFidelityCost( - static_cast(locations.at(i))); + static_cast(node.locations.at(i))); } // adding cost of the swap gates for (auto& swap : node.swaps) { @@ -976,32 +1003,26 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node "noise-aware mapping"); } } - node.validMappedTwoQubitGates.clear(); // adding cost of two qubit gates that are already mapped next to each other - for (const auto& edgeMultiplicity : twoQubitGateMultiplicity) { - const auto& q1 = edgeMultiplicity.first.first; - const auto& q2 = edgeMultiplicity.first.second; - const auto& straightMultiplicity = edgeMultiplicity.second.first; - const auto& reverseMultiplicity = edgeMultiplicity.second.second; - - if (architecture->isEdgeConnected( - {static_cast(locations.at(q1)), - static_cast(locations.at(q2))}) || - architecture->isEdgeConnected({static_cast(locations.at(q2)), - static_cast( - locations.at(q1))})) { // validly mapped - node.costFixed += (straightMultiplicity * - architecture->getTwoQubitFidelityCost( - static_cast(locations.at(q1)), - static_cast(locations.at(q2))) + - reverseMultiplicity * - architecture->getTwoQubitFidelityCost( - static_cast(locations.at(q2)), - static_cast(locations.at(q1)))); - node.validMappedTwoQubitGates.emplace(q1, q2); + for (const auto& [edge, mult] : twoQubitGateMultiplicity) { + if (node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates not yet validly mapped are handled in the heuristic + continue; } + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; + + node.costFixed += (forwardMult * + architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))) + + reverseMult * + architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q2)), + static_cast(node.locations.at(q1))) + ); } - // 2-qubit-gates not yet validly mapped are handled in the heuristic } @@ -1010,8 +1031,8 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, Node& n for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur = std::max(costHeur, architecture->distance(static_cast(locations.at(q1)), - static_cast(locations.at(q2)))); + costHeur = std::max(costHeur, architecture->distance(static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2)))); } return costHeur; @@ -1023,8 +1044,8 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, Node& n for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur += architecture->distance(static_cast(locations.at(q1)), - static_cast(locations.at(q2))); + costHeur += architecture->distance(static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))); } return costHeur; @@ -1036,8 +1057,8 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps(std::size_ for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur += architecture->distance(static_cast(locations.at(q1)), - static_cast(locations.at(q2))); + costHeur += architecture->distance(static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))); } // TODO: improve heuristic further by using number of 2Q blocks (for @@ -1046,9 +1067,9 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps(std::size_ std::size_t n = activeQubits.size(); double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_BIDIRECTIONAL_SWAP; } else { - sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_UNIDIRECTIONAL_SWAP; } return std::max(0., costHeur - sharedSwapCostReduction); @@ -1061,7 +1082,7 @@ double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwa for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - const double swapCost = architecture->distance(static_cast(locations.at(q1)), static_cast(locations.at(q2))); + const double swapCost = architecture->distance(static_cast(node.locations.at(q1)), static_cast(node.locations.at(q2))); costSum += swapCost; costMax = std::max(costMax, swapCost); } @@ -1072,9 +1093,9 @@ double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwa std::size_t n = activeQubits.size(); double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_BIDIRECTIONAL_SWAP; + sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_BIDIRECTIONAL_SWAP; } else { - sharedSwapCostReduction = ((n-1)*n/2 - node.sharedSwaps)*COST_UNIDIRECTIONAL_SWAP; + sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_UNIDIRECTIONAL_SWAP; } return std::max(costMax, costSum - sharedSwapCostReduction); @@ -1097,7 +1118,7 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n } double qbitSavings = 0; const double currFidelity = architecture->getSingleQubitFidelityCost( - static_cast(locations.at(logQbit))); + static_cast(node.locations.at(logQbit))); for (std::uint16_t physQbit = 0U; physQbit < architecture->getNqubits(); ++physQbit) { if (architecture->getSingleQubitFidelityCost(physQbit) >= currFidelity) { @@ -1107,8 +1128,8 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n singleQubitGateMultiplicity.at(logQbit) * (currFidelity - architecture->getSingleQubitFidelityCost(physQbit)) - architecture->fidelityDistance( - static_cast(locations.at(logQbit)), physQbit, - consideredQubits.size()); + static_cast(node.locations.at(logQbit)), physQbit, + consideredQubits.size() - 1); qbitSavings = std::max(qbitSavings, curSavings); } savingsPotential += qbitSavings; @@ -1116,10 +1137,9 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n // iterating over all virtual qubit pairs, that share a gate on the // current layer - for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { - const auto& [q1, q2] = edge; - - const auto& [straightMultiplicity, reverseMultiplicity] = multiplicity; + for (const auto& [edge, mult] : twoQubitGateMultiplicity) { + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; const bool edgeDone = (node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end() || @@ -1134,36 +1154,36 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n for (const auto& [q3, q4] : architecture->getCouplingMap()) { swapCost = std::min( swapCost, - straightMultiplicity * architecture->getTwoQubitFidelityCost(q3, q4) + - reverseMultiplicity * architecture->getTwoQubitFidelityCost(q4, q3) + + forwardMult * architecture->getTwoQubitFidelityCost(q3, q4) + + reverseMult * architecture->getTwoQubitFidelityCost(q4, q3) + architecture->fidelityDistance( - static_cast(locations.at(q1)), q3, - consideredQubits.size()) + + static_cast(node.locations.at(q1)), q3, + consideredQubits.size() - 1) + architecture->fidelityDistance( - static_cast(locations.at(q2)), q4, - consideredQubits.size())); + static_cast(node.locations.at(q2)), q4, + consideredQubits.size() - 1)); swapCost = std::min( swapCost, - straightMultiplicity * architecture->getTwoQubitFidelityCost(q4, q3) + - reverseMultiplicity * architecture->getTwoQubitFidelityCost(q3, q4) + + forwardMult * architecture->getTwoQubitFidelityCost(q4, q3) + + reverseMult * architecture->getTwoQubitFidelityCost(q3, q4) + architecture->fidelityDistance( - static_cast(locations.at(q2)), q3, - consideredQubits.size()) + + static_cast(node.locations.at(q2)), q3, + consideredQubits.size() - 1) + architecture->fidelityDistance( - static_cast(locations.at(q1)), q4, - consideredQubits.size())); + static_cast(node.locations.at(q1)), q4, + consideredQubits.size()- 1)); } if (edgeDone) { const double currEdgeCost = - (straightMultiplicity * + (forwardMult * architecture->getTwoQubitFidelityCost( - static_cast(locations.at(q1)), - static_cast(locations.at(q2))) + - reverseMultiplicity * + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))) + + reverseMult * architecture->getTwoQubitFidelityCost( - static_cast(locations.at(q2)), - static_cast(locations.at(q1)))); + static_cast(node.locations.at(q2)), + static_cast(node.locations.at(q1)))); savingsPotential += (currEdgeCost - swapCost); } else { costHeur += swapCost; diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 2df8b3565..ce89a3fe2 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -13,52 +13,231 @@ #include #include -TEST(Functionality, NodeCostCalculation) { +/** + * @brief Get id of the final node in a given layer from a data log. + */ +std::size_t getFinalNodeFromDatalog(std::string dataLoggingPath, std::size_t layer) { + auto layerFile = std::ifstream(dataLoggingPath + "/layer_" + + std::to_string(layer) + ".json"); + if (!layerFile.is_open()) { + throw std::runtime_error("Could not open file " + dataLoggingPath + + "/layer_" + std::to_string(layer) + ".json"); + } + const auto layerJson = nlohmann::json::parse(layerFile); + if (layerJson.find("final_node_id") == layerJson.end()) { + throw std::runtime_error("Missing key \"final_node_id\" in " + dataLoggingPath + + "/layer_" + std::to_string(layer) + ".json"); + } + const std::size_t finalNodeId = layerJson["final_node_id"]; + return finalNodeId; +} + +/** + * @brief parses all nodes in a given layer from a data log and enter them + * into `nodes` with each node at the position corresponding to its id. + * + * Only logged values are entered into the nodes, all other values are left at + * default (e.g. `validMappedTwoQubitGates` and `sharedSwaps`) + */ +void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::vector& nodes) { + std::string layerNodeFilePath = dataLoggingPath + "/nodes_layer_" + std::to_string(layer) + ".csv"; + auto layerNodeFile = std::ifstream(layerNodeFilePath); + if (!layerNodeFile.is_open()) { + throw std::runtime_error("Could not open file " + layerNodeFilePath); + } + std::string line; + while (std::getline(layerNodeFile, line)) { + if (line.empty()) { + continue; + } + std::string col; + std::size_t nodeId = 0; + + std::vector layout{}; + std::vector> swaps{}; + std::stringstream lineStream(line); + if (std::getline(lineStream, col, ';')) { + nodeId = std::stoull(col); + if (nodeId >= nodes.size()) { + throw std::runtime_error("Node id " + std::to_string(nodeId) + " out of range in " + layerNodeFilePath); + } + nodes[nodeId].id = nodeId; + } else { + throw std::runtime_error("Missing value for node id in " + layerNodeFilePath); + } + auto& node = nodes[nodeId]; + if (std::getline(lineStream, col, ';')) { + node.parent = std::stoull(col); + } else { + throw std::runtime_error("Missing value for parent node id in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + node.costFixed = std::stod(col); + } else { + throw std::runtime_error("Missing value for fixed cost in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + node.costHeur = std::stod(col); + } else { + throw std::runtime_error("Missing value for heuristic cost in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + node.lookaheadPenalty = std::stod(col); + } else { + throw std::runtime_error("Missing value for lookahead penalty in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + std::size_t validMapping = std::stoull(col); + if (validMapping > 1) { + throw std::runtime_error("Non-boolean value " + std::to_string(validMapping) + + " for validMapping in " + layerNodeFilePath); + } + node.validMapping = static_cast(validMapping); + } else { + throw std::runtime_error("Missing value for validMapping in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + node.depth = std::stoull(col); + } else { + throw std::runtime_error("Missing value for depth in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + for (std::size_t i = 0; i < MAX_DEVICE_QUBITS; ++i) { + node.qubits[i] = -1; + node.locations[i] = -1; + } + + std::stringstream qubitMapBuffer(col); + std::string entry; + for (std::size_t i = 0; std::getline(qubitMapBuffer, entry, ','); ++i) { + auto qubit = static_cast(std::stoi(entry)); + node.qubits[i] = qubit; + if (qubit >= 0) { + node.locations[qubit] = static_cast(i); + } + } + } else { + throw std::runtime_error("Missing value for qubit layout in " + layerNodeFilePath); + } + if (std::getline(lineStream, col, ';')) { + std::stringstream swapBuffer(col); + std::string entry; + while (std::getline(swapBuffer, entry, ',')) { + std::uint16_t q1 = 0; + std::uint16_t q2 = 0; + std::string opTypeStr = ""; + std::stringstream(entry) >> q1 >> q2 >> opTypeStr; + qc::OpType opType = qc::OpType::SWAP; + if (opTypeStr.size() > 0) { + opType = qc::opTypeFromString(opTypeStr); + } + // ignoring op type for now, which is logged as 3rd value unless it is SWAP + node.swaps.emplace_back(q1, q2, opType); + } + } + } +} + +/** + * @brief Get the path from a node to the root node (id of the given node is the first element, id of the root is last) + * + * @param nodes vector of all nodes (each at the position corresponding to its id) + * @param nodeId id of the node from which to find the path to the root + */ +std::vector getPathToRoot(std::vector& nodes, std::size_t nodeId) { + std::vector path{}; + if (nodeId >= nodes.size() || nodes[nodeId].id != nodeId) { + throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); + } + auto& node = nodes[nodeId]; + while (node.parent != node.id) { + path.push_back(node.id); + if (node.parent >= nodes.size() || nodes[node.parent].id != node.parent) { + throw std::runtime_error("Invalid parent id " + std::to_string(node.parent) + " for node " + std::to_string(node.id)); + } + node = nodes[node.parent]; + } + path.push_back(node.id); + return path; +} + + + + +Architecture internalsTestArchitecture{1, {}}; +class InternalsTest : public HeuristicMapper, public testing::Test { + protected: + InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, internalsTestArchitecture) {} + void SetUp() override { + results = MappingResults{}; + } +}; + +TEST_F(InternalsTest, NodeCostCalculation) { const double tolerance = 1e-6; - const CouplingMap cm = {{0, 1}, {1, 2}, {3, 1}, {4, 3}}; - Architecture arch{5, cm}; - const SingleQubitMultiplicity empty1Mult = {}; - const std::unordered_set& consideredQubits = {0, 1, 2, 3, 5}; - const TwoQubitMultiplicity multiplicity = {{{0, 1}, {5, 2}}, - {{2, 3}, {0, 1}}}; - const std::array qubits = {4, 3, 1, 2, 0}; - const std::array locations = {4, 2, 3, 1, 0}; - - const std::vector> swaps = { - {Exchange(0, 1, qc::OpType::Teleportation)}, - {Exchange(1, 2, qc::OpType::SWAP)}}; - - HeuristicMapper::Node node(0, 0, qubits, locations, swaps, 5., 0, false, - false); - node.updateHeuristicCost(arch, empty1Mult, multiplicity, consideredQubits); + + results.config.heuristic = Heuristic::GateCountMaxDistance; + results.config.lookaheadHeuristic = LookaheadHeuristic::None; + results.config.layering = Layering::Disjoint2qBlocks; + + architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); + qc = qc::QuantumComputation{5}; + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{1}, 0); + qc.cx(qc::Control{1}, 0); + qc.cx(qc::Control{3}, 2); + createLayers(); + + EXPECT_EQ(layers.size(), 1) << "layering failed, not able to test node cost calculation"; + + const std::vector swaps{ + Exchange(0, 1, qc::OpType::Teleportation), + Exchange(1, 2, qc::OpType::SWAP)}; + + HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, {{2, 3}}, 5., 0); + EXPECT_NEAR(node.costFixed, 5., tolerance); + EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance); + EXPECT_EQ(node.validMappedTwoQubitGates.size(), 1); + + results.config.heuristic = Heuristic::GateCountSumDistance; + updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 14 + COST_DIRECTION_REVERSE * 3, tolerance); - - node = - HeuristicMapper::Node(0, 0, qubits, locations, swaps, 5., 0, false, true); - EXPECT_NEAR(node.costFixed, 5., tolerance); - node.updateHeuristicCost(arch, empty1Mult, multiplicity, consideredQubits); + EXPECT_NEAR(node.costFixed, 5., tolerance) << "updateHeuristicCost should not change costFixed"; + + results.config.heuristic = Heuristic::GateCountMaxDistance; + updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); - node.applySWAP({3, 4}, arch, empty1Mult, multiplicity, consideredQubits); - node.updateHeuristicCost(arch, empty1Mult, multiplicity, consideredQubits); + EXPECT_NEAR(node.costFixed, 5., tolerance) << "updateHeuristicCost should not change costFixed"; + + applySWAP({3, 4}, 0 , node); EXPECT_NEAR(node.costFixed, 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, tolerance); + EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); + node.lookaheadPenalty = 0.; EXPECT_NEAR(node.getTotalCost(), 5. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); EXPECT_NEAR(node.getTotalFixedCost(), 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); + node.lookaheadPenalty = 2.; EXPECT_NEAR(node.getTotalCost(), 7. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); EXPECT_NEAR(node.getTotalFixedCost(), 7. + COST_UNIDIRECTIONAL_SWAP, tolerance); - node.recalculateFixedCost(arch, empty1Mult, multiplicity); + + recalculateFixedCost(0, node); + EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); EXPECT_NEAR(node.costFixed, COST_TELEPORTATION + COST_UNIDIRECTIONAL_SWAP * 2, tolerance); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, @@ -72,6 +251,171 @@ TEST(Functionality, NodeCostCalculation) { tolerance); } + +class TestHeuristics : public testing::TestWithParam> { +protected: + std::string testExampleDir = "../examples/"; + std::string testArchitectureDir = "../extern/architectures/"; + std::string testCalibrationDir = "../extern/calibration/"; + + qc::QuantumComputation qc{}; + Architecture ibmqYorktown{}; // 5 qubits + Architecture ibmqLondon{}; // 5 qubits (with calibration) + std::unique_ptr ibmqYorktownMapper; + std::unique_ptr ibmqLondonMapper; + Architecture ibmQX5{}; // 16 qubits + std::unique_ptr ibmQX5Mapper; + Configuration settings{}; + const double tolerance = 1e-6; + + void SetUp() override { + qc.import(testExampleDir + std::get<1>(GetParam()) + ".qasm"); + ibmqYorktown.loadCouplingMap(AvailableArchitecture::IbmqYorktown); + ibmqLondon.loadCouplingMap(testArchitectureDir + "ibmq_london.arch"); + ibmqLondon.loadProperties(testCalibrationDir + "ibmq_london.csv"); + ibmqYorktownMapper = std::make_unique(qc, ibmqYorktown); + ibmqLondonMapper = std::make_unique(qc, ibmqLondon); + ibmQX5.loadCouplingMap(AvailableArchitecture::IbmQx5); + ibmQX5Mapper = std::make_unique(qc, ibmQX5); + settings.debug = true; + settings.automaticLayerSplits = false; + settings.initialLayout = InitialLayout::Identity; + settings.layering = Layering::DisjointQubits; + settings.lookaheadHeuristic = LookaheadHeuristic::None; + settings.heuristic = std::get<0>(GetParam()); + settings.dataLoggingPath = "test_log"; + } +}; + +INSTANTIATE_TEST_SUITE_P( + Heuristic, TestHeuristics, + testing::Combine( + testing::Values( + Heuristic::GateCountMaxDistance, + Heuristic::GateCountSumDistance, + Heuristic::GateCountSumDistanceMinusSharedSwaps, + Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps, + Heuristic::FidelityBestLocation + ), + testing::Values( + "3_17_13", // 5q + "ex-1_166", // 5q + "ham3_102", // 5q + "miller_11", // 5q + "4gt11_84", // 5q + "4mod5-v0_20", // 5q + "mod5d1_63", // 5q + "ising_model_10", // 16q + "rd73_140", // 16q + "cnt3-5_179", // 16q + "qft_16", // 16q + "z4_268" // 16q + ) + ), + [](const testing::TestParamInfo& inf) { + std::string name = std::get<1>(inf.param); + std::replace(name.begin(), name.end(), '-', '_'); + std::stringstream ss{}; + ss << name << "_" << toString(std::get<0>(inf.param)); + return ss.str(); + }); + +TEST_P(TestHeuristics, HeuristicProperties) { + EXPECT_TRUE(!isAdmissible(settings.heuristic) || isPrincipallyAdmissible(settings.heuristic)) << "Admissible heuristics are by definition also principally admissible"; + + std::vector> allNodes{}; + std::vector finalSolutionIds{}; + + if (qc.getNqubits() <= ibmqYorktown.getNqubits()) { + if (isFidelityAware(settings.heuristic)) { + EXPECT_THROW(ibmqYorktownMapper->map(settings), QMAPException); + } else { + ibmqYorktownMapper->map(settings); + auto results = ibmqYorktownMapper->getResults(); + for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { + allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); + parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); + finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + } + } + } + + if (qc.getNqubits() <= ibmqLondon.getNqubits()) { + ibmqLondonMapper->map(settings); + auto results = ibmqLondonMapper->getResults(); + for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { + allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); + parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); + finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + } + } + + if (qc.getNqubits() <= ibmQX5.getNqubits()) { + if (isFidelityAware(settings.heuristic)) { + EXPECT_THROW(ibmQX5Mapper->map(settings), QMAPException); + } else { + ibmQX5Mapper->map(settings); + auto results = ibmQX5Mapper->getResults(); + for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { + allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); + parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); + finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + } + } + } + + for (std::size_t i = 0; i < allNodes.size(); ++i) { + auto& nodes = allNodes.at(i); + auto& finalSolutionId = finalSolutionIds.at(i); + + if (finalSolutionId >= nodes.size() || nodes.at(finalSolutionId).id != finalSolutionId) { + FAIL() << "Final solution node " << finalSolutionId << " not found in nodes of layer " << i; + } + auto& finalSolutionNode = nodes.at(finalSolutionId); + EXPECT_TRUE(finalSolutionNode.validMapping); + + if (isPrincipallyAdmissible(settings.heuristic)) { + auto solutionPath = getPathToRoot(nodes, finalSolutionId); + for (auto nodeId : solutionPath) { + auto& node = nodes.at(nodeId); + EXPECT_LE(node.getTotalCost(), finalSolutionNode.costFixed) << "Heuristic " << toString(settings.heuristic) << " is not principally admissible"; + } + } + + for (std::size_t j = 0; j < nodes.size(); ++j) { + const auto& node = nodes.at(j); + if (j != node.id) { + continue; + } + + // check non-decreasing total cost + if (node.parent != node.id) { + if (node.parent >= nodes.size() || nodes.at(node.parent).id != node.parent) { + FAIL() << "Invalid parent id " << node.parent << " for node " << node.id; + } + EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) << "Heuristic " << toString(settings.heuristic) << " does not result in non-decreasing cost estimation"; + } + + EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) << "Lookahead penalty not 0 even though lookahead has been deactivated"; + + if (node.validMapping) { + if (isTight(settings.heuristic)) { + EXPECT_NEAR(node.costHeur, 0., tolerance) << "Heuristic " << toString(settings.heuristic) << " is not tight"; + } + + if (isAdmissible(settings.heuristic)) { + auto path = getPathToRoot(nodes, node.id); + for (auto nodeId : path) { + auto& n = nodes.at(nodeId); + EXPECT_LE(n.getTotalCost(), node.costFixed) << "Heuristic " << toString(settings.heuristic) << " is not admissible"; + } + } + } + } + } +} + + TEST(Functionality, HeuristicBenchmark) { /* 3 @@ -249,60 +593,6 @@ TEST(Functionality, InvalidCircuits) { EXPECT_THROW(mapper3.map(config), QMAPException); } -// TODO: replace with principal admissibility test -TEST(Functionality, HeuristicAdmissibility) { - Architecture architecture{}; - const CouplingMap cm = {{0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, - {3, 2}, {3, 4}, {4, 3}, {4, 5}, {5, 4}}; - architecture.loadCouplingMap(6, cm); - const std::vector perms{{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}}; - - const SingleQubitMultiplicity empty1Mult = {}; - const std::unordered_set& consideredQubits = {0, 1, 2, - 3, 4, 5}; - const TwoQubitMultiplicity multiplicity = { - {{0, 4}, {1, 0}}, {{1, 3}, {1, 0}}, {{2, 5}, {1, 0}}}; - - // perform depth-limited depth first search - const std::size_t depthLimit = 6; - std::vector nodeStack{}; - nodeStack.reserve(depthLimit); - std::stack permStack{}; - - auto initNode = HeuristicMapper::Node( - 0, 0, {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5}, {}, 0., 0, false, true); - initNode.recalculateFixedCost(architecture, empty1Mult, multiplicity); - initNode.updateHeuristicCost(architecture, empty1Mult, multiplicity, - consideredQubits); - nodeStack.emplace_back(initNode); - permStack.emplace(perms.size()); - - while (!nodeStack.empty()) { - const auto& node = nodeStack.back(); - if (node.done) { - // check if all nodes in stack have lower or equal cost - for (const auto& prevNode : nodeStack) { - EXPECT_LE(prevNode.getTotalCost(), node.getTotalCost()); - } - } - if (node.done || nodeStack.size() >= depthLimit || permStack.top() == 0) { - nodeStack.pop_back(); - permStack.pop(); - continue; - } - --permStack.top(); - const auto perm = perms[permStack.top()]; - auto newNode = - HeuristicMapper::Node(1, 0, node.qubits, node.locations, node.swaps, - node.costFixed, node.depth + 1, false, true); - newNode.applySWAP(perm, architecture, empty1Mult, multiplicity, consideredQubits); - newNode.updateHeuristicCost(architecture, empty1Mult, multiplicity, - consideredQubits); - nodeStack.emplace_back(newNode); - permStack.emplace(perms.size()); - } -} - TEST(Functionality, DataLoggerAfterClose) { const std::string dataLoggingPath = "test_log/"; qc::QuantumComputation qc{3}; @@ -576,123 +866,49 @@ TEST(Functionality, DataLogger) { EXPECT_EQ(layerJson["initial_layout"].size(), architecture.getNqubits()); EXPECT_EQ(layerJson["single_qubit_multiplicity"].size(), architecture.getNqubits()); - - auto layerNodeFile = - std::ifstream(settings.dataLoggingPath + "/nodes_layer_" + - std::to_string(i) + ".csv"); - if (!layerNodeFile.is_open()) { - FAIL() << "Could not open file " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; + + std::vector nodes{results.layerHeuristicBenchmark.at(i).generatedNodes}; + parseNodesFromDatalog(settings.dataLoggingPath, i, nodes); + + if (finalNodeId >= nodes.size() || nodes.at(finalNodeId).id != finalNodeId) { + FAIL() << "Final solution node " << finalNodeId << " not found in nodes of layer " << i; } - std::string line; - bool foundFinalNode = false; - std::set nodeIds; - while (std::getline(layerNodeFile, line)) { - if (line.empty()) { + auto& finalSolutionNode = nodes.at(finalNodeId); + EXPECT_EQ(layerJson["final_cost_fixed"], finalSolutionNode.costFixed); + EXPECT_EQ(layerJson["final_cost_heur"], finalSolutionNode.costHeur); + EXPECT_EQ(layerJson["final_lookahead_penalty"], finalSolutionNode.lookaheadPenalty); + EXPECT_EQ(layerJson["final_search_depth"], finalSolutionNode.depth); + std::vector layout{}; + for (std::size_t j = 0; j < architecture.getNqubits(); ++j) { + layout.emplace_back(finalSolutionNode.qubits[j]); + } + std::vector> swaps{}; + for (auto& swap : finalSolutionNode.swaps) { + swaps.emplace_back(swap.first, swap.second); + } + EXPECT_EQ(layerJson["final_layout"], layout); + EXPECT_EQ(layerJson["final_swaps"], swaps); + EXPECT_EQ(finalSolutionNode.validMapping, true); + + for (std::size_t j = 0; j < nodes.size(); ++j) { + auto& node = nodes.at(j); + if (j != node.id) { continue; } - std::string col; - std::size_t nodeId = 0; - std::size_t parentId = 0; - std::size_t depth = 0; - std::size_t isValidMapping = 0; - double costFixed = 0.; - double costHeur = 0.; - double lookaheadPenalty = 0.; - std::vector layout{}; - std::vector> swaps{}; - std::stringstream lineStream(line); - if (std::getline(lineStream, col, ';')) { - nodeId = std::stoull(col); - nodeIds.insert(nodeId); - } else { - FAIL() << "Missing value for node id in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - parentId = std::stoull(col); - if (nodeId != 0) { - EXPECT_TRUE(nodeIds.count(parentId) > 0); - } - } else { - FAIL() << "Missing value for parent node id in " - << settings.dataLoggingPath << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - costFixed = std::stod(col); - } else { - FAIL() << "Missing value for fixed cost in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - costHeur = std::stod(col); - } else { - FAIL() << "Missing value for heuristic cost in " - << settings.dataLoggingPath << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - lookaheadPenalty = std::stod(col); - } else { - FAIL() << "Missing value for lookahead penalty in " - << settings.dataLoggingPath << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - isValidMapping = std::stoull(col); - if (isValidMapping > 1) { - FAIL() << "Non-boolean value " << isValidMapping - << " for isValidMapping in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; + + for (std::size_t k = 0; k < architecture.getNqubits(); ++k) { + EXPECT_GE(node.qubits[k], -1); + EXPECT_LT(node.qubits[k], qc.getNqubits()); + EXPECT_GE(node.locations[k], -1); + EXPECT_LT(node.locations[k], architecture.getNqubits()); + + if (node.qubits[k] >= 0) { + EXPECT_EQ(node.locations[static_cast(node.qubits[k])], static_cast(k)); } - } else { - FAIL() << "Missing value for isValidMapping in " - << settings.dataLoggingPath << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - depth = std::stoull(col); - } else { - FAIL() << "Missing value for depth in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; - } - if (std::getline(lineStream, col, ';')) { - std::stringstream qubitMapBuffer(col); - std::string entry; - while (std::getline(qubitMapBuffer, entry, ',')) { - const std::int32_t qubit = std::stoi(entry); - layout.push_back(qubit); - EXPECT_TRUE(-1 <= qubit && qubit < architecture.getNqubits()); + if (node.locations[k] >= 0) { + EXPECT_EQ(node.qubits[static_cast(node.locations[k])], static_cast(k)); } - EXPECT_EQ(layout.size(), architecture.getNqubits()); - } else { - FAIL() << "Missing value for layout in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; } - if (std::getline(lineStream, col, ';')) { - std::stringstream swapBuffer(col); - std::string entry; - while (std::getline(swapBuffer, entry, ',')) { - std::int32_t q1 = 0; - std::int32_t q2 = 0; - std::stringstream(entry) >> q1 >> q2; - EXPECT_TRUE(0 <= q1 && q1 < architecture.getNqubits()); - EXPECT_TRUE(0 <= q2 && q2 < architecture.getNqubits()); - swaps.emplace_back(q1, q2); - } - } - - if (nodeId == finalNodeId) { - foundFinalNode = true; - EXPECT_EQ(layerJson["final_cost_fixed"], costFixed); - EXPECT_EQ(layerJson["final_cost_heur"], costHeur); - EXPECT_EQ(layerJson["final_layout"], layout); - EXPECT_EQ(layerJson["final_lookahead_penalty"], lookaheadPenalty); - EXPECT_EQ(layerJson["final_search_depth"], depth); - EXPECT_EQ(layerJson["final_swaps"], swaps); - EXPECT_EQ(isValidMapping, 1); - } - } - if (!foundFinalNode) { - FAIL() << "Could not find final node in " << settings.dataLoggingPath - << "/nodes_layer_" << i << ".csv"; } } @@ -1003,7 +1219,6 @@ TEST_P(HeuristicTest20QTeleport, Teleportation) { Configuration settings{}; settings.initialLayout = InitialLayout::Dynamic; settings.debug = true; - settings.verbose = true; settings.teleportationQubits = std::min( (arch.getNqubits() - qc.getNqubits()) & ~1U, static_cast(8)); settings.teleportationSeed = std::get<0>(GetParam()); From 230a1d6f6e34319088ad77f6ba8b8ed354f485df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 03:42:19 +0000 Subject: [PATCH 05/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/DataLogger.hpp | 8 +- include/configuration/Configuration.hpp | 13 +- include/configuration/Heuristic.hpp | 47 ++- include/configuration/LookaheadHeuristic.hpp | 20 +- include/heuristic/HeuristicMapper.hpp | 109 +++--- src/DataLogger.cpp | 10 +- src/configuration/Configuration.cpp | 6 +- src/heuristic/HeuristicMapper.cpp | 383 ++++++++++--------- src/mqt/qmap/compile.py | 2 +- src/python/bindings.cpp | 14 +- test/test_heuristic.cpp | 341 +++++++++-------- 11 files changed, 524 insertions(+), 429 deletions(-) diff --git a/include/DataLogger.hpp b/include/DataLogger.hpp index c783af3b2..501e3c0a2 100644 --- a/include/DataLogger.hpp +++ b/include/DataLogger.hpp @@ -36,9 +36,8 @@ class DataLogger { std::size_t parentId, double costFixed, double costHeur, double lookaheadPenalty, const std::array& qubits, - bool validMapping, - const std::vector& swaps, - std::size_t depth); + bool validMapping, const std::vector& swaps, + std::size_t depth); void logFinalizeLayer( std::size_t layer, const qc::CompoundOperation& ops, const std::vector& singleQubitMultiplicity, @@ -49,8 +48,7 @@ class DataLogger { std::size_t finalNodeId, double finalCostFixed, double finalCostHeur, double finalLookaheadPenalty, const std::array& finalLayout, - const std::vector& finalSwaps, - std::size_t finalSearchDepth); + const std::vector& finalSwaps, std::size_t finalSearchDepth); void splitLayer(); void logMappingResult(MappingResults& result); void logInputCircuit(qc::QuantumComputation& qc) { diff --git a/include/configuration/Configuration.hpp b/include/configuration/Configuration.hpp index e608b9b32..61685873b 100644 --- a/include/configuration/Configuration.hpp +++ b/include/configuration/Configuration.hpp @@ -22,8 +22,8 @@ struct Configuration { Configuration() = default; // which method to use - Method method = Method::Heuristic; - Heuristic heuristic = Heuristic::GateCountMaxDistance; + Method method = Method::Heuristic; + Heuristic heuristic = Heuristic::GateCountMaxDistance; bool preMappingOptimizations = true; bool postMappingOptimizations = true; @@ -59,10 +59,11 @@ struct Configuration { std::size_t iterativeBidirectionalRoutingPasses = 0; // lookahead scheme settings - LookaheadHeuristic lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; - std::size_t nrLookaheads = 15; - double firstLookaheadFactor = 0.75; - double lookaheadFactor = 0.5; + LookaheadHeuristic lookaheadHeuristic = + LookaheadHeuristic::GateCountMaxDistance; + std::size_t nrLookaheads = 15; + double firstLookaheadFactor = 0.75; + double lookaheadFactor = 0.5; // teleportation settings bool useTeleportation = false; diff --git a/include/configuration/Heuristic.hpp b/include/configuration/Heuristic.hpp index 2141f70f9..fbd78b3d9 100644 --- a/include/configuration/Heuristic.hpp +++ b/include/configuration/Heuristic.hpp @@ -8,22 +8,30 @@ #include enum class Heuristic { - /** maximum over all distances between any virtual qubit pair in the current layer; optimizing gate-count; admissible; tight */ + /** maximum over all distances between any virtual qubit pair in the current + layer; optimizing gate-count; admissible; tight */ GateCountMaxDistance, - /** sum over all distances between any virtual qubit pair in the current layer; optimizing gate-count; not admissible; tight */ + /** sum over all distances between any virtual qubit pair in the current + layer; optimizing gate-count; not admissible; tight */ GateCountSumDistance, - /** sum over all distances between any virtual qubit pair in the current layer minus the upper limit of viable shared swaps; optimizing gate-count; admissible; tight */ + /** sum over all distances between any virtual qubit pair in the current layer + minus the upper limit of viable shared swaps; optimizing gate-count; + admissible; tight */ GateCountSumDistanceMinusSharedSwaps, - /** maximum of `Heuristic::GateCountMaxDistance` and `Heuristic::GateCountSumDistanceMinusSharedSwaps`; optimizing gate-count; admissible; tight */ + /** maximum of `Heuristic::GateCountMaxDistance` and + `Heuristic::GateCountSumDistanceMinusSharedSwaps`; optimizing gate-count; + admissible; tight */ GateCountMaxDistanceOrSumDistanceMinusSharedSwaps, - /** minimum cost if each virtual qubit pair/qubit is mapped to its individually best physical edge/qubit; optimizing fidelity; admissible; tight */ + /** minimum cost if each virtual qubit pair/qubit is mapped to its + individually best physical edge/qubit; optimizing fidelity; admissible; + tight */ FidelityBestLocation }; /** - * A heuristic is admissible if it never overestimates the cost of the best - * reachable goal node, i.e. c(n*) <= c(n) + h(n) for cost function c, - * heuristic h, any node n in the search graph, and n* the best reachable goal + * A heuristic is admissible if it never overestimates the cost of the best + * reachable goal node, i.e. c(n*) <= c(n) + h(n) for cost function c, + * heuristic h, any node n in the search graph, and n* the best reachable goal * node from n. */ [[maybe_unused]] static inline bool isAdmissible(const Heuristic heuristic) { @@ -40,12 +48,13 @@ enum class Heuristic { } /** - * A heuristic is principally admissible if it never overestimates the cost of the - * globally optimal solution along the solution path, i.e. c(n*) <= c(n) + h(n) - * for cost function c, heuristic h, any node n along the optimal solution path, - * and n* the globally optimal solution node. + * A heuristic is principally admissible if it never overestimates the cost of + * the globally optimal solution along the solution path, i.e. c(n*) <= c(n) + + * h(n) for cost function c, heuristic h, any node n along the optimal solution + * path, and n* the globally optimal solution node. */ -[[maybe_unused]] static inline bool isPrincipallyAdmissible(const Heuristic heuristic) { +[[maybe_unused]] static inline bool +isPrincipallyAdmissible(const Heuristic heuristic) { switch (heuristic) { case Heuristic::GateCountMaxDistance: case Heuristic::GateCountSumDistanceMinusSharedSwaps: @@ -108,21 +117,25 @@ enum class Heuristic { return " "; } -[[maybe_unused]] static Heuristic heuristicFromString(const std::string& heuristic) { +[[maybe_unused]] static Heuristic +heuristicFromString(const std::string& heuristic) { if (heuristic == "gate_count_max_distance" || heuristic == "0") { return Heuristic::GateCountMaxDistance; } if (heuristic == "gate_count_sum_distance" || heuristic == "1") { return Heuristic::GateCountSumDistance; } - if (heuristic == "gate_count_sum_distance_minus_shared_swaps" || heuristic == "2") { + if (heuristic == "gate_count_sum_distance_minus_shared_swaps" || + heuristic == "2") { return Heuristic::GateCountSumDistanceMinusSharedSwaps; } - if (heuristic == "gate_count_max_distance_or_sum_distance_minus_shared_swaps" || heuristic == "3") { + if (heuristic == + "gate_count_max_distance_or_sum_distance_minus_shared_swaps" || + heuristic == "3") { return Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps; } if (heuristic == "fidelity_best_location" || heuristic == "4") { return Heuristic::FidelityBestLocation; } throw std::invalid_argument("Invalid heuristic value: " + heuristic); -} \ No newline at end of file +} diff --git a/include/configuration/LookaheadHeuristic.hpp b/include/configuration/LookaheadHeuristic.hpp index 8694648b6..9a2a373db 100644 --- a/include/configuration/LookaheadHeuristic.hpp +++ b/include/configuration/LookaheadHeuristic.hpp @@ -10,9 +10,11 @@ enum class LookaheadHeuristic { /** no lookahead */ None, - /** maximum over all distances between any virtual qubit pair in the given layer; optimizing gate-count */ + /** maximum over all distances between any virtual qubit pair in the given + layer; optimizing gate-count */ GateCountMaxDistance, - /** sum over all distances between any virtual qubit pair in the given layer; optimizing gate-count */ + /** sum over all distances between any virtual qubit pair in the given layer; + optimizing gate-count */ GateCountSumDistance }; @@ -20,7 +22,8 @@ enum class LookaheadHeuristic { * A heuristic is fidelity aware if it takes into account the error rates of * physical qubits and minimizes the total error of the mapped circuit. */ -[[maybe_unused]] static inline bool isFidelityAware(const LookaheadHeuristic heuristic) { +[[maybe_unused]] static inline bool +isFidelityAware(const LookaheadHeuristic heuristic) { switch (heuristic) { case LookaheadHeuristic::None: case LookaheadHeuristic::GateCountMaxDistance: @@ -30,7 +33,8 @@ enum class LookaheadHeuristic { return false; } -[[maybe_unused]] static inline std::string toString(const LookaheadHeuristic heuristic) { +[[maybe_unused]] static inline std::string +toString(const LookaheadHeuristic heuristic) { switch (heuristic) { case LookaheadHeuristic::None: return "none"; @@ -42,7 +46,8 @@ enum class LookaheadHeuristic { return " "; } -[[maybe_unused]] static LookaheadHeuristic lookaheadHeuristicFromString(const std::string& heuristic) { +[[maybe_unused]] static LookaheadHeuristic +lookaheadHeuristicFromString(const std::string& heuristic) { if (heuristic == "none" || heuristic == "0") { return LookaheadHeuristic::None; } @@ -52,5 +57,6 @@ enum class LookaheadHeuristic { if (heuristic == "gate_count_sum_distance" || heuristic == "2") { return LookaheadHeuristic::GateCountSumDistance; } - throw std::invalid_argument("Invalid lookahead heuristic value: " + heuristic); -} \ No newline at end of file + throw std::invalid_argument("Invalid lookahead heuristic value: " + + heuristic); +} diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 9acda2e1a..67279bb50 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -32,7 +32,7 @@ class HeuristicMapper : public Mapper { struct Node { /** gates (pair of logical qubits) currently mapped next to each other */ std::set validMappedTwoQubitGates = {}; - /** swaps used so far to get from the initial mapping of the current layer + /** swaps used so far to get from the initial mapping of the current layer * to the current mapping in this node */ std::vector swaps = {}; /** @@ -63,19 +63,18 @@ class HeuristicMapper : public Mapper { /** depth in search tree (starting with 0 at the root) */ std::size_t depth = 0; std::size_t parent = 0; - std::size_t id = 0; + std::size_t id = 0; /** true if all qubit pairs are mapped next to each other on the * architecture */ bool validMapping = true; - + explicit Node() = default; - explicit Node(std::size_t nodeId) - : id(nodeId) {}; + explicit Node(std::size_t nodeId) : id(nodeId){}; Node(std::size_t nodeId, std::size_t parentId, const std::array& q, const std::array& loc, - const std::vector& sw = {}, - const std::set& valid2QGates = {}, + const std::vector& sw = {}, + const std::set& valid2QGates = {}, const double initCostFixed = 0, const std::size_t searchDepth = 0) : costFixed(initCostFixed), depth(searchDepth), parent(parentId), id(nodeId) { @@ -121,7 +120,7 @@ class HeuristicMapper : public Mapper { protected: UniquePriorityQueue nodes{}; std::unique_ptr dataLogger; - std::size_t nextNodeId = 0; + std::size_t nextNodeId = 0; bool principallyAdmissibleHeur = true; bool tightHeur = true; bool fidelityAwareHeur = false; @@ -235,12 +234,12 @@ class HeuristicMapper : public Mapper { * @param twoQubitGateMultiplicity number of two qubit gates acting on pairs * of logical qubits in the current layer */ - void expandNodeAddOneSwap( - const Edge& swap, Node& node, std::size_t layer); - + void expandNodeAddOneSwap(const Edge& swap, Node& node, std::size_t layer); + /** - * @brief applies an in-place swap of 2 virtual qubits in the given node and recalculates all costs accordingly - * + * @brief applies an in-place swap of 2 virtual qubits in the given node and + * recalculates all costs accordingly + * * @param swap physical edge on which to perform a swap * @param layer index of current circuit layer * @param node search node in which to apply the swap @@ -248,8 +247,9 @@ class HeuristicMapper : public Mapper { void applySWAP(const Edge& swap, std::size_t layer, Node& node); /** - * @brief applies an in-place teleportation of 2 virtual qubits in the given node and recalculates all costs accordingly - * + * @brief applies an in-place teleportation of 2 virtual qubits in the given + * node and recalculates all costs accordingly + * * @param swap pair of physical qubits on which to perform a teleportation * @param layer index of current circuit layer * @param node search node in which to apply the swap @@ -257,7 +257,8 @@ class HeuristicMapper : public Mapper { void applyTeleportation(const Edge& swap, std::size_t layer, Node& node); /** - * @brief recalculates the fixed cost of the node from the current mapping and swaps + * @brief recalculates the fixed cost of the node from the current mapping and + * swaps * * @param layer index of current circuit layer * @param node search node for which to recalculate the fixed cost @@ -265,7 +266,8 @@ class HeuristicMapper : public Mapper { void recalculateFixedCost(std::size_t layer, Node& node); /** - * @brief recalculates the fidelity-aware fixed cost of the node from the current mapping and swaps + * @brief recalculates the fidelity-aware fixed cost of the node from the + * current mapping and swaps * * @param layer index of current circuit layer * @param node search node for which to recalculate the fixed cost @@ -273,7 +275,8 @@ class HeuristicMapper : public Mapper { void recalculateFixedCostFidelity(std::size_t layer, Node& node); /** - * @brief recalculates the gate-count-optimizing fixed cost of the node from the current mapping and swaps + * @brief recalculates the gate-count-optimizing fixed cost of the node from + * the current mapping and swaps * * @param node search node for which to recalculate the fixed cost */ @@ -282,93 +285,100 @@ class HeuristicMapper : public Mapper { /** * @brief calculates the heuristic cost of the current mapping in the node * for some given layer and writes it to `Node::costHeur`, additionally - * `Node::validMapping` is set to true if all qubit pairs sharing a gate in + * `Node::validMapping` is set to true if all qubit pairs sharing a gate in * the current layer are mapped next to each other * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost */ void updateHeuristicCost(std::size_t layer, Node& node); - + /** * @brief calculates the heuristic using `Heuristic::GateCountMaxDistance` * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost - * + * * @return heuristic cost */ double heuristicGateCountMaxDistance(std::size_t layer, Node& node); - + /** * @brief calculates the heuristic using `Heuristic::GateCountSumDistance` * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost - * + * * @return heuristic cost */ double heuristicGateCountSumDistance(std::size_t layer, Node& node); - + /** - * @brief calculates the heuristic using + * @brief calculates the heuristic using * `Heuristic::GateCountSumDistanceMinusSharedSwaps` * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost - * + * * @return heuristic cost */ - double heuristicGateCountSumDistanceMinusSharedSwaps(std::size_t layer, Node& node); - + double heuristicGateCountSumDistanceMinusSharedSwaps(std::size_t layer, + Node& node); + /** - * @brief calculates the heuristic using + * @brief calculates the heuristic using * `Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps` * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost - * + * * @return heuristic cost */ - double heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(std::size_t layer, Node& node); - + double + heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(std::size_t layer, + Node& node); + /** - * @brief calculates the heuristic using + * @brief calculates the heuristic using * `Heuristic::FidelityBestLocation` * * @param layer index of current circuit layer * @param node search node for which to calculate the heuristic cost - * + * * @return heuristic cost */ double heuristicFidelityBestLocation(std::size_t layer, Node& node); /** - * @brief calculates an estimation of the heuristic cost for the following - * layers (depreciated by a constant factor growing with each layer) and + * @brief calculates an estimation of the heuristic cost for the following + * layers (depreciated by a constant factor growing with each layer) and * saves it in the node as `Node::lookaheadPenalty` * * @param layer index of current circuit layer * @param node search node for which to calculate lookahead penalty */ void updateLookaheadPenalty(std::size_t layer, Node& node); - + /** - * @brief calculates the lookahead penalty for one layer using `LookaheadHeuristic::GateCountMaxDistance` + * @brief calculates the lookahead penalty for one layer using + * `LookaheadHeuristic::GateCountMaxDistance` * - * @param layer index of the circuit layer for which to calculate the lookahead penalty + * @param layer index of the circuit layer for which to calculate the + * lookahead penalty * @param node search node for which to calculate the heuristic cost - * + * * @return lookahead penalty */ double lookaheadGateCountMaxDistance(std::size_t layer, Node& node); - + /** - * @brief calculates the lookahead penalty for one layer using `LookaheadHeuristic::GateCountSumDistance` + * @brief calculates the lookahead penalty for one layer using + * `LookaheadHeuristic::GateCountSumDistance` * - * @param layer index of the circuit layer for which to calculate the lookahead penalty + * @param layer index of the circuit layer for which to calculate the + * lookahead penalty * @param node search node for which to calculate the heuristic cost - * + * * @return lookahead penalty */ double lookaheadGateCountSumDistance(std::size_t layer, Node& node); @@ -418,10 +428,10 @@ inline bool operator>(const HeuristicMapper::Node& x, const HeuristicMapper::Node& y) { // order nodes by costFixed + costHeur + lookaheadPenalty (increasing) // then by validMapping (true before false) - // then by costHeur + lookaheadPenalty (increasing), + // then by costHeur + lookaheadPenalty (increasing), // equivalent to ordering by costFixed (decreasing) // then by the amount of validly mapped 2q gates (decreasing) - // then by the qubit mapping (lexicographically) as an arbitrary but + // then by the qubit mapping (lexicographically) as an arbitrary but // consistent tie-breaker const auto xcost = x.getTotalCost(); const auto ycost = y.getTotalCost(); @@ -441,10 +451,11 @@ inline bool operator>(const HeuristicMapper::Node& x, if (std::abs(xheur - yheur) > 1e-6) { return xheur > yheur; } - + if (x.validMappedTwoQubitGates.size() != y.validMappedTwoQubitGates.size()) { - return x.validMappedTwoQubitGates.size() < y.validMappedTwoQubitGates.size(); + return x.validMappedTwoQubitGates.size() < + y.validMappedTwoQubitGates.size(); } - + return x < y; } diff --git a/src/DataLogger.cpp b/src/DataLogger.cpp index bfbc32b97..6787a303a 100644 --- a/src/DataLogger.cpp +++ b/src/DataLogger.cpp @@ -87,8 +87,7 @@ void DataLogger::logFinalizeLayer( std::size_t finalNodeId, double finalCostFixed, double finalCostHeur, double finalLookaheadPenalty, const std::array& finalLayout, - const std::vector& finalSwaps, - std::size_t finalSearchDepth) { + const std::vector& finalSwaps, std::size_t finalSearchDepth) { if (deactivated) { return; } @@ -141,8 +140,8 @@ void DataLogger::logFinalizeLayer( if (finalSwaps.empty()) { json["final_swaps"] = nlohmann::json::array(); } else { - auto& finalSwapsJSON = json["final_swaps"]; - std::size_t i = 0; + auto& finalSwapsJSON = json["final_swaps"]; + std::size_t i = 0; for (const auto& swap : finalSwaps) { finalSwapsJSON[i][0] = swap.first; finalSwapsJSON[i][1] = swap.second; @@ -186,8 +185,7 @@ void DataLogger::logSearchNode( std::size_t layerIndex, std::size_t nodeId, std::size_t parentId, double costFixed, double costHeur, double lookaheadPenalty, const std::array& qubits, - bool validMapping, const std::vector& swaps, - std::size_t depth) { + bool validMapping, const std::vector& swaps, std::size_t depth) { if (deactivated) { return; } diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index ae47fc955..b9091fa9e 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -19,9 +19,9 @@ nlohmann::json Configuration::json() const { config["debug"] = debug; if (method == Method::Heuristic) { - auto& heuristicJson = config["settings"]; - heuristicJson["heuristic"] = ::toString(heuristic); - heuristicJson["initial_layout"] = ::toString(initialLayout); + auto& heuristicJson = config["settings"]; + heuristicJson["heuristic"] = ::toString(heuristic); + heuristicJson["initial_layout"] = ::toString(initialLayout); if (lookaheadHeuristic != LookaheadHeuristic::None) { auto& lookaheadSettings = heuristicJson["lookahead"]; lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 299ea230e..9fd442b18 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -14,11 +14,11 @@ void HeuristicMapper::map(const Configuration& configuration) { dataLogger = std::make_unique(configuration.dataLoggingPath, *architecture, qc); } - + principallyAdmissibleHeur = isPrincipallyAdmissible(configuration.heuristic); - tightHeur = isTight(configuration.heuristic); - fidelityAwareHeur = isFidelityAware(configuration.heuristic); - + tightHeur = isTight(configuration.heuristic); + fidelityAwareHeur = isFidelityAware(configuration.heuristic); + results = MappingResults{}; results.config = configuration; auto& config = results.config; @@ -30,7 +30,9 @@ void HeuristicMapper::map(const Configuration& configuration) { if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { throw QMAPException("No calibration data available for this architecture!"); } - if (fidelityAwareHeur && !(isFidelityAware(config.lookaheadHeuristic) || config.lookaheadHeuristic == LookaheadHeuristic::None)) { + if (fidelityAwareHeur && + !(isFidelityAware(config.lookaheadHeuristic) || + config.lookaheadHeuristic == LookaheadHeuristic::None)) { throw QMAPException("Fidelity-aware heuristics may only be used with " "fidelity-aware lookahead heuristics (or no " "lookahead)!"); @@ -369,9 +371,8 @@ void HeuristicMapper::routeCircuit() { } if (!architecture->isEdgeConnected({swap.first, swap.second}) && !architecture->isEdgeConnected({swap.second, swap.first})) { - throw QMAPException( - "Invalid SWAP: " + std::to_string(swap.first) + "<->" + - std::to_string(swap.second)); + throw QMAPException("Invalid SWAP: " + std::to_string(swap.first) + + "<->" + std::to_string(swap.second)); } qcMapped.swap(swap.first, swap.second); results.output.swaps++; @@ -534,8 +535,8 @@ void HeuristicMapper::routeCircuit() { } HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { - auto& config = results.config; - nextNodeId = 0; + auto& config = results.config; + nextNodeId = 0; const std::unordered_set& consideredQubits = (fidelityAwareHeur ? activeQubits[layer] : activeQubits2QGates[layer]); @@ -568,8 +569,9 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { const bool splittable = config.automaticLayerSplits ? isLayerSplittable(layer) : false; - while (!nodes.empty() && (!validMapping || nodes.top().getTotalCost() < - bestDoneNode.getTotalFixedCost())) { + while (!nodes.empty() && + (!validMapping || + nodes.top().getTotalCost() < bestDoneNode.getTotalFixedCost())) { if (splittable && expandedNodes >= config.automaticLayerSplitsNodeLimit) { if (config.dataLoggingEnabled()) { qc::CompoundOperation compOp(architecture->getNqubits()); @@ -737,11 +739,11 @@ void HeuristicMapper::expandNode( } } -void HeuristicMapper::expandNodeAddOneSwap( - const Edge& swap, Node& node, const std::size_t layer) { - - Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, - node.swaps, node.validMappedTwoQubitGates, node.costFixed, node.depth + 1); +void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, + const std::size_t layer) { + Node newNode = + Node(nextNodeId++, node.id, node.qubits, node.locations, node.swaps, + node.validMappedTwoQubitGates, node.costFixed, node.depth + 1); if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { @@ -752,18 +754,18 @@ void HeuristicMapper::expandNodeAddOneSwap( nodes.push(newNode); if (results.config.dataLoggingEnabled()) { - dataLogger->logSearchNode(layer, newNode.id, newNode.parent, - newNode.costFixed, newNode.costHeur, - newNode.lookaheadPenalty, newNode.qubits, - newNode.validMapping, newNode.swaps, newNode.depth); + dataLogger->logSearchNode( + layer, newNode.id, newNode.parent, newNode.costFixed, newNode.costHeur, + newNode.lookaheadPenalty, newNode.qubits, newNode.validMapping, + newNode.swaps, newNode.depth); } } - -void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { - auto& consideredQubits = activeQubits.at(layer); +void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, + Node& node) { + auto& consideredQubits = activeQubits.at(layer); auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - + const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); @@ -789,7 +791,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) } else { throw QMAPException("Something wrong in applySWAP."); } - + // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { auto [q3, q4] = edge; @@ -800,16 +802,20 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) architecture->isEdgeConnected(Edge{physQ4, physQ3})) { // validly mapped now if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == - node.validMappedTwoQubitGates.end()) { // not mapped validly before + node.validMappedTwoQubitGates + .end()) { // not mapped validly before // add cost of newly validly mapped gates node.costFixed += - mult.first * architecture->getTwoQubitFidelityCost(physQ3, physQ4) + - mult.second * architecture->getTwoQubitFidelityCost(physQ4, physQ3); + mult.first * + architecture->getTwoQubitFidelityCost(physQ3, physQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(physQ4, physQ3); } node.validMappedTwoQubitGates.emplace(edge); } else { // not mapped validly now - if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { // mapped validly before + if (fidelityAwareHeur && + node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { // mapped validly before // remove cost of now no longer validly mapped gates auto prevPhysQ3 = physQ3; if (prevPhysQ3 == swap.first) { @@ -823,10 +829,11 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) } else if (prevPhysQ4 == swap.second) { prevPhysQ4 = swap.first; } - node.costFixed -= mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, - prevPhysQ4) + - mult.second * architecture->getTwoQubitFidelityCost(prevPhysQ4, - prevPhysQ3); + node.costFixed -= + mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, + prevPhysQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); } node.validMappedTwoQubitGates.erase(edge); } @@ -845,10 +852,13 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) // accounting for fidelity difference of single qubit gates (two qubit // gates are handled in the heuristic) node.costFixed += - ((q2Mult - q1Mult) * architecture->getSingleQubitFidelityCost(swap.first) + - (q1Mult - q2Mult) * architecture->getSingleQubitFidelityCost(swap.second)); + ((q2Mult - q1Mult) * + architecture->getSingleQubitFidelityCost(swap.first) + + (q1Mult - q2Mult) * + architecture->getSingleQubitFidelityCost(swap.second)); // adding cost of the swap gate itself - node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); + node.costFixed += + architecture->getSwapFidelityCost(swap.first, swap.second); } else { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -856,15 +866,15 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) node.costFixed += COST_UNIDIRECTIONAL_SWAP; } } - + updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { updateLookaheadPenalty(layer, node); } } - -void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { +void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, + Node& node) { const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); @@ -916,7 +926,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, No node.swaps.emplace_back(source, target, middleAnc, qc::Teleportation); node.costFixed += COST_TELEPORTATION; - + // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { auto [q3, q4] = edge; @@ -932,14 +942,13 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, No } } } - + updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { updateLookaheadPenalty(layer, node); } } - void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { node.validMappedTwoQubitGates.clear(); for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { @@ -947,14 +956,15 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { if (architecture->isEdgeConnected( {static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))}) || - architecture->isEdgeConnected({static_cast(node.locations.at(q2)), - static_cast( - node.locations.at(q1))})) { // validly mapped + static_cast(node.locations.at(q2))}) || + architecture->isEdgeConnected( + {static_cast(node.locations.at(q2)), + static_cast( + node.locations.at(q1))})) { // validly mapped node.validMappedTwoQubitGates.emplace(q1, q2); } } - + if (fidelityAwareHeur) { recalculateFixedCostFidelity(layer, node); } else { @@ -962,10 +972,9 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { } } - void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { node.costFixed = 0; - + for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { if (architecture->bidirectional()) { @@ -979,11 +988,11 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { } } - -void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node) { +void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, + Node& node) { auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + node.costFixed = 0; // adding costs of single qubit gates for (std::uint16_t i = 0U; i < architecture->getNqubits(); ++i) { @@ -991,13 +1000,14 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node continue; } node.costFixed += singleQubitGateMultiplicity.at(i) * - architecture->getSingleQubitFidelityCost( - static_cast(node.locations.at(i))); + architecture->getSingleQubitFidelityCost( + static_cast(node.locations.at(i))); } // adding cost of the swap gates for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { - node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); + node.costFixed += + architecture->getSwapFidelityCost(swap.first, swap.second); } else if (swap.op == qc::Teleportation) { throw QMAPException("Teleportation currently not supported for " "noise-aware mapping"); @@ -1007,112 +1017,126 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node for (const auto& [edge, mult] : twoQubitGateMultiplicity) { if (node.validMappedTwoQubitGates.find(edge) == node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates not yet validly mapped are handled in the heuristic - continue; + // 2-qubit-gates not yet validly mapped are handled in the heuristic + continue; } - const auto [q1, q2] = edge; + const auto [q1, q2] = edge; const auto [forwardMult, reverseMult] = mult; - - node.costFixed += (forwardMult * - architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))) + - reverseMult * - architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q2)), - static_cast(node.locations.at(q1))) - ); + + node.costFixed += + (forwardMult * architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))) + + reverseMult * architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q2)), + static_cast(node.locations.at(q1)))); } } - -double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, Node& node) { +double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, + Node& node) { double costHeur = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur = std::max(costHeur, architecture->distance(static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2)))); + costHeur = std::max(costHeur, + architecture->distance( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2)))); } - + return costHeur; } - -double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, Node& node) { +double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, + Node& node) { double costHeur = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur += architecture->distance(static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))); + costHeur += architecture->distance( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))); } - + return costHeur; } - -double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps(std::size_t layer, Node& node) { +double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( + std::size_t layer, Node& node) { double costHeur = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - costHeur += architecture->distance(static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))); + costHeur += architecture->distance( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))); } - - // TODO: improve heuristic further by using number of 2Q blocks (for - // gate-count-optimizing mapping qubit pairs will only travel towards + + // TODO: improve heuristic further by using number of 2Q blocks (for + // gate-count-optimizing mapping qubit pairs will only travel towards // each other, i.e. a qubit can only share 1 swap per qubit pair) - std::size_t n = activeQubits.size(); - double sharedSwapCostReduction = 0; + std::size_t n = activeQubits.size(); + double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_BIDIRECTIONAL_SWAP; + sharedSwapCostReduction = + ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * + COST_BIDIRECTIONAL_SWAP; } else { - sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_UNIDIRECTIONAL_SWAP; + sharedSwapCostReduction = + ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * + COST_UNIDIRECTIONAL_SWAP; } - + return std::max(0., costHeur - sharedSwapCostReduction); } - -double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(std::size_t layer, Node& node) { +double +HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps( + std::size_t layer, Node& node) { double costMax = 0.; double costSum = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; - const double swapCost = architecture->distance(static_cast(node.locations.at(q1)), static_cast(node.locations.at(q2))); + const auto& [q1, q2] = edge; + const double swapCost = architecture->distance( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))); costSum += swapCost; costMax = std::max(costMax, swapCost); } - - // TODO: improve heuristic further by using number of 2Q blocks (for - // gate-count-optimizing mapping qubit pairs will only travel towards + + // TODO: improve heuristic further by using number of 2Q blocks (for + // gate-count-optimizing mapping qubit pairs will only travel towards // each other, i.e. a qubit can only share 1 swap per qubit pair) - std::size_t n = activeQubits.size(); - double sharedSwapCostReduction = 0; + std::size_t n = activeQubits.size(); + double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_BIDIRECTIONAL_SWAP; + sharedSwapCostReduction = + ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * + COST_BIDIRECTIONAL_SWAP; } else { - sharedSwapCostReduction = ((n-1)*n/2 - static_cast(node.sharedSwaps))*COST_UNIDIRECTIONAL_SWAP; + sharedSwapCostReduction = + ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * + COST_UNIDIRECTIONAL_SWAP; } - + return std::max(costMax, costSum - sharedSwapCostReduction); } - -double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& node) { +double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, + Node& node) { auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - auto& consideredQubits = activeQubits.at(layer); - + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + auto& consideredQubits = activeQubits.at(layer); + double costHeur = 0.; - + // single qubit gate savings potential by moving them to different physical // qubits with higher fidelity double savingsPotential = 0.; - for (std::uint16_t logQbit = 0U; logQbit < architecture->getNqubits(); ++logQbit) { + for (std::uint16_t logQbit = 0U; logQbit < architecture->getNqubits(); + ++logQbit) { if (singleQubitGateMultiplicity.at(logQbit) == 0) { continue; } @@ -1120,13 +1144,14 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n const double currFidelity = architecture->getSingleQubitFidelityCost( static_cast(node.locations.at(logQbit))); for (std::uint16_t physQbit = 0U; physQbit < architecture->getNqubits(); - ++physQbit) { + ++physQbit) { if (architecture->getSingleQubitFidelityCost(physQbit) >= currFidelity) { continue; } const double curSavings = singleQubitGateMultiplicity.at(logQbit) * - (currFidelity - architecture->getSingleQubitFidelityCost(physQbit)) - + (currFidelity - + architecture->getSingleQubitFidelityCost(physQbit)) - architecture->fidelityDistance( static_cast(node.locations.at(logQbit)), physQbit, consideredQubits.size() - 1); @@ -1138,14 +1163,14 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n // iterating over all virtual qubit pairs, that share a gate on the // current layer for (const auto& [edge, mult] : twoQubitGateMultiplicity) { - const auto [q1, q2] = edge; + const auto [q1, q2] = edge; const auto [forwardMult, reverseMult] = mult; const bool edgeDone = (node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end() || - node.validMappedTwoQubitGates.find({q1, q2}) != - node.validMappedTwoQubitGates.end()); - + node.validMappedTwoQubitGates.end() || + node.validMappedTwoQubitGates.find({q1, q2}) != + node.validMappedTwoQubitGates.end()); + // find the optimal edge, to which to remap the given virtual qubit // pair and take the cost of moving it there via swaps plus the // fidelity cost of executing all their shared gates on that edge @@ -1171,57 +1196,57 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& n consideredQubits.size() - 1) + architecture->fidelityDistance( static_cast(node.locations.at(q1)), q4, - consideredQubits.size()- 1)); + consideredQubits.size() - 1)); } if (edgeDone) { const double currEdgeCost = (forwardMult * - architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))) + - reverseMult * - architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q2)), - static_cast(node.locations.at(q1)))); + architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q1)), + static_cast(node.locations.at(q2))) + + reverseMult * + architecture->getTwoQubitFidelityCost( + static_cast(node.locations.at(q2)), + static_cast(node.locations.at(q1)))); savingsPotential += (currEdgeCost - swapCost); } else { costHeur += swapCost; } } - + return costHeur - savingsPotential; } - void HeuristicMapper::updateHeuristicCost(std::size_t layer, Node& node) { // the mapping is valid, only if all qubit pairs are mapped next to each other node.validMapping = (node.validMappedTwoQubitGates.size() == twoQubitMultiplicities.at(layer).size()); - + switch (results.config.heuristic) { - case Heuristic::GateCountMaxDistance: - node.costHeur = heuristicGateCountMaxDistance(layer, node); - break; - case Heuristic::GateCountSumDistance: - node.costHeur = heuristicGateCountSumDistance(layer, node); - break; - case Heuristic::GateCountSumDistanceMinusSharedSwaps: - node.costHeur = heuristicGateCountSumDistanceMinusSharedSwaps(layer, node); - break; - case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: - node.costHeur = heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(layer, node); - break; - case Heuristic::FidelityBestLocation: - node.costHeur = heuristicFidelityBestLocation(layer, node); - break; - default: - throw QMAPException("Unknown heuristic."); + case Heuristic::GateCountMaxDistance: + node.costHeur = heuristicGateCountMaxDistance(layer, node); + break; + case Heuristic::GateCountSumDistance: + node.costHeur = heuristicGateCountSumDistance(layer, node); + break; + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + node.costHeur = heuristicGateCountSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + node.costHeur = + heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::FidelityBestLocation: + node.costHeur = heuristicFidelityBestLocation(layer, node); + break; + default: + throw QMAPException("Unknown heuristic."); } } - -void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicMapper::Node& node) { +void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, + HeuristicMapper::Node& node) { const auto& config = results.config; auto nextLayer = getNextLayer(layer); double factor = config.firstLookaheadFactor; @@ -1232,8 +1257,7 @@ void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicM } double penalty = 0.; - switch (config.lookaheadHeuristic) - { + switch (config.lookaheadHeuristic) { case LookaheadHeuristic::GateCountMaxDistance: penalty = lookaheadGateCountMaxDistance(nextLayer, node); break; @@ -1251,12 +1275,14 @@ void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicM } } -double HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, HeuristicMapper::Node& node) { +double +HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, + HeuristicMapper::Node& node) { double penalty = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - + auto loc1 = node.locations.at(q1); auto loc2 = node.locations.at(q2); if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { @@ -1276,31 +1302,29 @@ double HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, H 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( - static_cast(loc1), - j)); + min = std::min(min, distanceOnArchitectureOfPhysicalQubits( + static_cast(loc1), j)); } } penalty = std::max(penalty, min); } else { - auto cost = architecture->distance( - static_cast(loc1), - static_cast(loc2)); - penalty = std::max(penalty, cost); + auto cost = architecture->distance(static_cast(loc1), + static_cast(loc2)); + penalty = std::max(penalty, cost); } } - + return penalty; } - -double HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, HeuristicMapper::Node& node) { +double +HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, + HeuristicMapper::Node& node) { double penalty = 0.; - + for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - + auto loc1 = node.locations.at(q1); auto loc2 = node.locations.at(q2); if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { @@ -1320,20 +1344,17 @@ double HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, H 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( - static_cast(loc1), - j)); + min = std::min(min, distanceOnArchitectureOfPhysicalQubits( + static_cast(loc1), j)); } } penalty = min; } else { - auto cost = architecture->distance( - static_cast(loc1), - static_cast(loc2)); - penalty = cost; + auto cost = architecture->distance(static_cast(loc1), + static_cast(loc2)); + penalty = cost; } } - + return penalty; -} \ No newline at end of file +} diff --git a/src/mqt/qmap/compile.py b/src/mqt/qmap/compile.py index e406778c5..f6d47f820 100644 --- a/src/mqt/qmap/compile.py +++ b/src/mqt/qmap/compile.py @@ -22,8 +22,8 @@ CommanderGrouping, Configuration, Encoding, - InitialLayout, Heuristic, + InitialLayout, Layering, LookaheadHeuristic, MappingResults, diff --git a/src/python/bindings.cpp b/src/python/bindings.cpp index 1ce4d1104..d237c2a1c 100644 --- a/src/python/bindings.cpp +++ b/src/python/bindings.cpp @@ -122,13 +122,15 @@ PYBIND11_MODULE(pyqmap, m) { .def(py::init([](const std::string& str) -> InitialLayout { return initialLayoutFromString(str); })); - + // Heuristic function py::enum_(m, "Heuristic") .value("gate_count_max_distance", Heuristic::GateCountMaxDistance) .value("gate_count_sum_distance", Heuristic::GateCountSumDistance) - .value("gate_count_sum_distance_minus_shared_swaps", Heuristic::GateCountSumDistanceMinusSharedSwaps) - .value("gate_count_max_distance_or_sum_distance_minus_shared_swaps", Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps) + .value("gate_count_sum_distance_minus_shared_swaps", + Heuristic::GateCountSumDistanceMinusSharedSwaps) + .value("gate_count_max_distance_or_sum_distance_minus_shared_swaps", + Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps) .value("fidelity_best_location", Heuristic::FidelityBestLocation) .export_values() // allow construction from string @@ -139,8 +141,10 @@ PYBIND11_MODULE(pyqmap, m) { // Lookahead heuristic function py::enum_(m, "LookaheadHeuristic") .value("none", LookaheadHeuristic::None) - .value("gate_count_max_distance", LookaheadHeuristic::GateCountMaxDistance) - .value("gate_count_sum_distance", LookaheadHeuristic::GateCountSumDistance) + .value("gate_count_max_distance", + LookaheadHeuristic::GateCountMaxDistance) + .value("gate_count_sum_distance", + LookaheadHeuristic::GateCountSumDistance) .export_values() // allow construction from string .def(py::init([](const std::string& str) -> LookaheadHeuristic { diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index ce89a3fe2..16eaa3dc8 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -16,122 +16,137 @@ /** * @brief Get id of the final node in a given layer from a data log. */ -std::size_t getFinalNodeFromDatalog(std::string dataLoggingPath, std::size_t layer) { +std::size_t getFinalNodeFromDatalog(std::string dataLoggingPath, + std::size_t layer) { auto layerFile = std::ifstream(dataLoggingPath + "/layer_" + - std::to_string(layer) + ".json"); + std::to_string(layer) + ".json"); if (!layerFile.is_open()) { - throw std::runtime_error("Could not open file " + dataLoggingPath + - "/layer_" + std::to_string(layer) + ".json"); + throw std::runtime_error("Could not open file " + dataLoggingPath + + "/layer_" + std::to_string(layer) + ".json"); } - const auto layerJson = nlohmann::json::parse(layerFile); + const auto layerJson = nlohmann::json::parse(layerFile); if (layerJson.find("final_node_id") == layerJson.end()) { - throw std::runtime_error("Missing key \"final_node_id\" in " + dataLoggingPath + - "/layer_" + std::to_string(layer) + ".json"); + throw std::runtime_error("Missing key \"final_node_id\" in " + + dataLoggingPath + "/layer_" + + std::to_string(layer) + ".json"); } const std::size_t finalNodeId = layerJson["final_node_id"]; return finalNodeId; } /** - * @brief parses all nodes in a given layer from a data log and enter them + * @brief parses all nodes in a given layer from a data log and enter them * into `nodes` with each node at the position corresponding to its id. - * - * Only logged values are entered into the nodes, all other values are left at + * + * Only logged values are entered into the nodes, all other values are left at * default (e.g. `validMappedTwoQubitGates` and `sharedSwaps`) */ -void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::vector& nodes) { - std::string layerNodeFilePath = dataLoggingPath + "/nodes_layer_" + std::to_string(layer) + ".csv"; +void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, + std::vector& nodes) { + std::string layerNodeFilePath = + dataLoggingPath + "/nodes_layer_" + std::to_string(layer) + ".csv"; auto layerNodeFile = std::ifstream(layerNodeFilePath); if (!layerNodeFile.is_open()) { throw std::runtime_error("Could not open file " + layerNodeFilePath); } - std::string line; + std::string line; while (std::getline(layerNodeFile, line)) { if (line.empty()) { continue; } - std::string col; - std::size_t nodeId = 0; - + std::string col; + std::size_t nodeId = 0; + std::vector layout{}; std::vector> swaps{}; std::stringstream lineStream(line); if (std::getline(lineStream, col, ';')) { nodeId = std::stoull(col); if (nodeId >= nodes.size()) { - throw std::runtime_error("Node id " + std::to_string(nodeId) + " out of range in " + layerNodeFilePath); + throw std::runtime_error("Node id " + std::to_string(nodeId) + + " out of range in " + layerNodeFilePath); } nodes[nodeId].id = nodeId; } else { - throw std::runtime_error("Missing value for node id in " + layerNodeFilePath); + throw std::runtime_error("Missing value for node id in " + + layerNodeFilePath); } auto& node = nodes[nodeId]; if (std::getline(lineStream, col, ';')) { node.parent = std::stoull(col); } else { - throw std::runtime_error("Missing value for parent node id in " + layerNodeFilePath); + throw std::runtime_error("Missing value for parent node id in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { node.costFixed = std::stod(col); } else { - throw std::runtime_error("Missing value for fixed cost in " + layerNodeFilePath); + throw std::runtime_error("Missing value for fixed cost in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { node.costHeur = std::stod(col); } else { - throw std::runtime_error("Missing value for heuristic cost in " + layerNodeFilePath); + throw std::runtime_error("Missing value for heuristic cost in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { node.lookaheadPenalty = std::stod(col); } else { - throw std::runtime_error("Missing value for lookahead penalty in " + layerNodeFilePath); + throw std::runtime_error("Missing value for lookahead penalty in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { std::size_t validMapping = std::stoull(col); if (validMapping > 1) { - throw std::runtime_error("Non-boolean value " + std::to_string(validMapping) + - " for validMapping in " + layerNodeFilePath); + throw std::runtime_error("Non-boolean value " + + std::to_string(validMapping) + + " for validMapping in " + layerNodeFilePath); } node.validMapping = static_cast(validMapping); } else { - throw std::runtime_error("Missing value for validMapping in " + layerNodeFilePath); + throw std::runtime_error("Missing value for validMapping in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { node.depth = std::stoull(col); } else { - throw std::runtime_error("Missing value for depth in " + layerNodeFilePath); + throw std::runtime_error("Missing value for depth in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { for (std::size_t i = 0; i < MAX_DEVICE_QUBITS; ++i) { - node.qubits[i] = -1; + node.qubits[i] = -1; node.locations[i] = -1; } - + std::stringstream qubitMapBuffer(col); std::string entry; for (std::size_t i = 0; std::getline(qubitMapBuffer, entry, ','); ++i) { - auto qubit = static_cast(std::stoi(entry)); + auto qubit = static_cast(std::stoi(entry)); node.qubits[i] = qubit; if (qubit >= 0) { node.locations[qubit] = static_cast(i); } } } else { - throw std::runtime_error("Missing value for qubit layout in " + layerNodeFilePath); + throw std::runtime_error("Missing value for qubit layout in " + + layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { std::stringstream swapBuffer(col); std::string entry; while (std::getline(swapBuffer, entry, ',')) { - std::uint16_t q1 = 0; - std::uint16_t q2 = 0; - std::string opTypeStr = ""; + std::uint16_t q1 = 0; + std::uint16_t q2 = 0; + std::string opTypeStr = ""; std::stringstream(entry) >> q1 >> q2 >> opTypeStr; qc::OpType opType = qc::OpType::SWAP; if (opTypeStr.size() > 0) { opType = qc::opTypeFromString(opTypeStr); } - // ignoring op type for now, which is logged as 3rd value unless it is SWAP + // ignoring op type for now, which is logged as 3rd value unless it is + // SWAP node.swaps.emplace_back(q1, q2, opType); } } @@ -139,12 +154,15 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std:: } /** - * @brief Get the path from a node to the root node (id of the given node is the first element, id of the root is last) - * - * @param nodes vector of all nodes (each at the position corresponding to its id) + * @brief Get the path from a node to the root node (id of the given node is the + * first element, id of the root is last) + * + * @param nodes vector of all nodes (each at the position corresponding to its + * id) * @param nodeId id of the node from which to find the path to the root */ -std::vector getPathToRoot(std::vector& nodes, std::size_t nodeId) { +std::vector +getPathToRoot(std::vector& nodes, std::size_t nodeId) { std::vector path{}; if (nodeId >= nodes.size() || nodes[nodeId].id != nodeId) { throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); @@ -153,7 +171,9 @@ std::vector getPathToRoot(std::vector& nodes while (node.parent != node.id) { path.push_back(node.id); if (node.parent >= nodes.size() || nodes[node.parent].id != node.parent) { - throw std::runtime_error("Invalid parent id " + std::to_string(node.parent) + " for node " + std::to_string(node.id)); + throw std::runtime_error("Invalid parent id " + + std::to_string(node.parent) + " for node " + + std::to_string(node.id)); } node = nodes[node.parent]; } @@ -161,25 +181,21 @@ std::vector getPathToRoot(std::vector& nodes return path; } - - - Architecture internalsTestArchitecture{1, {}}; class InternalsTest : public HeuristicMapper, public testing::Test { - protected: - InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, internalsTestArchitecture) {} - void SetUp() override { - results = MappingResults{}; - } +protected: + InternalsTest() + : HeuristicMapper(qc::QuantumComputation{1}, internalsTestArchitecture) {} + void SetUp() override { results = MappingResults{}; } }; TEST_F(InternalsTest, NodeCostCalculation) { - const double tolerance = 1e-6; - - results.config.heuristic = Heuristic::GateCountMaxDistance; + const double tolerance = 1e-6; + + results.config.heuristic = Heuristic::GateCountMaxDistance; results.config.lookaheadHeuristic = LookaheadHeuristic::None; - results.config.layering = Layering::Disjoint2qBlocks; - + results.config.layering = Layering::Disjoint2qBlocks; + architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); qc = qc::QuantumComputation{5}; qc.cx(qc::Control{0}, 1); @@ -191,51 +207,54 @@ TEST_F(InternalsTest, NodeCostCalculation) { qc.cx(qc::Control{1}, 0); qc.cx(qc::Control{3}, 2); createLayers(); - - EXPECT_EQ(layers.size(), 1) << "layering failed, not able to test node cost calculation"; - - const std::vector swaps{ - Exchange(0, 1, qc::OpType::Teleportation), - Exchange(1, 2, qc::OpType::SWAP)}; - - HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, {{2, 3}}, 5., 0); + + EXPECT_EQ(layers.size(), 1) + << "layering failed, not able to test node cost calculation"; + + const std::vector swaps{Exchange(0, 1, qc::OpType::Teleportation), + Exchange(1, 2, qc::OpType::SWAP)}; + + HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, + {{2, 3}}, 5., 0); EXPECT_NEAR(node.costFixed, 5., tolerance); EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 1); - + results.config.heuristic = Heuristic::GateCountSumDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 14 + COST_DIRECTION_REVERSE * 3, tolerance); - EXPECT_NEAR(node.costFixed, 5., tolerance) << "updateHeuristicCost should not change costFixed"; - + EXPECT_NEAR(node.costFixed, 5., tolerance) + << "updateHeuristicCost should not change costFixed"; + results.config.heuristic = Heuristic::GateCountMaxDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); - EXPECT_NEAR(node.costFixed, 5., tolerance) << "updateHeuristicCost should not change costFixed"; - - applySWAP({3, 4}, 0 , node); + EXPECT_NEAR(node.costFixed, 5., tolerance) + << "updateHeuristicCost should not change costFixed"; + + applySWAP({3, 4}, 0, node); EXPECT_NEAR(node.costFixed, 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, tolerance); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); - + node.lookaheadPenalty = 0.; EXPECT_NEAR(node.getTotalCost(), 5. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); EXPECT_NEAR(node.getTotalFixedCost(), 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); - + node.lookaheadPenalty = 2.; EXPECT_NEAR(node.getTotalCost(), 7. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); EXPECT_NEAR(node.getTotalFixedCost(), 7. + COST_UNIDIRECTIONAL_SWAP, tolerance); - + recalculateFixedCost(0, node); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); EXPECT_NEAR(node.costFixed, COST_TELEPORTATION + COST_UNIDIRECTIONAL_SWAP * 2, @@ -251,8 +270,8 @@ TEST_F(InternalsTest, NodeCostCalculation) { tolerance); } - -class TestHeuristics : public testing::TestWithParam> { +class TestHeuristics + : public testing::TestWithParam> { protected: std::string testExampleDir = "../examples/"; std::string testArchitectureDir = "../extern/architectures/"; @@ -277,41 +296,37 @@ class TestHeuristics : public testing::TestWithParam(qc, ibmqLondon); ibmQX5.loadCouplingMap(AvailableArchitecture::IbmQx5); ibmQX5Mapper = std::make_unique(qc, ibmQX5); - settings.debug = true; + settings.debug = true; settings.automaticLayerSplits = false; - settings.initialLayout = InitialLayout::Identity; - settings.layering = Layering::DisjointQubits; - settings.lookaheadHeuristic = LookaheadHeuristic::None; - settings.heuristic = std::get<0>(GetParam()); - settings.dataLoggingPath = "test_log"; + settings.initialLayout = InitialLayout::Identity; + settings.layering = Layering::DisjointQubits; + settings.lookaheadHeuristic = LookaheadHeuristic::None; + settings.heuristic = std::get<0>(GetParam()); + settings.dataLoggingPath = "test_log"; } }; INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, testing::Combine( - testing::Values( - Heuristic::GateCountMaxDistance, - Heuristic::GateCountSumDistance, - Heuristic::GateCountSumDistanceMinusSharedSwaps, - Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps, - Heuristic::FidelityBestLocation - ), - testing::Values( - "3_17_13", // 5q - "ex-1_166", // 5q - "ham3_102", // 5q - "miller_11", // 5q - "4gt11_84", // 5q - "4mod5-v0_20", // 5q - "mod5d1_63", // 5q - "ising_model_10", // 16q - "rd73_140", // 16q - "cnt3-5_179", // 16q - "qft_16", // 16q - "z4_268" // 16q - ) - ), + testing::Values( + Heuristic::GateCountMaxDistance, Heuristic::GateCountSumDistance, + Heuristic::GateCountSumDistanceMinusSharedSwaps, + Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps, + Heuristic::FidelityBestLocation), + testing::Values("3_17_13", // 5q + "ex-1_166", // 5q + "ham3_102", // 5q + "miller_11", // 5q + "4gt11_84", // 5q + "4mod5-v0_20", // 5q + "mod5d1_63", // 5q + "ising_model_10", // 16q + "rd73_140", // 16q + "cnt3-5_179", // 16q + "qft_16", // 16q + "z4_268" // 16q + )), [](const testing::TestParamInfo& inf) { std::string name = std::get<1>(inf.param); std::replace(name.begin(), name.end(), '-', '_'); @@ -321,11 +336,13 @@ INSTANTIATE_TEST_SUITE_P( }); TEST_P(TestHeuristics, HeuristicProperties) { - EXPECT_TRUE(!isAdmissible(settings.heuristic) || isPrincipallyAdmissible(settings.heuristic)) << "Admissible heuristics are by definition also principally admissible"; - + EXPECT_TRUE(!isAdmissible(settings.heuristic) || + isPrincipallyAdmissible(settings.heuristic)) + << "Admissible heuristics are by definition also principally admissible"; + std::vector> allNodes{}; - std::vector finalSolutionIds{}; - + std::vector finalSolutionIds{}; + if (qc.getNqubits() <= ibmqYorktown.getNqubits()) { if (isFidelityAware(settings.heuristic)) { EXPECT_THROW(ibmqYorktownMapper->map(settings), QMAPException); @@ -333,23 +350,27 @@ TEST_P(TestHeuristics, HeuristicProperties) { ibmqYorktownMapper->map(settings); auto results = ibmqYorktownMapper->getResults(); for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { - allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); + allNodes.emplace_back( + results.layerHeuristicBenchmark.at(i).generatedNodes); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); - finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + finalSolutionIds.push_back( + getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } } - + if (qc.getNqubits() <= ibmqLondon.getNqubits()) { ibmqLondonMapper->map(settings); auto results = ibmqLondonMapper->getResults(); for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { - allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); - parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); - finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + allNodes.emplace_back( + results.layerHeuristicBenchmark.at(i).generatedNodes); + parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); + finalSolutionIds.push_back( + getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } - + if (qc.getNqubits() <= ibmQX5.getNqubits()) { if (isFidelityAware(settings.heuristic)) { EXPECT_THROW(ibmQX5Mapper->map(settings), QMAPException); @@ -357,57 +378,73 @@ TEST_P(TestHeuristics, HeuristicProperties) { ibmQX5Mapper->map(settings); auto results = ibmQX5Mapper->getResults(); for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { - allNodes.emplace_back(results.layerHeuristicBenchmark.at(i).generatedNodes); + allNodes.emplace_back( + results.layerHeuristicBenchmark.at(i).generatedNodes); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); - finalSolutionIds.push_back(getFinalNodeFromDatalog(settings.dataLoggingPath, i)); + finalSolutionIds.push_back( + getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } } - + for (std::size_t i = 0; i < allNodes.size(); ++i) { - auto& nodes = allNodes.at(i); + auto& nodes = allNodes.at(i); auto& finalSolutionId = finalSolutionIds.at(i); - - if (finalSolutionId >= nodes.size() || nodes.at(finalSolutionId).id != finalSolutionId) { - FAIL() << "Final solution node " << finalSolutionId << " not found in nodes of layer " << i; + + if (finalSolutionId >= nodes.size() || + nodes.at(finalSolutionId).id != finalSolutionId) { + FAIL() << "Final solution node " << finalSolutionId + << " not found in nodes of layer " << i; } auto& finalSolutionNode = nodes.at(finalSolutionId); EXPECT_TRUE(finalSolutionNode.validMapping); - + if (isPrincipallyAdmissible(settings.heuristic)) { auto solutionPath = getPathToRoot(nodes, finalSolutionId); for (auto nodeId : solutionPath) { auto& node = nodes.at(nodeId); - EXPECT_LE(node.getTotalCost(), finalSolutionNode.costFixed) << "Heuristic " << toString(settings.heuristic) << " is not principally admissible"; + EXPECT_LE(node.getTotalCost(), finalSolutionNode.costFixed) + << "Heuristic " << toString(settings.heuristic) + << " is not principally admissible"; } } - + for (std::size_t j = 0; j < nodes.size(); ++j) { const auto& node = nodes.at(j); if (j != node.id) { continue; } - + // check non-decreasing total cost if (node.parent != node.id) { - if (node.parent >= nodes.size() || nodes.at(node.parent).id != node.parent) { - FAIL() << "Invalid parent id " << node.parent << " for node " << node.id; + if (node.parent >= nodes.size() || + nodes.at(node.parent).id != node.parent) { + FAIL() << "Invalid parent id " << node.parent << " for node " + << node.id; } - EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) << "Heuristic " << toString(settings.heuristic) << " does not result in non-decreasing cost estimation"; + EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) + << "Heuristic " << toString(settings.heuristic) + << " does not result in non-decreasing cost estimation"; } - - EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) << "Lookahead penalty not 0 even though lookahead has been deactivated"; - + + EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) + << "Lookahead penalty not 0 even though lookahead has been " + "deactivated"; + if (node.validMapping) { if (isTight(settings.heuristic)) { - EXPECT_NEAR(node.costHeur, 0., tolerance) << "Heuristic " << toString(settings.heuristic) << " is not tight"; + EXPECT_NEAR(node.costHeur, 0., tolerance) + << "Heuristic " << toString(settings.heuristic) + << " is not tight"; } - + if (isAdmissible(settings.heuristic)) { auto path = getPathToRoot(nodes, node.id); for (auto nodeId : path) { auto& n = nodes.at(nodeId); - EXPECT_LE(n.getTotalCost(), node.costFixed) << "Heuristic " << toString(settings.heuristic) << " is not admissible"; + EXPECT_LE(n.getTotalCost(), node.costFixed) + << "Heuristic " << toString(settings.heuristic) + << " is not admissible"; } } } @@ -415,7 +452,6 @@ TEST_P(TestHeuristics, HeuristicProperties) { } } - TEST(Functionality, HeuristicBenchmark) { /* 3 @@ -517,18 +553,18 @@ TEST(Functionality, InvalidSettings) { props.setSingleQubitErrorRate(0, "x", 0.1); arch.loadProperties(props); HeuristicMapper mapper(qc, arch); - auto config = Configuration{}; - config.method = Method::Heuristic; - config.heuristic = Heuristic::GateCountMaxDistance; + auto config = Configuration{}; + config.method = Method::Heuristic; + config.heuristic = Heuristic::GateCountMaxDistance; config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; // invalid layering - config.layering = Layering::OddGates; + config.layering = Layering::OddGates; EXPECT_THROW(mapper.map(config), QMAPException); config.layering = Layering::QubitTriangle; EXPECT_THROW(mapper.map(config), QMAPException); - config.layering = Layering::IndividualGates; + config.layering = Layering::IndividualGates; // fidelity-aware heuristic with non-fidelity-aware lookahead heuristic - config.heuristic = Heuristic::FidelityBestLocation; + config.heuristic = Heuristic::FidelityBestLocation; EXPECT_THROW(mapper.map(config), QMAPException); config.lookaheadHeuristic = LookaheadHeuristic::None; // fidelity-aware heuristic with teleportation @@ -760,7 +796,8 @@ TEST(Functionality, DataLogger) { toString(settings.initialLayout)); if (settings.lookaheadHeuristic != LookaheadHeuristic::None) { const auto& lookaheadJson = heuristicSettingsJson["lookahead"]; - EXPECT_EQ(lookaheadJson["heuristic"], toString(settings.lookaheadHeuristic)); + EXPECT_EQ(lookaheadJson["heuristic"], + toString(settings.lookaheadHeuristic)); EXPECT_EQ(lookaheadJson["factor"], settings.lookaheadFactor); EXPECT_EQ(lookaheadJson["first_factor"], settings.firstLookaheadFactor); EXPECT_EQ(lookaheadJson["lookaheads"], settings.nrLookaheads); @@ -866,17 +903,21 @@ TEST(Functionality, DataLogger) { EXPECT_EQ(layerJson["initial_layout"].size(), architecture.getNqubits()); EXPECT_EQ(layerJson["single_qubit_multiplicity"].size(), architecture.getNqubits()); - - std::vector nodes{results.layerHeuristicBenchmark.at(i).generatedNodes}; + + std::vector nodes{ + results.layerHeuristicBenchmark.at(i).generatedNodes}; parseNodesFromDatalog(settings.dataLoggingPath, i, nodes); - - if (finalNodeId >= nodes.size() || nodes.at(finalNodeId).id != finalNodeId) { - FAIL() << "Final solution node " << finalNodeId << " not found in nodes of layer " << i; + + if (finalNodeId >= nodes.size() || + nodes.at(finalNodeId).id != finalNodeId) { + FAIL() << "Final solution node " << finalNodeId + << " not found in nodes of layer " << i; } auto& finalSolutionNode = nodes.at(finalNodeId); EXPECT_EQ(layerJson["final_cost_fixed"], finalSolutionNode.costFixed); EXPECT_EQ(layerJson["final_cost_heur"], finalSolutionNode.costHeur); - EXPECT_EQ(layerJson["final_lookahead_penalty"], finalSolutionNode.lookaheadPenalty); + EXPECT_EQ(layerJson["final_lookahead_penalty"], + finalSolutionNode.lookaheadPenalty); EXPECT_EQ(layerJson["final_search_depth"], finalSolutionNode.depth); std::vector layout{}; for (std::size_t j = 0; j < architecture.getNqubits(); ++j) { @@ -889,24 +930,26 @@ TEST(Functionality, DataLogger) { EXPECT_EQ(layerJson["final_layout"], layout); EXPECT_EQ(layerJson["final_swaps"], swaps); EXPECT_EQ(finalSolutionNode.validMapping, true); - + for (std::size_t j = 0; j < nodes.size(); ++j) { auto& node = nodes.at(j); if (j != node.id) { continue; } - + for (std::size_t k = 0; k < architecture.getNqubits(); ++k) { EXPECT_GE(node.qubits[k], -1); EXPECT_LT(node.qubits[k], qc.getNqubits()); EXPECT_GE(node.locations[k], -1); EXPECT_LT(node.locations[k], architecture.getNqubits()); - + if (node.qubits[k] >= 0) { - EXPECT_EQ(node.locations[static_cast(node.qubits[k])], static_cast(k)); + EXPECT_EQ(node.locations[static_cast(node.qubits[k])], + static_cast(k)); } if (node.locations[k] >= 0) { - EXPECT_EQ(node.qubits[static_cast(node.locations[k])], static_cast(k)); + EXPECT_EQ(node.qubits[static_cast(node.locations[k])], + static_cast(k)); } } } From 2c46590f09506af2f2104ee2b3496148fbcad135 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Tue, 2 Jan 2024 23:41:32 +0100 Subject: [PATCH 06/47] adding comments to large test functions --- test/test_heuristic.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 95744b386..b7e75a412 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -49,6 +49,8 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, if (!layerNodeFile.is_open()) { throw std::runtime_error("Could not open file " + layerNodeFilePath); } + // iterating over the lines in the csv file and then over the entries + // separated by ';' std::string line; while (std::getline(layerNodeFile, line)) { if (line.empty()) { @@ -143,10 +145,9 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::stringstream(entry) >> q1 >> q2 >> opTypeStr; qc::OpType opType = qc::OpType::SWAP; if (opTypeStr.size() > 0) { + // if no opType is given, the default value is SWAP opType = qc::opTypeFromString(opTypeStr); } - // ignoring op type for now, which is logged as 3rd value unless it is - // SWAP node.swaps.emplace_back(q1, q2, opType); } } @@ -339,10 +340,14 @@ TEST_P(TestHeuristics, HeuristicProperties) { EXPECT_TRUE(!isAdmissible(settings.heuristic) || isPrincipallyAdmissible(settings.heuristic)) << "Admissible heuristics are by definition also principally admissible"; - + + // list of nodes for each search process (i.e. each layer) in all mappings + // each node is at the position corresponding to its id; positions of unused + // ids are filled with default values (i.e. node.id = 0) std::vector> allNodes{}; std::vector finalSolutionIds{}; - + + // map to IBM Yorktown if possible if (qc.getNqubits() <= ibmqYorktown.getNqubits()) { if (isFidelityAware(settings.heuristic)) { EXPECT_THROW(ibmqYorktownMapper->map(settings), QMAPException); @@ -358,7 +363,8 @@ TEST_P(TestHeuristics, HeuristicProperties) { } } } - + + // map to IBM London if possible if (qc.getNqubits() <= ibmqLondon.getNqubits()) { ibmqLondonMapper->map(settings); auto results = ibmqLondonMapper->getResults(); @@ -370,7 +376,8 @@ TEST_P(TestHeuristics, HeuristicProperties) { getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } - + + // map to IBM QX5 if possible if (qc.getNqubits() <= ibmQX5.getNqubits()) { if (isFidelityAware(settings.heuristic)) { EXPECT_THROW(ibmQX5Mapper->map(settings), QMAPException); @@ -400,6 +407,9 @@ TEST_P(TestHeuristics, HeuristicProperties) { EXPECT_TRUE(finalSolutionNode.validMapping); if (isPrincipallyAdmissible(settings.heuristic)) { + // for principally admissible heuristics all nodes on the optimal + // solution path should have + // node.costFixed+node.costHeur <= finalSolutionNode.costFixed auto solutionPath = getPathToRoot(nodes, finalSolutionId); for (auto nodeId : solutionPath) { auto& node = nodes.at(nodeId); @@ -433,12 +443,19 @@ TEST_P(TestHeuristics, HeuristicProperties) { if (node.validMapping) { if (isTight(settings.heuristic)) { + // tight heuristics are 0 in any goal node EXPECT_NEAR(node.costHeur, 0., tolerance) << "Heuristic " << toString(settings.heuristic) << " is not tight"; } if (isAdmissible(settings.heuristic)) { + // for admissible heuristics all nodes should have + // node.costFixed+node.costHeur <= solutionNode.costFixed, + // where solutionNode is the best goal node reachable from the node; + // since reachability in a directed tree is equivalent to the being + // on the same path to the root, one can also check that all nodes on + // the path to the root from any goal node fulfill this condition auto path = getPathToRoot(nodes, node.id); for (auto nodeId : path) { auto& n = nodes.at(nodeId); From c60d736539271741cb860d902e7b477bcf4ab39c Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 4 Jan 2024 02:17:48 +0100 Subject: [PATCH 07/47] fix CNOT reversals --- include/heuristic/HeuristicMapper.hpp | 3 +- include/utils.hpp | 59 +++++----- src/Architecture.cpp | 10 +- src/heuristic/HeuristicMapper.cpp | 154 +++++++++++++++++--------- src/utils.cpp | 77 +++++++------ test/test_general.cpp | 25 +---- 6 files changed, 184 insertions(+), 144 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 67279bb50..a3827c3e5 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -278,9 +278,10 @@ class HeuristicMapper : public Mapper { * @brief recalculates the gate-count-optimizing fixed cost of the node from * the current mapping and swaps * + * @param layer index of current circuit layer * @param node search node for which to recalculate the fixed cost */ - void recalculateFixedCostNonFidelity(Node& node); + void recalculateFixedCostNonFidelity(std::size_t layer, Node& node); /** * @brief calculates the heuristic cost of the current mapping in the node diff --git a/include/utils.hpp b/include/utils.hpp index 75d019299..0bf3ebf68 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -55,44 +55,30 @@ class QMAPException : public std::runtime_error { class Dijkstra { public: struct Node { - /** true if the path contains any forward edge - (i.e. an edge on which a CNOT with directionality q1->q2 - can be applied without the need of a CNOT reversal) */ - bool containsCorrectEdge = false; /** true if the node has already been expanded */ bool visited = false; /** current qubit */ std::optional pos = std::nullopt; /** current cost of the path */ double cost = -1.; - /** current cost of the path with the last swap removed */ - double prevCost = -1.; }; /** * @brief builds a distance table containing the minimal costs for moving - * logical qubits from one physical qubit to/next to another (along the - * cheapest path) + * logical qubits from one physical qubit to another (along the cheapest path) * * e.g. cost of moving qubit q1 onto q2: * distanceTable[q1][q2] * - * @param n size of the distance table (i.e. number of qubits) * @param couplingMap coupling map specifying all edges in the architecture * @param distanceTable target table * @param edgeWeights matrix containing costs for swapping any two, connected * qubits (this might be uniform for all edges or different for each edge, as * e.g. in the case of fidelity-aware distances or distances on * mixed bi/unidirectional architectures) - * @param reversalCost cost added if path consists only of back edges, i.e. - * the 2-qubit gate to be mapped would need to be reversed in any case - * (if reversal costs are handled elsewhere this should be set to 0) - * @param removeLastEdge if set to true, the cost for the last swap on any - * path is removed (i.e. distance is given for moving "next to" qubit) */ - static void buildTable(std::uint16_t n, const CouplingMap& couplingMap, - Matrix& distanceTable, const Matrix& edgeWeights, - double reversalCost, bool removeLastEdge); + static void buildTable(const CouplingMap& couplingMap, + Matrix& distanceTable, const Matrix& edgeWeights); /** * @brief builds a 3d matrix containing the distance tables giving the minimal * distances between 2 qubit when upto k edges can be skipped. @@ -102,39 +88,46 @@ class Dijkstra { * * if k > edgeSkipDistanceTable.size() a cost of 0 can be assumed * - * this implementation does not work with distance tables containing CNOT - * reversal costs or the last edge removed - * (only pure distances between 2 qubits) - * - * @param distanceTable 2d matrix containing pure distances between any 2 - * qubits: distanceTable[source][target] + * @param distanceTable 2d matrix containing distances between any 2 qubits: + * distanceTable[source][target] * @param couplingMap coupling map specifying all edges in the architecture * @param edgeSkipDistanceTable 3d target table */ static void buildEdgeSkipTable(const Matrix& distanceTable, const CouplingMap& couplingMap, std::vector& edgeSkipDistanceTable); + /** + * @brief builds a distance table containing the minimal costs for moving + * logical qubits from one physical qubit to another (along the cheapest path) + * while skipping a single edge, i.e. equivalent to buildEdgeSkipTable(...)[1] + * + * An additional reversal cost can be specified, which is added to the cost if + * the skipped edge is a back edge + * + * @param distanceTable 2d matrix containing distances between any 2 qubits: + * distanceTable[source][target] + * @param couplingMap coupling map specifying all edges in the architecture + * @param reversalCost cost for reversing an edge + * @param edgeSkipDistanceTable target distance table + */ + static void buildSingleEdgeSkipTable(const Matrix& distanceTable, + const CouplingMap& couplingMap, + const double reversalCost, + Matrix& edgeSkipDistanceTable); protected: static void dijkstra(const CouplingMap& couplingMap, std::vector& nodes, - std::uint16_t start, const Matrix& edgeWeights, - double reversalCost); + std::uint16_t start, const Matrix& edgeWeights); struct NodeComparator { bool operator()(const Node* x, const Node* y) { - if (x->cost != y->cost) { - return x->cost > y->cost; - } - return !x->containsCorrectEdge && y->containsCorrectEdge; + return x->cost > y->cost; } }; }; inline bool operator<(const Dijkstra::Node& x, const Dijkstra::Node& y) { - if (x.cost != y.cost) { - return x.cost < y.cost; - } - return x.containsCorrectEdge && !y.containsCorrectEdge; + return x.cost < y.cost; } /// Iterating routine through all combinations diff --git a/src/Architecture.cpp b/src/Architecture.cpp index 23cec6287..f7c782515 100644 --- a/src/Architecture.cpp +++ b/src/Architecture.cpp @@ -197,9 +197,10 @@ void Architecture::createDistanceTable() { edgeWeights.at(edge.first).at(edge.second) = COST_BIDIRECTIONAL_SWAP; } } - - Dijkstra::buildTable(nqubits, couplingMap, distanceTable, edgeWeights, - COST_DIRECTION_REVERSE, true); + + Matrix simpleDistanceTable{}; + Dijkstra::buildTable(couplingMap, simpleDistanceTable, edgeWeights); + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, COST_DIRECTION_REVERSE, distanceTable); } void Architecture::createFidelityTable() { @@ -264,8 +265,7 @@ void Architecture::createFidelityTable() { fidelityDistanceTables.clear(); if (fidelityAvailable) { Matrix distances = {}; - Dijkstra::buildTable(nqubits, couplingMap, distances, swapFidelityCosts, 0., - false); + Dijkstra::buildTable(couplingMap, distances, swapFidelityCosts); Dijkstra::buildEdgeSkipTable(distances, couplingMap, fidelityDistanceTables); } diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 55e93d29d..f3c6c92f2 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -1002,14 +1002,11 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { node.validMappedTwoQubitGates.clear(); for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { const auto [q1, q2] = edge; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); - if (architecture->isEdgeConnected( - {static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))}) || - architecture->isEdgeConnected( - {static_cast(node.locations.at(q2)), - static_cast( - node.locations.at(q1))})) { // validly mapped + if (architecture->isEdgeConnected({physQ1, physQ2}) || + architecture->isEdgeConnected({physQ2, physQ1})) { // validly mapped node.validMappedTwoQubitGates.emplace(q1, q2); } } @@ -1017,13 +1014,14 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { if (fidelityAwareHeur) { recalculateFixedCostFidelity(layer, node); } else { - recalculateFixedCostNonFidelity(node); + recalculateFixedCostNonFidelity(layer, node); } } -void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { +void HeuristicMapper::recalculateFixedCostNonFidelity(std::size_t layer, Node& node) { node.costFixed = 0; - + + // swap costs for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { if (architecture->bidirectional()) { @@ -1035,6 +1033,27 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { node.costFixed += COST_TELEPORTATION; } } + + // reversal costs of validly mapped two qubit gates + if (!architecture->bidirectional()) { + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + if (node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates not yet validly mapped are handled in the heuristic + continue; + } + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + if (!architecture->isEdgeConnected({physQ1, physQ2})) { + node.costFixed += forwardMult * COST_DIRECTION_REVERSE; + } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { + node.costFixed += reverseMult * COST_DIRECTION_REVERSE; + } + } + } } void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, @@ -1071,14 +1090,12 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, } const auto [q1, q2] = edge; const auto [forwardMult, reverseMult] = mult; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); node.costFixed += - (forwardMult * architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))) + - reverseMult * architecture->getTwoQubitFidelityCost( - static_cast(node.locations.at(q2)), - static_cast(node.locations.at(q1)))); + (forwardMult * architecture->getTwoQubitFidelityCost(physQ1, physQ2) + + reverseMult * architecture->getTwoQubitFidelityCost(physQ2, physQ1)); } } @@ -1087,11 +1104,23 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates already validly mapped are handled in the fixed cost + continue; + } + const auto& [q1, q2] = edge; - costHeur = std::max(costHeur, - architecture->distance( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2)))); + const auto [forwardMult, reverseMult] = multiplicity; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + if (forwardMult > 0) { + costHeur = std::max(costHeur, architecture->distance(physQ1, physQ2)); + } + if (reverseMult > 0) { + costHeur = std::max(costHeur, architecture->distance(physQ2, physQ1)); + } } return costHeur; @@ -1102,10 +1131,31 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates already validly mapped are handled in the fixed cost + continue; + } + const auto& [q1, q2] = edge; - costHeur += architecture->distance( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))); + const auto [forwardMult, reverseMult] = multiplicity; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + double swapCost = 0.; + + if (forwardMult == 0) { + // forwardMult == 0 && reverseMult > 0 + swapCost = architecture->distance(physQ2, physQ1); + } else if (reverseMult == 0) { + // forwardMult > 0 && reverseMult == 0 + swapCost = architecture->distance(physQ1, physQ2); + } else { + // forwardMult > 0 && reverseMult > 0 + swapCost = std::max(architecture->distance(physQ1, physQ2), + architecture->distance(physQ2, physQ1)); + } + costHeur += swapCost; } return costHeur; @@ -1116,10 +1166,31 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates already validly mapped are handled in the fixed cost + continue; + } + const auto& [q1, q2] = edge; - costHeur += architecture->distance( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))); + const auto [forwardMult, reverseMult] = multiplicity; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + double swapCost = 0.; + + if (forwardMult == 0) { + // forwardMult == 0 && reverseMult > 0 + swapCost = architecture->distance(physQ2, physQ1); + } else if (reverseMult == 0) { + // forwardMult > 0 && reverseMult == 0 + swapCost = architecture->distance(physQ1, physQ2); + } else { + // forwardMult > 0 && reverseMult > 0 + swapCost = std::min(architecture->distance(physQ1, physQ2), + architecture->distance(physQ2, physQ1)); + } + costHeur += swapCost; } // TODO: improve heuristic further by using number of 2Q blocks (for @@ -1143,34 +1214,11 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps( std::size_t layer, Node& node) { - double costMax = 0.; - double costSum = 0.; - - for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; - const double swapCost = architecture->distance( - static_cast(node.locations.at(q1)), - static_cast(node.locations.at(q2))); - costSum += swapCost; - costMax = std::max(costMax, swapCost); - } - - // TODO: improve heuristic further by using number of 2Q blocks (for - // gate-count-optimizing mapping qubit pairs will only travel towards - // each other, i.e. a qubit can only share 1 swap per qubit pair) - std::size_t n = activeQubits.size(); - double sharedSwapCostReduction = 0; - if (architecture->bidirectional()) { - sharedSwapCostReduction = - ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * - COST_BIDIRECTIONAL_SWAP; - } else { - sharedSwapCostReduction = - ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * - COST_UNIDIRECTIONAL_SWAP; - } - return std::max(costMax, costSum - sharedSwapCostReduction); + return std::max( + heuristicGateCountMaxDistance(layer, node), + heuristicGateCountSumDistanceMinusSharedSwaps(layer, node) + ); } double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, diff --git a/src/utils.cpp b/src/utils.cpp index 3e4b08133..c92cee955 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -7,40 +7,30 @@ #include -void Dijkstra::buildTable(const std::uint16_t n, const CouplingMap& couplingMap, - Matrix& distanceTable, const Matrix& edgeWeights, - const double reversalCost, - const bool removeLastEdge) { +void Dijkstra::buildTable(const CouplingMap& couplingMap, + Matrix& distanceTable, const Matrix& edgeWeights) { + const std::uint16_t n = edgeWeights.size(); // number of qubits + distanceTable.clear(); distanceTable.resize(n, std::vector(n, -1.)); for (std::uint16_t i = 0; i < n; ++i) { std::vector nodes(n); for (std::uint16_t j = 0; j < n; ++j) { - nodes.at(j).containsCorrectEdge = false; nodes.at(j).visited = false; nodes.at(j).pos = j; nodes.at(j).cost = -1.; - nodes.at(j).prevCost = -1.; } - // initially all paths assume that a CNOT reversal will be necessary, - // as soon as a forward edge is encountered along the path, the cost - // for the reversal is removed - nodes.at(i).cost = reversalCost; - nodes.at(i).prevCost = reversalCost; + nodes.at(i).cost = 0; - dijkstra(couplingMap, nodes, i, edgeWeights, reversalCost); + dijkstra(couplingMap, nodes, i, edgeWeights); for (std::uint16_t j = 0; j < n; ++j) { if (i == j) { distanceTable.at(i).at(j) = 0; } else { - if (removeLastEdge) { - distanceTable.at(i).at(j) = nodes.at(j).prevCost; - } else { - distanceTable.at(i).at(j) = nodes.at(j).cost; - } + distanceTable.at(i).at(j) = nodes.at(j).cost; } } } @@ -48,7 +38,7 @@ void Dijkstra::buildTable(const std::uint16_t n, const CouplingMap& couplingMap, void Dijkstra::dijkstra(const CouplingMap& couplingMap, std::vector& nodes, const std::uint16_t start, - const Matrix& edgeWeights, const double reversalCost) { + const Matrix& edgeWeights) { std::priority_queue, NodeComparator> queue{}; queue.push(&nodes.at(start)); while (!queue.empty()) { @@ -59,14 +49,8 @@ void Dijkstra::dijkstra(const CouplingMap& couplingMap, for (const auto& edge : couplingMap) { std::optional to = std::nullopt; - // if the path up to here already contains a forward edge, we do not care - // about the directionality of other edges anymore; the value of the last - // node is therefore kept and only overwritten with true if the current - // edge is a forward edge (but never with false) - bool correctEdge = current->containsCorrectEdge; if (pos == edge.first) { // forward edge - to = edge.second; - correctEdge = true; + to = edge.second; } else if (pos == edge.second) { // back edge to = edge.first; } @@ -77,15 +61,7 @@ void Dijkstra::dijkstra(const CouplingMap& couplingMap, Node newNode; newNode.cost = current->cost + edgeWeights.at(*pos).at(*to); - newNode.prevCost = current->cost; newNode.pos = to; - newNode.containsCorrectEdge = correctEdge; - if (newNode.containsCorrectEdge && !current->containsCorrectEdge) { - // when encountering the first forward edge along the path, the - // reversal costs need to be removed - newNode.cost -= reversalCost; - newNode.prevCost -= reversalCost; - } if (nodes.at(*to).cost < 0 || newNode < nodes.at(*to)) { nodes.at(*to) = newNode; queue.push(&nodes.at(*to)); @@ -150,6 +126,41 @@ void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, } } +void Dijkstra::buildSingleEdgeSkipTable(const Matrix& distanceTable, + const CouplingMap& couplingMap, + const double reversalCost, + Matrix& edgeSkipDistanceTable) { + const std::size_t n = distanceTable.size(); + edgeSkipDistanceTable.clear(); + edgeSkipDistanceTable.resize(n, std::vector(n, std::numeric_limits::max())); + for (std::size_t q = 0; q < n; ++q) { + edgeSkipDistanceTable.at(q).at(q) = 0.; + } + for (const auto& [e1, e2] : couplingMap) { // edge to be skipped + for (std::size_t q1 = 0; q1 < n; ++q1) { // q1 ... source qubit + for (std::size_t q2 = q1 + 1; q2 < n; ++q2) { // q2 ... target qubit + edgeSkipDistanceTable.at(q1).at(q2) = + std::min(edgeSkipDistanceTable.at(q1).at(q2), + distanceTable.at(q1).at(e1) + distanceTable.at(e2).at(q2)); + edgeSkipDistanceTable.at(q1).at(q2) = + std::min(edgeSkipDistanceTable.at(q1).at(q2), + distanceTable.at(q1).at(e2) + distanceTable.at(e1).at(q2) + reversalCost); + if (reversalCost == 0.) { + edgeSkipDistanceTable.at(q2).at(q1) = edgeSkipDistanceTable.at(q1).at(q2); + } else { + edgeSkipDistanceTable.at(q2).at(q1) = + std::min(edgeSkipDistanceTable.at(q2).at(q1), + distanceTable.at(q2).at(e1) + distanceTable.at(e2).at(q1)); + edgeSkipDistanceTable.at(q2).at(q1) = + std::min(edgeSkipDistanceTable.at(q2).at(q2), + distanceTable.at(q2).at(e2) + distanceTable.at(e1).at(q1) + reversalCost); + } + + } + } + } +} + /// Create a string representation of a given permutation /// \param pi permutation /// \return string representation of pi diff --git a/test/test_general.cpp b/test/test_general.cpp index fb82c65fd..9cbc7c1b2 100644 --- a/test/test_general.cpp +++ b/test/test_general.cpp @@ -72,14 +72,8 @@ TEST(General, Dijkstra) { const Matrix targetTable1 = { {0, 1, 3, 6}, {1, 0, 2, 5}, {10, 9, 0, 3}, {7, 6, 3, 0}}; Matrix distanceTable{}; - Dijkstra::buildTable(4, cm, distanceTable, edgeWeights, 0, false); + Dijkstra::buildTable(cm, distanceTable, edgeWeights); EXPECT_EQ(distanceTable, targetTable1); - - const Matrix targetTable2 = { - {0, 0, 1, 3}, {0, 0, 0, 2}, {9, 3, 0, 0}, {6, 0, 0, 0}}; - distanceTable = {}; - Dijkstra::buildTable(4, cm, distanceTable, edgeWeights, 0, true); - EXPECT_EQ(distanceTable, targetTable2); } TEST(General, DijkstraCNOTReversal) { @@ -94,23 +88,16 @@ TEST(General, DijkstraCNOTReversal) { {0, 3, 0, 3, 0}, {0, 0, 3, 0, 3}, {0, 0, 0, 3, 0}}; - - const Matrix targetTable1 = {{0, 3, 6, 9, 12}, - {4, 0, 4, 6, 9}, - {6, 3, 0, 3, 6}, - {9, 6, 4, 0, 3}, - {12, 9, 7, 4, 0}}; - Matrix distanceTable{}; - Dijkstra::buildTable(5, cm, distanceTable, edgeWeights, 1, false); - EXPECT_EQ(distanceTable, targetTable1); + Matrix simpleDistanceTable{}; + Dijkstra::buildTable(cm, simpleDistanceTable, edgeWeights); + Matrix distanceTable{}; + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, cm, 1., distanceTable); const Matrix targetTable2 = {{0, 0, 3, 6, 9}, {1, 0, 1, 3, 6}, {3, 0, 0, 0, 3}, {6, 3, 1, 0, 0}, {9, 6, 4, 1, 0}}; - distanceTable = {}; - Dijkstra::buildTable(5, cm, distanceTable, edgeWeights, 1, true); EXPECT_EQ(distanceTable, targetTable2); } @@ -147,7 +134,7 @@ TEST(General, DijkstraSkipEdges) { {6, 8, 7, 6, 4, 2, 0, 1, 2, 3}, {7, 9, 8, 7, 5, 3, 1, 0, 1, 2}, {8, 10, 9, 8, 6, 4, 2, 1, 0, 1}, {9, 11, 10, 9, 7, 5, 3, 2, 1, 0}}; Matrix distanceTable{}; - Dijkstra::buildTable(10, cm, distanceTable, edgeWeights, 0, false); + Dijkstra::buildTable(cm, distanceTable, edgeWeights); EXPECT_EQ(distanceTable, targetTable); const std::vector edgeSkipTargetTable = { From e0305046e6a90f2b50939ef93d32b49381258f25 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 02:15:52 +0100 Subject: [PATCH 08/47] fix further bugs in heuristic properties test --- src/utils.cpp | 2 +- test/test_heuristic.cpp | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index c92cee955..a71de95e1 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -152,7 +152,7 @@ void Dijkstra::buildSingleEdgeSkipTable(const Matrix& distanceTable, std::min(edgeSkipDistanceTable.at(q2).at(q1), distanceTable.at(q2).at(e1) + distanceTable.at(e2).at(q1)); edgeSkipDistanceTable.at(q2).at(q1) = - std::min(edgeSkipDistanceTable.at(q2).at(q2), + std::min(edgeSkipDistanceTable.at(q2).at(q1), distanceTable.at(q2).at(e2) + distanceTable.at(e1).at(q1) + reversalCost); } diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index b7e75a412..177f1f09b 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -58,9 +58,7 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, } std::string col; std::size_t nodeId = 0; - - std::vector layout{}; - std::vector> swaps{}; + std::stringstream lineStream(line); if (std::getline(lineStream, col, ';')) { nodeId = std::stoull(col); @@ -168,17 +166,17 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { if (nodeId >= nodes.size() || nodes[nodeId].id != nodeId) { throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); } - auto& node = nodes[nodeId]; - while (node.parent != node.id) { - path.push_back(node.id); - if (node.parent >= nodes.size() || nodes[node.parent].id != node.parent) { + auto node = &nodes[nodeId]; + while (node->parent != node->id) { + path.push_back(node->id); + if (node->parent >= nodes.size() || nodes[node->parent].id != node->parent) { throw std::runtime_error("Invalid parent id " + - std::to_string(node.parent) + " for node " + - std::to_string(node.id)); + std::to_string(node->parent) + " for node " + + std::to_string(node->id)); } - node = nodes[node.parent]; + node = &nodes[node->parent]; } - path.push_back(node.id); + path.push_back(node->id); return path; } @@ -412,8 +410,10 @@ TEST_P(TestHeuristics, HeuristicProperties) { // node.costFixed+node.costHeur <= finalSolutionNode.costFixed auto solutionPath = getPathToRoot(nodes, finalSolutionId); for (auto nodeId : solutionPath) { - auto& node = nodes.at(nodeId); - EXPECT_LE(node.getTotalCost(), finalSolutionNode.costFixed) + if (nodes.at(nodeId).id != nodeId) { + throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); + } + EXPECT_LE(nodes.at(nodeId).getTotalCost(), finalSolutionNode.costFixed) << "Heuristic " << toString(settings.heuristic) << " is not principally admissible"; } From 318a700d62e23e3221484a0b14e3df9ec67cf672 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 19:06:43 +0100 Subject: [PATCH 09/47] move reversals into costFixed for goal nodes --- include/configuration/Heuristic.hpp | 17 + include/heuristic/HeuristicMapper.hpp | 35 ++- src/heuristic/HeuristicMapper.cpp | 429 ++++++++++++++------------ test/test_heuristic.cpp | 26 +- 4 files changed, 282 insertions(+), 225 deletions(-) diff --git a/include/configuration/Heuristic.hpp b/include/configuration/Heuristic.hpp index fbd78b3d9..37efab2eb 100644 --- a/include/configuration/Heuristic.hpp +++ b/include/configuration/Heuristic.hpp @@ -47,6 +47,23 @@ enum class Heuristic { return false; } +/** + * A heuristic is non-decreasing if the estimated cost (i.e. c(n) + h(n)) is + * non-decreasing along any path. + */ +[[maybe_unused]] static inline bool isNonDecreasing(const Heuristic heuristic) { + switch (heuristic) { + case Heuristic::GateCountMaxDistance: + case Heuristic::FidelityBestLocation: + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + return true; + case Heuristic::GateCountSumDistance: + return false; + } + return false; +} + /** * A heuristic is principally admissible if it never overestimates the cost of * the globally optimal solution along the solution path, i.e. c(n*) <= c(n) + diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index a3827c3e5..dc08eb704 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -49,10 +49,19 @@ class HeuristicMapper : public Mapper { * The inverse of `qubits` */ std::array locations{}; - /** current fixed cost (for non-fidelity-aware mapping cost of all swaps - * already added) */ - double costFixed = 0; - /** heuristic cost expected for future swaps needed in current circuit layer + /** current fixed cost + * + * non-fidelity-aware: cost of all swaps used in the node + * + * fidelity-aware: fidelity cost of all swaps used in the node + fidelity + * cost of all validly mapped gates at their current position + */ + double costFixed = 0.; + /** current fixed cost of reversals (only for non-fidelity-aware mapping + * and only in goal nodes)*/ + double costFixedReversals = 0.; + /** heuristic cost (i.e. expected difference from current cost to cost of + * the best reachable goal node) */ double costHeur = 0.; /** heuristic cost expected for future swaps needed in later circuit layers @@ -75,8 +84,8 @@ class HeuristicMapper : public Mapper { const std::array& loc, const std::vector& sw = {}, const std::set& valid2QGates = {}, - const double initCostFixed = 0, const std::size_t searchDepth = 0) - : costFixed(initCostFixed), depth(searchDepth), parent(parentId), + const double initCostFixed = 0, const double initCostFixedReversals = 0, const std::size_t searchDepth = 0) + : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), depth(searchDepth), parent(parentId), id(nodeId) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); @@ -90,14 +99,14 @@ class HeuristicMapper : public Mapper { * @brief returns costFixed + costHeur + lookaheadPenalty */ [[nodiscard]] double getTotalCost() const { - return costFixed + costHeur + lookaheadPenalty; + return costFixed + costFixedReversals + costHeur + lookaheadPenalty; } /** * @brief returns costFixed + lookaheadPenalty */ [[nodiscard]] double getTotalFixedCost() const { - return costFixed + lookaheadPenalty; + return costFixed + costFixedReversals + lookaheadPenalty; } std::ostream& print(std::ostream& out) const { @@ -278,10 +287,18 @@ class HeuristicMapper : public Mapper { * @brief recalculates the gate-count-optimizing fixed cost of the node from * the current mapping and swaps * + * @param node search node for which to recalculate the fixed cost + */ + void recalculateFixedCostNonFidelity(Node& node); + + /** + * @brief recalculates the gate-count-optimizing fixed cost of all reversals + * in the current mapping of a goal node or sets it to 0 otherwise + * * @param layer index of current circuit layer * @param node search node for which to recalculate the fixed cost */ - void recalculateFixedCostNonFidelity(std::size_t layer, Node& node); + void recalculateFixedCostReversals(std::size_t layer, Node& node); /** * @brief calculates the heuristic cost of the current mapping in the node diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index f3c6c92f2..04fe55d97 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -14,8 +14,7 @@ void HeuristicMapper::map(const Configuration& configuration) { dataLogger = std::make_unique(configuration.dataLoggingPath, *architecture, qc); } - - principallyAdmissibleHeur = isPrincipallyAdmissible(configuration.heuristic); + tightHeur = isTight(configuration.heuristic); fidelityAwareHeur = isFidelityAware(configuration.heuristic); @@ -557,7 +556,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { updateLookaheadPenalty(layer, node); if (config.dataLoggingEnabled()) { - dataLogger->logSearchNode(layer, node.id, node.parent, node.costFixed, + dataLogger->logSearchNode(layer, node.id, node.parent, node.costFixed + node.costFixedReversals, node.costHeur, node.lookaheadPenalty, node.qubits, node.validMapping, node.swaps, node.depth); } @@ -676,8 +675,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { const std::chrono::duration diff = end - start; results.heuristicBenchmark.secondsPerNode += diff.count(); - layerResultsIt->generatedNodes = - layerResultsIt->expandedNodes + nodes.size(); + layerResultsIt->generatedNodes = nextNodeId; results.heuristicBenchmark.generatedNodes += layerResultsIt->generatedNodes; if (layerResultsIt->expandedNodes > 0) { @@ -792,7 +790,7 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, const std::size_t layer) { Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, node.swaps, - node.validMappedTwoQubitGates, node.costFixed, node.depth + 1); + node.validMappedTwoQubitGates, node.costFixed, node.costFixedReversals, node.depth + 1); if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { @@ -804,12 +802,112 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, nodes.push(newNode); if (results.config.dataLoggingEnabled()) { dataLogger->logSearchNode( - layer, newNode.id, newNode.parent, newNode.costFixed, newNode.costHeur, + layer, newNode.id, newNode.parent, newNode.costFixed + newNode.costFixedReversals, newNode.costHeur, newNode.lookaheadPenalty, newNode.qubits, newNode.validMapping, newNode.swaps, newNode.depth); } } +void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { + node.validMappedTwoQubitGates.clear(); + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + const auto [q1, q2] = edge; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + if (architecture->isEdgeConnected({physQ1, physQ2}) || + architecture->isEdgeConnected({physQ2, physQ1})) { // validly mapped + node.validMappedTwoQubitGates.emplace(q1, q2); + } + } + + if (fidelityAwareHeur) { + recalculateFixedCostFidelity(layer, node); + } else { + recalculateFixedCostNonFidelity(node); + } + recalculateFixedCostReversals(layer, node); +} + +void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, Node& node) { + node.costFixedReversals = 0.; + if (!fidelityAwareHeur && node.validMappedTwoQubitGates.size() == twoQubitMultiplicities.at(layer).size()) { + // only consider reversal costs as fixed in goal nodes + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + if (!architecture->isEdgeConnected({physQ1, physQ2})) { + node.costFixedReversals += forwardMult * COST_DIRECTION_REVERSE; + } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { + node.costFixedReversals += reverseMult * COST_DIRECTION_REVERSE; + } + } + } +} + +void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { + node.costFixed = 0; + + // swap costs + for (auto& swap : node.swaps) { + if (swap.op == qc::SWAP) { + if (architecture->bidirectional()) { + node.costFixed += COST_BIDIRECTIONAL_SWAP; + } else { + node.costFixed += COST_UNIDIRECTIONAL_SWAP; + } + } else if (swap.op == qc::Teleportation) { + node.costFixed += COST_TELEPORTATION; + } + } +} + +void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, + Node& node) { + auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + + node.costFixed = 0; + // adding costs of single qubit gates + for (std::uint16_t i = 0U; i < architecture->getNqubits(); ++i) { + if (singleQubitGateMultiplicity.at(i) == 0) { + continue; + } + node.costFixed += singleQubitGateMultiplicity.at(i) * + architecture->getSingleQubitFidelityCost( + static_cast(node.locations.at(i))); + } + // adding cost of the swap gates + for (auto& swap : node.swaps) { + if (swap.op == qc::SWAP) { + node.costFixed += + architecture->getSwapFidelityCost(swap.first, swap.second); + } else if (swap.op == qc::Teleportation) { + throw QMAPException("Teleportation currently not supported for " + "noise-aware mapping"); + } + } + // adding cost of two qubit gates that are already mapped next to each other + for (const auto& [edge, mult] : twoQubitGateMultiplicity) { + if (node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { + // 2-qubit-gates not yet validly mapped are handled in the heuristic + continue; + } + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); + + node.costFixed += + (forwardMult * architecture->getTwoQubitFidelityCost(physQ1, physQ2) + + reverseMult * architecture->getTwoQubitFidelityCost(physQ2, physQ1)); + } +} + void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { auto& consideredQubits = activeQubits.at(layer); @@ -843,28 +941,29 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - auto [q3, q4] = edge; + const auto [q3, q4] = edge; + const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { - auto physQ3 = static_cast(node.locations.at(q3)); - auto physQ4 = static_cast(node.locations.at(q4)); + const auto physQ3 = static_cast(node.locations.at(q3)); + const auto physQ4 = static_cast(node.locations.at(q4)); if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || architecture->isEdgeConnected(Edge{physQ4, physQ3})) { // validly mapped now - if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == - node.validMappedTwoQubitGates - .end()) { // not mapped validly before + if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == node.validMappedTwoQubitGates.end()) { + // not mapped validly before // add cost of newly validly mapped gates node.costFixed += - mult.first * - architecture->getTwoQubitFidelityCost(physQ3, physQ4) + - mult.second * - architecture->getTwoQubitFidelityCost(physQ4, physQ3); + mult.first * + architecture->getTwoQubitFidelityCost(physQ3, physQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(physQ4, physQ3); } node.validMappedTwoQubitGates.emplace(edge); - } else { // not mapped validly now - if (fidelityAwareHeur && - node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { // mapped validly before + } else { + // not mapped validly now + if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // mapped validly before // remove cost of now no longer validly mapped gates auto prevPhysQ3 = physQ3; if (prevPhysQ3 == swap.first) { @@ -878,11 +977,12 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else if (prevPhysQ4 == swap.second) { prevPhysQ4 = swap.first; } + node.costFixed -= - mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, - prevPhysQ4) + - mult.second * - architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); + mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, + prevPhysQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); } node.validMappedTwoQubitGates.erase(edge); } @@ -915,7 +1015,8 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.costFixed += COST_UNIDIRECTIONAL_SWAP; } } - + + recalculateFixedCostReversals(layer, node); updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { updateLookaheadPenalty(layer, node); @@ -978,148 +1079,85 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - auto [q3, q4] = edge; + const auto [q3, q4] = edge; + const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { - auto physQ3 = static_cast(node.locations.at(q3)); - auto physQ4 = static_cast(node.locations.at(q4)); + const auto physQ3 = static_cast(node.locations.at(q3)); + const auto physQ4 = static_cast(node.locations.at(q4)); if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || architecture->isEdgeConnected(Edge{physQ4, physQ3})) { // validly mapped now node.validMappedTwoQubitGates.emplace(edge); - } else { // not mapped validly now + } else { + // not mapped validly now node.validMappedTwoQubitGates.erase(edge); } } } - + + recalculateFixedCostReversals(layer, node); updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { updateLookaheadPenalty(layer, node); } } -void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { - node.validMappedTwoQubitGates.clear(); - for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q1, q2] = edge; - const auto physQ1 = static_cast(node.locations.at(q1)); - const auto physQ2 = static_cast(node.locations.at(q2)); - - if (architecture->isEdgeConnected({physQ1, physQ2}) || - architecture->isEdgeConnected({physQ2, physQ1})) { // validly mapped - node.validMappedTwoQubitGates.emplace(q1, q2); - } - } - - if (fidelityAwareHeur) { - recalculateFixedCostFidelity(layer, node); - } else { - recalculateFixedCostNonFidelity(layer, node); - } -} - -void HeuristicMapper::recalculateFixedCostNonFidelity(std::size_t layer, Node& node) { - node.costFixed = 0; - - // swap costs - for (auto& swap : node.swaps) { - if (swap.op == qc::SWAP) { - if (architecture->bidirectional()) { - node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else { - node.costFixed += COST_UNIDIRECTIONAL_SWAP; - } - } else if (swap.op == qc::Teleportation) { - node.costFixed += COST_TELEPORTATION; - } - } - - // reversal costs of validly mapped two qubit gates - if (!architecture->bidirectional()) { - for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - if (node.validMappedTwoQubitGates.find(edge) == - node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates not yet validly mapped are handled in the heuristic - continue; - } - const auto [q1, q2] = edge; - const auto [forwardMult, reverseMult] = mult; - const auto physQ1 = static_cast(node.locations.at(q1)); - const auto physQ2 = static_cast(node.locations.at(q2)); - - if (!architecture->isEdgeConnected({physQ1, physQ2})) { - node.costFixed += forwardMult * COST_DIRECTION_REVERSE; - } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { - node.costFixed += reverseMult * COST_DIRECTION_REVERSE; - } - } - } -} - -void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, - Node& node) { - auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - - node.costFixed = 0; - // adding costs of single qubit gates - for (std::uint16_t i = 0U; i < architecture->getNqubits(); ++i) { - if (singleQubitGateMultiplicity.at(i) == 0) { - continue; - } - node.costFixed += singleQubitGateMultiplicity.at(i) * - architecture->getSingleQubitFidelityCost( - static_cast(node.locations.at(i))); - } - // adding cost of the swap gates - for (auto& swap : node.swaps) { - if (swap.op == qc::SWAP) { - node.costFixed += - architecture->getSwapFidelityCost(swap.first, swap.second); - } else if (swap.op == qc::Teleportation) { - throw QMAPException("Teleportation currently not supported for " - "noise-aware mapping"); - } - } - // adding cost of two qubit gates that are already mapped next to each other - for (const auto& [edge, mult] : twoQubitGateMultiplicity) { - if (node.validMappedTwoQubitGates.find(edge) == - node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates not yet validly mapped are handled in the heuristic - continue; - } - const auto [q1, q2] = edge; - const auto [forwardMult, reverseMult] = mult; - const auto physQ1 = static_cast(node.locations.at(q1)); - const auto physQ2 = static_cast(node.locations.at(q2)); +void HeuristicMapper::updateHeuristicCost(std::size_t layer, Node& node) { + // the mapping is valid, only if all qubit pairs are mapped next to each other + node.validMapping = (node.validMappedTwoQubitGates.size() == + twoQubitMultiplicities.at(layer).size()); - node.costFixed += - (forwardMult * architecture->getTwoQubitFidelityCost(physQ1, physQ2) + - reverseMult * architecture->getTwoQubitFidelityCost(physQ2, physQ1)); + switch (results.config.heuristic) { + case Heuristic::GateCountMaxDistance: + node.costHeur = heuristicGateCountMaxDistance(layer, node); + break; + case Heuristic::GateCountSumDistance: + node.costHeur = heuristicGateCountSumDistance(layer, node); + break; + case Heuristic::GateCountSumDistanceMinusSharedSwaps: + node.costHeur = heuristicGateCountSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: + node.costHeur = + heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(layer, node); + break; + case Heuristic::FidelityBestLocation: + node.costHeur = heuristicFidelityBestLocation(layer, node); + break; + default: + throw QMAPException("Unknown heuristic."); } } double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, Node& node) { + if (node.validMapping) { + return 0.; + } double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - if (node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates already validly mapped are handled in the fixed cost - continue; - } - const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (forwardMult > 0) { - costHeur = std::max(costHeur, architecture->distance(physQ1, physQ2)); - } - if (reverseMult > 0) { - costHeur = std::max(costHeur, architecture->distance(physQ2, physQ1)); + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // validly mapped 2-qubit-gates + if (!architecture->isEdgeConnected({physQ1, physQ2})) { + costHeur = std::max(costHeur, static_cast(forwardMult * COST_DIRECTION_REVERSE)); + } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { + costHeur = std::max(costHeur, static_cast(reverseMult * COST_DIRECTION_REVERSE)); + } + } else { + // not validly mapped 2-qubit-gates + if (forwardMult > 0) { + costHeur = std::max(costHeur, architecture->distance(physQ1, physQ2)); + } + if (reverseMult > 0) { + costHeur = std::max(costHeur, architecture->distance(physQ2, physQ1)); + } } } @@ -1128,34 +1166,42 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, Node& node) { + if (node.validMapping) { + return 0.; + } double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - if (node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates already validly mapped are handled in the fixed cost - continue; - } - const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - double swapCost = 0.; - - if (forwardMult == 0) { - // forwardMult == 0 && reverseMult > 0 - swapCost = architecture->distance(physQ2, physQ1); - } else if (reverseMult == 0) { - // forwardMult > 0 && reverseMult == 0 - swapCost = architecture->distance(physQ1, physQ2); + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // validly mapped 2-qubit-gates + if (!architecture->isEdgeConnected({physQ1, physQ2})) { + costHeur += forwardMult * COST_DIRECTION_REVERSE; + } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { + costHeur += reverseMult * COST_DIRECTION_REVERSE; + } } else { - // forwardMult > 0 && reverseMult > 0 - swapCost = std::max(architecture->distance(physQ1, physQ2), - architecture->distance(physQ2, physQ1)); + // not validly mapped 2-qubit-gates + double swapCost = 0.; + + if (forwardMult == 0) { + // forwardMult == 0 && reverseMult > 0 + swapCost = architecture->distance(physQ2, physQ1); + } else if (reverseMult == 0) { + // forwardMult > 0 && reverseMult == 0 + swapCost = architecture->distance(physQ1, physQ2); + } else { + // forwardMult > 0 && reverseMult > 0 + swapCost = std::max(architecture->distance(physQ1, physQ2), + architecture->distance(physQ2, physQ1)); + } + costHeur += swapCost; } - costHeur += swapCost; } return costHeur; @@ -1163,34 +1209,40 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( std::size_t layer, Node& node) { + if (node.validMapping) { + return 0.; + } double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - if (node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { - // 2-qubit-gates already validly mapped are handled in the fixed cost - continue; - } - const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - double swapCost = 0.; - - if (forwardMult == 0) { - // forwardMult == 0 && reverseMult > 0 - swapCost = architecture->distance(physQ2, physQ1); - } else if (reverseMult == 0) { - // forwardMult > 0 && reverseMult == 0 - swapCost = architecture->distance(physQ1, physQ2); + if (node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { + // validly mapped 2-qubit-gates + // TODO: handle reversals correctly } else { - // forwardMult > 0 && reverseMult > 0 - swapCost = std::min(architecture->distance(physQ1, physQ2), - architecture->distance(physQ2, physQ1)); + // not validly mapped 2-qubit-gates + double swapCost = 0.; + + if (forwardMult == 0) { + // forwardMult == 0 && reverseMult > 0 + swapCost = architecture->distance(physQ2, physQ1); + } else if (reverseMult == 0) { + // forwardMult > 0 && reverseMult == 0 + swapCost = architecture->distance(physQ1, physQ2); + } else { + // forwardMult > 0 && reverseMult > 0 + swapCost = std::min(architecture->distance(physQ1, physQ2), + architecture->distance(physQ2, physQ1)); + } + costHeur += swapCost; } - costHeur += swapCost; + + } // TODO: improve heuristic further by using number of 2Q blocks (for @@ -1315,33 +1367,6 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, return costHeur - savingsPotential; } -void HeuristicMapper::updateHeuristicCost(std::size_t layer, Node& node) { - // the mapping is valid, only if all qubit pairs are mapped next to each other - node.validMapping = (node.validMappedTwoQubitGates.size() == - twoQubitMultiplicities.at(layer).size()); - - switch (results.config.heuristic) { - case Heuristic::GateCountMaxDistance: - node.costHeur = heuristicGateCountMaxDistance(layer, node); - break; - case Heuristic::GateCountSumDistance: - node.costHeur = heuristicGateCountSumDistance(layer, node); - break; - case Heuristic::GateCountSumDistanceMinusSharedSwaps: - node.costHeur = heuristicGateCountSumDistanceMinusSharedSwaps(layer, node); - break; - case Heuristic::GateCountMaxDistanceOrSumDistanceMinusSharedSwaps: - node.costHeur = - heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps(layer, node); - break; - case Heuristic::FidelityBestLocation: - node.costHeur = heuristicFidelityBestLocation(layer, node); - break; - default: - throw QMAPException("Unknown heuristic."); - } -} - void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicMapper::Node& node) { const auto& config = results.config; diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 177f1f09b..845844724 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -298,7 +298,7 @@ class TestHeuristics settings.debug = true; settings.automaticLayerSplits = false; settings.initialLayout = InitialLayout::Identity; - settings.layering = Layering::DisjointQubits; + settings.layering = Layering::Disjoint2qBlocks; settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.heuristic = std::get<0>(GetParam()); settings.dataLoggingPath = "test_log"; @@ -321,10 +321,7 @@ INSTANTIATE_TEST_SUITE_P( "4mod5-v0_20", // 5q "mod5d1_63", // 5q "ising_model_10", // 16q - "rd73_140", // 16q - "cnt3-5_179", // 16q - "qft_16", // 16q - "z4_268" // 16q + "rd73_140" // 16q )), [](const testing::TestParamInfo& inf) { std::string name = std::get<1>(inf.param); @@ -425,16 +422,17 @@ TEST_P(TestHeuristics, HeuristicProperties) { continue; } - // check non-decreasing total cost - if (node.parent != node.id) { - if (node.parent >= nodes.size() || - nodes.at(node.parent).id != node.parent) { - FAIL() << "Invalid parent id " << node.parent << " for node " - << node.id; + if (isNonDecreasing(settings.heuristic)) { + if (node.parent != node.id) { + if (node.parent >= nodes.size() || + nodes.at(node.parent).id != node.parent) { + FAIL() << "Invalid parent id " << node.parent << " for node " + << node.id; + } + EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) + << "Heuristic " << toString(settings.heuristic) + << " does not result in non-decreasing cost estimation"; } - EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) - << "Heuristic " << toString(settings.heuristic) - << " does not result in non-decreasing cost estimation"; } EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) From f1a54a5b391cafe4f8acd42d583c9b57a74b55cc Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 19:08:34 +0100 Subject: [PATCH 10/47] fix tests after merge --- test/test_heuristic.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index e784dffab..ee856e613 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -571,14 +571,13 @@ TEST(Functionality, BenchmarkGeneratedNodes) { auto ibmQX5Mapper = std::make_unique(qc, ibmQX5); Configuration settings{}; - settings.admissibleHeuristic = true; - settings.lookahead = false; + settings.heuristic = Heuristic::GateCountMaxDistance; + settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.layering = Layering::IndividualGates; settings.automaticLayerSplits = false; settings.initialLayout = InitialLayout::Identity; settings.preMappingOptimizations = false; settings.postMappingOptimizations = false; - settings.considerFidelity = false; settings.useTeleportation = false; settings.debug = true; ibmQX5Mapper->map(settings); From c4c30d583e4231eca4a029235cefbe42278fe830 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 20:06:45 +0100 Subject: [PATCH 11/47] making local variables const --- src/heuristic/HeuristicMapper.cpp | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 04fe55d97..144ec8e4c 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -20,7 +20,7 @@ void HeuristicMapper::map(const Configuration& configuration) { results = MappingResults{}; results.config = configuration; - auto& config = results.config; + const auto& config = results.config; if (config.layering == Layering::OddGates || config.layering == Layering::QubitTriangle) { throw QMAPException("Layering strategy " + toString(config.layering) + @@ -224,8 +224,8 @@ void HeuristicMapper::mapUnmappedGates(std::size_t layer) { for (const auto& [logEdge, _] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = logEdge; - auto q1Location = locations.at(q1); - auto q2Location = locations.at(q2); + const auto q1Location = locations.at(q1); + const auto q2Location = locations.at(q2); if (q1Location == DEFAULT_POSITION && q2Location == DEFAULT_POSITION) { std::set possibleEdges{}; @@ -286,7 +286,7 @@ void HeuristicMapper::mapToMinDistance(const std::uint16_t source, 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( + const auto distance = distanceOnArchitectureOfPhysicalQubits( static_cast(locations.at(source)), i); if (distance < min) { min = distance; @@ -316,7 +316,7 @@ void HeuristicMapper::pseudoRouteCircuit(bool reverse) { config.debug = false; for (std::size_t i = 0; i < layers.size(); ++i) { - auto layerIndex = (reverse ? layers.size() - i - 1 : i); + const auto layerIndex = (reverse ? layers.size() - i - 1 : i); const Node result = aStarMap(layerIndex, reverse); qubits = result.qubits; @@ -339,7 +339,7 @@ void HeuristicMapper::pseudoRouteCircuit(bool reverse) { } void HeuristicMapper::routeCircuit() { - auto& config = results.config; + const auto& config = results.config; std::size_t gateidx = 0; std::vector gatesToAdjust{}; @@ -499,8 +499,8 @@ void HeuristicMapper::routeCircuit() { } if (!gatesToAdjust.empty() && gatesToAdjust.back() == gateidx) { gatesToAdjust.pop_back(); - auto target = op->getTargets().at(0); - auto targetLocation = locations.at(target); + const auto target = op->getTargets().at(0); + const auto targetLocation = locations.at(target); if (targetLocation == -1) { // qubit only occurs in single qubit gates, can be mapped to an @@ -534,7 +534,7 @@ void HeuristicMapper::routeCircuit() { } HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { - auto& config = results.config; + const auto& config = results.config; nextNodeId = 0; const std::unordered_set& consideredQubits = @@ -769,8 +769,8 @@ void HeuristicMapper::expandNode( for (const auto& edge : perms) { if (edge.first == node.locations.at(q) || edge.second == node.locations.at(q)) { - auto q1 = node.qubits.at(edge.first); - auto q2 = node.qubits.at(edge.second); + const auto q1 = node.qubits.at(edge.first); + const auto q2 = node.qubits.at(edge.second); if (q2 == -1 || q1 == -1) { expandNodeAddOneSwap(edge, node, layer); } else if (!usedSwaps.at(static_cast(q1)) @@ -867,8 +867,8 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, Node& node) { - auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); node.costFixed = 0; // adding costs of single qubit gates @@ -910,8 +910,8 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { - auto& consideredQubits = activeQubits.at(layer); - auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + const auto& consideredQubits = activeQubits.at(layer); + const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); @@ -1275,9 +1275,9 @@ HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps( double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& node) { - auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - auto& consideredQubits = activeQubits.at(layer); + const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + const auto& consideredQubits = activeQubits.at(layer); double costHeur = 0.; @@ -1405,8 +1405,8 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - auto loc1 = node.locations.at(q1); - auto loc2 = node.locations.at(q2); + const auto loc1 = node.locations.at(q1); + const auto loc2 = node.locations.at(q2); if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { // no penalty } else if (loc1 == DEFAULT_POSITION) { @@ -1430,7 +1430,7 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, } penalty = std::max(penalty, min); } else { - auto cost = architecture->distance(static_cast(loc1), + const auto cost = architecture->distance(static_cast(loc1), static_cast(loc2)); penalty = std::max(penalty, cost); } @@ -1447,8 +1447,8 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; - auto loc1 = node.locations.at(q1); - auto loc2 = node.locations.at(q2); + const auto loc1 = node.locations.at(q1); + const auto loc2 = node.locations.at(q2); if (loc1 == DEFAULT_POSITION && loc2 == DEFAULT_POSITION) { // no penalty } else if (loc1 == DEFAULT_POSITION) { @@ -1472,7 +1472,7 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, } penalty = min; } else { - auto cost = architecture->distance(static_cast(loc1), + const auto cost = architecture->distance(static_cast(loc1), static_cast(loc2)); penalty = cost; } From d882ac4db2f0542a9b116ef66fc0d49ffaf11148 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 20:11:56 +0100 Subject: [PATCH 12/47] fix NodeCostCalculation test --- test/test_heuristic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index ee856e613..0a197e26e 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -222,7 +222,7 @@ TEST_F(InternalsTest, NodeCostCalculation) { results.config.heuristic = Heuristic::GateCountSumDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, - COST_UNIDIRECTIONAL_SWAP * 14 + COST_DIRECTION_REVERSE * 3, + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE * 2, tolerance); EXPECT_NEAR(node.costFixed, 5., tolerance) << "updateHeuristicCost should not change costFixed"; From 8824d46e0ece1549b36b05c6214401637b8be5cf Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 5 Jan 2024 20:21:11 +0100 Subject: [PATCH 13/47] fix earlyTermination test --- test/test_heuristic.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 0a197e26e..bc22c0ff3 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -1036,9 +1036,12 @@ TEST(Functionality, terminationStrategyFromString) { } TEST(Functionality, earlyTermination) { - qc::QuantumComputation qc{7}; + qc::QuantumComputation qc{7, 7}; qc.x(0); - qc.cx(qc::Control{1}, 3); + qc.cx(qc::Control{1}, 2); + for (std::size_t i = 0; i < 7; ++i) { + qc.measure(static_cast(i), i); + } const CouplingMap cm = {{0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 3}, {3, 2}, {3, 4}, {4, 3}, {4, 5}, {5, 4}, {5, 6}, {6, 5}}; From 6ff7b6ee5224a79064ad2ca42158123cd49e6eda Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Sun, 7 Jan 2024 18:24:19 +0100 Subject: [PATCH 14/47] further optimize GateCountSumDistanceMinusSharedSwaps --- include/Architecture.hpp | 19 +++- include/heuristic/HeuristicMapper.hpp | 34 ++++--- src/Architecture.cpp | 11 ++- src/heuristic/HeuristicMapper.cpp | 125 +++++++++++++++++--------- test/test_heuristic.cpp | 25 ++++-- 5 files changed, 147 insertions(+), 67 deletions(-) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index b924e3618..3153bac3d 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -249,7 +249,12 @@ class Architecture { return teleportationQubits; } - [[nodiscard]] const Matrix& getDistanceTable() const { return distanceTable; } + [[nodiscard]] const Matrix& getDistanceTable(bool includeReversalCost = true) const { + if (includeReversalCost) { + return distanceTableReversals; + } + return distanceTable; + } [[nodiscard]] const Properties& getProperties() const { return properties; } @@ -382,6 +387,8 @@ class Architecture { } [[nodiscard]] bool bidirectional() const { return isBidirectional; } + + [[nodiscard]] bool unidirectional() const { return isUnidirectional; } [[nodiscard]] bool isArchitectureAvailable() const { return !(name.empty()) && nqubits != 0; @@ -395,7 +402,9 @@ class Architecture { nqubits = 0; couplingMap.clear(); distanceTable.clear(); + distanceTableReversals.clear(); isBidirectional = true; + isUnidirectional = true; properties.clear(); fidelityAvailable = false; fidelityTable.clear(); @@ -407,8 +416,12 @@ class Architecture { } [[nodiscard]] double distance(std::uint16_t control, - std::uint16_t target) const { + std::uint16_t target, + bool includeReversalCost = true) const { if (currentTeleportations.empty()) { + if (includeReversalCost) { + return distanceTableReversals.at(control).at(target); + } return distanceTable.at(control).at(target); } return static_cast(bfs(control, target, currentTeleportations)); @@ -481,7 +494,9 @@ class Architecture { CouplingMap couplingMap = {}; CouplingMap currentTeleportations = {}; bool isBidirectional = true; + bool isUnidirectional = true; Matrix distanceTable = {}; + Matrix distanceTableReversals = {}; std::vector> teleportationQubits{}; Properties properties = {}; bool fidelityAvailable = false; diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index dc08eb704..a122b6d17 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -84,9 +84,13 @@ class HeuristicMapper : public Mapper { const std::array& loc, const std::vector& sw = {}, const std::set& valid2QGates = {}, - const double initCostFixed = 0, const double initCostFixedReversals = 0, const std::size_t searchDepth = 0) - : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), depth(searchDepth), parent(parentId), - id(nodeId) { + const double initCostFixed = 0, + const double initCostFixedReversals = 0, + const std::size_t searchDepth = 0, + const std::size_t initSharedSwaps = 0) + : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), + depth(searchDepth), parent(parentId), id(nodeId), + sharedSwaps(initSharedSwaps) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); std::copy(sw.begin(), sw.end(), std::back_inserter(swaps)); @@ -217,21 +221,29 @@ class HeuristicMapper : public Mapper { * @param reverse if true, the circuit is mapped from the end to the beginning */ virtual Node aStarMap(std::size_t layer, bool reverse); + + /** + * @brief Get all qubits that are acted on by a relevant gate in the given layer + * + * @param layer the layer for which to get the considered qubits + */ + const std::unordered_set& getConsideredQubits(std::size_t layer) const { + if (fidelityAwareHeur) { + return activeQubits.at(layer); + } else { + return activeQubits2QGates.at(layer); + } + } /** * @brief expand the given node by calling `expand_node_add_one_swap` for all * possible swaps, which creates new search nodes and adds them to * `HeuristicMapper::nodes` * - * @param consideredQubits set of all qubits that are acted on by a - * 2-qubit-gate in the respective layer * @param node current search node * @param layer index of current circuit layer - * @param twoQubitGateMultiplicity number of two qubit gates acting on pairs - * of logical qubits in the current layer */ - void expandNode(const std::unordered_set& consideredQubits, - Node& node, std::size_t layer); + void expandNode(Node& node, std::size_t layer); /** * @brief creates a new node with a swap on the given edge and adds it to @@ -240,8 +252,6 @@ class HeuristicMapper : public Mapper { * @param swap edge on which to perform a swap * @param node current search node * @param layer index of current circuit layer - * @param twoQubitGateMultiplicity number of two qubit gates acting on pairs - * of logical qubits in the current layer */ void expandNodeAddOneSwap(const Edge& swap, Node& node, std::size_t layer); @@ -255,7 +265,7 @@ class HeuristicMapper : public Mapper { */ void applySWAP(const Edge& swap, std::size_t layer, Node& node); - /** + /**d * @brief applies an in-place teleportation of 2 virtual qubits in the given * node and recalculates all costs accordingly * diff --git a/src/Architecture.cpp b/src/Architecture.cpp index f7c782515..9ce0bc65d 100644 --- a/src/Architecture.cpp +++ b/src/Architecture.cpp @@ -186,21 +186,30 @@ Architecture::Architecture(const std::uint16_t nQ, const CouplingMap& cm, void Architecture::createDistanceTable() { isBidirectional = true; + isUnidirectional = true; Matrix edgeWeights(nqubits, std::vector( nqubits, std::numeric_limits::max())); for (const auto& edge : couplingMap) { if (couplingMap.find({edge.second, edge.first}) == couplingMap.end()) { + // unidirectional edge isBidirectional = false; edgeWeights.at(edge.second).at(edge.first) = COST_UNIDIRECTIONAL_SWAP; edgeWeights.at(edge.first).at(edge.second) = COST_UNIDIRECTIONAL_SWAP; } else { + // bidirectional edge + isUnidirectional = false; edgeWeights.at(edge.first).at(edge.second) = COST_BIDIRECTIONAL_SWAP; } } Matrix simpleDistanceTable{}; Dijkstra::buildTable(couplingMap, simpleDistanceTable, edgeWeights); - Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, COST_DIRECTION_REVERSE, distanceTable); + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, 0., distanceTable); + if (bidirectional()) { + distanceTableReversals = distanceTable; + } else { + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, COST_DIRECTION_REVERSE, distanceTableReversals); + } } void Architecture::createFidelityTable() { diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 144ec8e4c..c92f4ee6a 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -7,6 +7,7 @@ #include "utils.hpp" +#include #include void HeuristicMapper::map(const Configuration& configuration) { @@ -536,9 +537,7 @@ void HeuristicMapper::routeCircuit() { HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { const auto& config = results.config; nextNodeId = 0; - - const std::unordered_set& consideredQubits = - (fidelityAwareHeur ? activeQubits[layer] : activeQubits2QGates[layer]); + const SingleQubitMultiplicity& singleQubitMultiplicity = singleQubitMultiplicities.at(layer); const TwoQubitMultiplicity& twoQubitMultiplicity = @@ -615,7 +614,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { } } nodes.pop(); - expandNode(consideredQubits, current, layer); + expandNode(current, layer); ++expandedNodes; if (validMapping) { ++expandedNodesAfterFirstSolution; @@ -711,9 +710,8 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { return result; } -void HeuristicMapper::expandNode( - const std::unordered_set& consideredQubits, Node& node, - std::size_t layer) { +void HeuristicMapper::expandNode(Node& node, std::size_t layer) { + const auto& consideredQubits = getConsideredQubits(layer); std::vector> usedSwaps; usedSwaps.reserve(architecture->getNqubits()); for (int p = 0; p < architecture->getNqubits(); ++p) { @@ -790,7 +788,8 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, const std::size_t layer) { Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, node.swaps, - node.validMappedTwoQubitGates, node.costFixed, node.costFixedReversals, node.depth + 1); + node.validMappedTwoQubitGates, node.costFixed, + node.costFixedReversals, node.depth + 1, node.sharedSwaps); if (architecture->isEdgeConnected(swap) || architecture->isEdgeConnected(Edge{swap.second, swap.first})) { @@ -910,16 +909,20 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { - const auto& consideredQubits = activeQubits.at(layer); + const auto& consideredQubits = getConsideredQubits(layer); const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); node.qubits.at(swap.first) = q2; node.qubits.at(swap.second) = q1; - if (consideredQubits.find(swap.first) != consideredQubits.end() && - consideredQubits.find(swap.second) != consideredQubits.end()) { + const auto logEdge = q1 < q2 ? std::make_pair(q1, q2) : std::make_pair(q2, q1); + if ((fidelityAwareHeur || twoQubitGateMultiplicity.find(logEdge) == + twoQubitGateMultiplicity.end()) && + consideredQubits.find(q1) != consideredQubits.end() && + consideredQubits.find(q2) != consideredQubits.end()) { ++node.sharedSwaps; } @@ -1025,11 +1028,21 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { + const auto& consideredQubits = getConsideredQubits(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); node.qubits.at(swap.first) = q2; node.qubits.at(swap.second) = q1; + const auto logEdge = q1 < q2 ? std::make_pair(q1, q2) : std::make_pair(q2, q1); + if ((fidelityAwareHeur || twoQubitGateMultiplicity.find(logEdge) == + twoQubitGateMultiplicity.end()) && + consideredQubits.find(q1) != consideredQubits.end() && + consideredQubits.find(q2) != consideredQubits.end()) { + ++node.sharedSwaps; + } if (q1 != -1) { node.locations.at(static_cast(q1)) = @@ -1212,55 +1225,81 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( if (node.validMapping) { return 0.; } + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); double costHeur = 0.; - - for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { + double costReversals = 0.; + std::vector nSwaps{}; + nSwaps.reserve(twoQubitGateMultiplicity.size()); + + for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); + if (architecture->unidirectional()) { + // only for purely unidirectional architectures is it certain that at + // least one of the two directions has to be reversed + costReversals += std::min(forwardMult, reverseMult) * COST_DIRECTION_REVERSE; + } + if (node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates - // TODO: handle reversals correctly - } else { - // not validly mapped 2-qubit-gates - double swapCost = 0.; - - if (forwardMult == 0) { - // forwardMult == 0 && reverseMult > 0 - swapCost = architecture->distance(physQ2, physQ1); - } else if (reverseMult == 0) { - // forwardMult > 0 && reverseMult == 0 - swapCost = architecture->distance(physQ1, physQ2); - } else { - // forwardMult > 0 && reverseMult > 0 - swapCost = std::min(architecture->distance(physQ1, physQ2), - architecture->distance(physQ2, physQ1)); - } - costHeur += swapCost; + continue; } + double swapCost = 0.; + if (forwardMult == 0) { + // forwardMult == 0 && reverseMult > 0 + swapCost = architecture->distance(physQ2, physQ1, false); + } else if (reverseMult == 0) { + // forwardMult > 0 && reverseMult == 0 + swapCost = architecture->distance(physQ1, physQ2, false); + } else { + // forwardMult > 0 && reverseMult > 0 + swapCost = std::min(architecture->distance(physQ1, physQ2, false), + architecture->distance(physQ2, physQ1, false)); + } + costHeur += swapCost; + // infer maximum number of swaps in this distance + if (architecture->unidirectional()) { + nSwaps.emplace_back(static_cast(swapCost / COST_UNIDIRECTIONAL_SWAP)); + } else { + nSwaps.emplace_back(static_cast(swapCost / COST_BIDIRECTIONAL_SWAP)); + } } - - // TODO: improve heuristic further by using number of 2Q blocks (for - // gate-count-optimizing mapping qubit pairs will only travel towards - // each other, i.e. a qubit can only share 1 swap per qubit pair) - std::size_t n = activeQubits.size(); + + // sort number of swaps in descending order + std::sort(nSwaps.begin(), nSwaps.end(), std::greater()); + + // infer maximum number of shared swaps + std::size_t maxSharedSwaps = 0; + for (std::size_t i = 0; i < nSwaps.size()-1; ++i) { + std::size_t maxSharedSwapsEdge = 0; // maximum number of shared swaps for this edge + for (std::size_t j = i + 1; j < nSwaps.size() && maxSharedSwapsEdge < nSwaps[i]; ++j) { + if (nSwaps[j] > 0) { + ++maxSharedSwapsEdge; + --nSwaps[j]; + } + } + maxSharedSwaps += maxSharedSwapsEdge; + } + if (node.sharedSwaps < maxSharedSwaps) { + maxSharedSwaps -= node.sharedSwaps; + } else { + maxSharedSwaps = 0; + } + double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = - ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * - COST_BIDIRECTIONAL_SWAP; + sharedSwapCostReduction = static_cast(maxSharedSwaps * COST_BIDIRECTIONAL_SWAP); } else { - sharedSwapCostReduction = - ((n - 1) * n / 2 - static_cast(node.sharedSwaps)) * - COST_UNIDIRECTIONAL_SWAP; + sharedSwapCostReduction = static_cast(maxSharedSwaps * COST_UNIDIRECTIONAL_SWAP); } - return std::max(0., costHeur - sharedSwapCostReduction); + return std::max(0., costHeur - sharedSwapCostReduction) + costReversals; } double @@ -1275,9 +1314,9 @@ HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps( double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, Node& node) { + const auto& consideredQubits = getConsideredQubits(layer); const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - const auto& consideredQubits = activeQubits.at(layer); double costHeur = 0.; diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index bc22c0ff3..62c73cd49 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -340,6 +340,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { // each node is at the position corresponding to its id; positions of unused // ids are filled with default values (i.e. node.id = 0) std::vector> allNodes{}; + std::vector layerNames{}; std::vector finalSolutionIds{}; // map to IBM Yorktown if possible @@ -352,6 +353,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { allNodes.emplace_back( results.layerHeuristicBenchmark.at(i).generatedNodes); + layerNames.emplace_back("on ibmq_yorktown in layer " + std::to_string(i)); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); finalSolutionIds.push_back( getFinalNodeFromDatalog(settings.dataLoggingPath, i)); @@ -366,6 +368,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { allNodes.emplace_back( results.layerHeuristicBenchmark.at(i).generatedNodes); + layerNames.emplace_back("on ibmq_london in layer " + std::to_string(i)); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); finalSolutionIds.push_back( getFinalNodeFromDatalog(settings.dataLoggingPath, i)); @@ -382,6 +385,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { allNodes.emplace_back( results.layerHeuristicBenchmark.at(i).generatedNodes); + layerNames.emplace_back("on ibmQX5 in layer " + std::to_string(i)); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); finalSolutionIds.push_back( getFinalNodeFromDatalog(settings.dataLoggingPath, i)); @@ -396,7 +400,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { if (finalSolutionId >= nodes.size() || nodes.at(finalSolutionId).id != finalSolutionId) { FAIL() << "Final solution node " << finalSolutionId - << " not found in nodes of layer " << i; + << " not found " << layerNames.at(i); } auto& finalSolutionNode = nodes.at(finalSolutionId); EXPECT_TRUE(finalSolutionNode.validMapping); @@ -408,11 +412,12 @@ TEST_P(TestHeuristics, HeuristicProperties) { auto solutionPath = getPathToRoot(nodes, finalSolutionId); for (auto nodeId : solutionPath) { if (nodes.at(nodeId).id != nodeId) { - throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); + throw std::runtime_error("Invalid node id " + std::to_string(nodeId) + " " + layerNames.at(i)); } EXPECT_LE(nodes.at(nodeId).getTotalCost(), finalSolutionNode.costFixed) << "Heuristic " << toString(settings.heuristic) - << " is not principally admissible"; + << " is not principally admissible " << layerNames.at(i) + << " in node " << nodeId; } } @@ -427,24 +432,25 @@ TEST_P(TestHeuristics, HeuristicProperties) { if (node.parent >= nodes.size() || nodes.at(node.parent).id != node.parent) { FAIL() << "Invalid parent id " << node.parent << " for node " - << node.id; + << node.id << " " << layerNames.at(i); } EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) << "Heuristic " << toString(settings.heuristic) - << " does not result in non-decreasing cost estimation"; + << " does not result in non-decreasing cost estimation " + << layerNames.at(i) << " in node " << node.id; } } EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) - << "Lookahead penalty not 0 even though lookahead has been " - "deactivated"; + << "Lookahead penalty not 0 " << layerNames.at(i) + << " even though lookahead has been deactivated"; if (node.validMapping) { if (isTight(settings.heuristic)) { // tight heuristics are 0 in any goal node EXPECT_NEAR(node.costHeur, 0., tolerance) << "Heuristic " << toString(settings.heuristic) - << " is not tight"; + << " is not tight " << layerNames.at(i) << " in node " << node.id; } if (isAdmissible(settings.heuristic)) { @@ -459,7 +465,8 @@ TEST_P(TestHeuristics, HeuristicProperties) { auto& n = nodes.at(nodeId); EXPECT_LE(n.getTotalCost(), node.costFixed) << "Heuristic " << toString(settings.heuristic) - << " is not admissible"; + << " is not admissible " << layerNames.at(i) + << " in node " << nodeId; } } } From 72f40129a076db957661f4beea34b2596a66c9b6 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 00:25:53 +0100 Subject: [PATCH 15/47] fix calculation of shared swaps --- include/heuristic/HeuristicMapper.hpp | 43 +- src/heuristic/HeuristicMapper.cpp | 99 ++++- test/test_heuristic.cpp | 551 +++++++++++++++++++++++++- 3 files changed, 656 insertions(+), 37 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index a122b6d17..f86bca530 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -67,7 +67,8 @@ class HeuristicMapper : public Mapper { /** heuristic cost expected for future swaps needed in later circuit layers * (further layers contribute less) */ double lookaheadPenalty = 0.; - /** number of swaps that were shared with another considered qubit */ + /** number of swaps that were shared with another considered qubit such + * that both qubits got closer to being validly mapped*/ std::size_t sharedSwaps = 0; /** depth in search tree (starting with 0 at the root) */ std::size_t depth = 0; @@ -77,8 +78,14 @@ class HeuristicMapper : public Mapper { * architecture */ bool validMapping = true; - explicit Node() = default; - explicit Node(std::size_t nodeId) : id(nodeId){}; + explicit Node() { + qubits.fill(DEFAULT_POSITION); + locations.fill(DEFAULT_POSITION); + }; + explicit Node(std::size_t nodeId) : id(nodeId){ + qubits.fill(DEFAULT_POSITION); + locations.fill(DEFAULT_POSITION); + }; Node(std::size_t nodeId, std::size_t parentId, const std::array& q, const std::array& loc, @@ -265,7 +272,7 @@ class HeuristicMapper : public Mapper { */ void applySWAP(const Edge& swap, std::size_t layer, Node& node); - /**d + /** * @brief applies an in-place teleportation of 2 virtual qubits in the given * node and recalculates all costs accordingly * @@ -274,6 +281,16 @@ class HeuristicMapper : public Mapper { * @param node search node in which to apply the swap */ void applyTeleportation(const Edge& swap, std::size_t layer, Node& node); + + /** + * @brief increments `node.sharedSwaps` if the given swap is shared with + * another qubit such that both qubits get closer to being validly mapped + * + * @param swap the swap to check + * @param layer index of current circuit layer + * @param node search node in which to update `sharedSwaps` + */ + void updateSharedSwaps(const Edge& swap, std::size_t layer, Node& node); /** * @brief recalculates the fixed cost of the node from the current mapping and @@ -467,10 +484,10 @@ inline bool operator>(const HeuristicMapper::Node& x, return xcost > ycost; } - if (x.validMapping) { + if (x.validMapping && !y.validMapping) { return false; } - if (y.validMapping) { + if (y.validMapping && !x.validMapping) { return true; } @@ -487,3 +504,17 @@ inline bool operator>(const HeuristicMapper::Node& x, return x < y; } + +inline bool operator==(const HeuristicMapper::Node& x, + const HeuristicMapper::Node& y) { + auto itx = x.qubits.begin(); // NOLINT (readability-qualified-auto) + auto ity = y.qubits.begin(); // NOLINT (readability-qualified-auto) + while (itx != x.qubits.end() && ity != y.qubits.end()) { + if (*itx != *ity) { + return false; + } + ++itx; + ++ity; + } + return true; +} diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index c92f4ee6a..863393005 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -909,22 +909,15 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { - const auto& consideredQubits = getConsideredQubits(layer); const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); - const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); + + updateSharedSwaps(swap, layer, node); node.qubits.at(swap.first) = q2; node.qubits.at(swap.second) = q1; - const auto logEdge = q1 < q2 ? std::make_pair(q1, q2) : std::make_pair(q2, q1); - if ((fidelityAwareHeur || twoQubitGateMultiplicity.find(logEdge) == - twoQubitGateMultiplicity.end()) && - consideredQubits.find(q1) != consideredQubits.end() && - consideredQubits.find(q2) != consideredQubits.end()) { - ++node.sharedSwaps; - } if (q1 != -1) { node.locations.at(static_cast(q1)) = @@ -1028,21 +1021,13 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { - const auto& consideredQubits = getConsideredQubits(layer); - const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); + + updateSharedSwaps(swap, layer, node); node.qubits.at(swap.first) = q2; node.qubits.at(swap.second) = q1; - const auto logEdge = q1 < q2 ? std::make_pair(q1, q2) : std::make_pair(q2, q1); - if ((fidelityAwareHeur || twoQubitGateMultiplicity.find(logEdge) == - twoQubitGateMultiplicity.end()) && - consideredQubits.find(q1) != consideredQubits.end() && - consideredQubits.find(q2) != consideredQubits.end()) { - ++node.sharedSwaps; - } if (q1 != -1) { node.locations.at(static_cast(q1)) = @@ -1115,6 +1100,82 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, } } +void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, + Node& node) { + const auto& consideredQubits = getConsideredQubits(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + + const auto q1 = node.qubits.at(swap.first); + const auto q2 = node.qubits.at(swap.second); + + if (consideredQubits.find(q1) != consideredQubits.end() && + consideredQubits.find(q2) != consideredQubits.end()) { + // TODO: handle single qubit gates for fidelity aware heuristic + Edge logEdge1 = {q1, q1}; + Edge logEdge2 = {q2, q2}; + for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { + if (edge.first == q1) { + logEdge1.second = edge.second; + } else if (edge.second == q1) { + logEdge1.second = edge.first; + } + if (edge.first == q2) { + logEdge2.second = edge.second; + } else if (edge.second == q2) { + logEdge2.second = edge.first; + } + } + if (// if both swapped qubits are acted on by a 2q gate + logEdge1.second != q1 && logEdge2.second != q2 && + // if it is not the same 2q gate acting on both qubits + logEdge1.second != q2) { + double logEdge1DistanceBefore; + double logEdge1DistanceNew; + double logEdge2DistanceBefore; + double logEdge2DistanceNew; + if (fidelityAwareHeur) { + logEdge1DistanceBefore = std::min( + architecture->fidelityDistance(swap.first, node.locations[logEdge1.second]), + architecture->fidelityDistance(node.locations[logEdge1.second], swap.first) + ); + logEdge1DistanceNew = std::min( + architecture->fidelityDistance(swap.second, node.locations[logEdge1.second]), + architecture->fidelityDistance(node.locations[logEdge1.second], swap.second) + ); + logEdge2DistanceBefore = std::min( + architecture->fidelityDistance(swap.second, node.locations[logEdge2.second]), + architecture->fidelityDistance(node.locations[logEdge2.second], swap.second) + ); + logEdge2DistanceNew = std::min( + architecture->fidelityDistance(swap.first, node.locations[logEdge2.second]), + architecture->fidelityDistance(node.locations[logEdge2.second], swap.first) + ); + } else { + logEdge1DistanceBefore = std::min( + architecture->distance(swap.first, node.locations[logEdge1.second], false), + architecture->distance(node.locations[logEdge1.second], swap.first, false) + ); + logEdge1DistanceNew = std::min( + architecture->distance(swap.second, node.locations[logEdge1.second], false), + architecture->distance(node.locations[logEdge1.second], swap.second, false) + ); + logEdge2DistanceBefore = std::min( + architecture->distance(swap.second, node.locations[logEdge2.second], false), + architecture->distance(node.locations[logEdge2.second], swap.second, false) + ); + logEdge2DistanceNew = std::min( + architecture->distance(swap.first, node.locations[logEdge2.second], false), + architecture->distance(node.locations[logEdge2.second], swap.first, false) + ); + } + if (logEdge1DistanceNew < logEdge1DistanceBefore && + logEdge2DistanceNew < logEdge2DistanceBefore) { + ++node.sharedSwaps; + } + } + } +} + void HeuristicMapper::updateHeuristicCost(std::size_t layer, Node& node) { // the mapping is valid, only if all qubit pairs are mapped next to each other node.validMapping = (node.validMappedTwoQubitGates.size() == diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 62c73cd49..fe30bd4b9 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -7,12 +7,15 @@ #include "nlohmann/json.hpp" #include "gtest/gtest.h" +#include #include #include #include #include #include +constexpr qc::OpType SWAP = qc::OpType::SWAP; + /** * @brief Get id of the final node in a given layer from a data log. */ @@ -115,11 +118,6 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { - for (std::size_t i = 0; i < MAX_DEVICE_QUBITS; ++i) { - node.qubits[i] = -1; - node.locations[i] = -1; - } - std::stringstream qubitMapBuffer(col); std::string entry; for (std::size_t i = 0; std::getline(qubitMapBuffer, entry, ','); ++i) { @@ -141,7 +139,7 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::uint16_t q2 = 0; std::string opTypeStr = ""; std::stringstream(entry) >> q1 >> q2 >> opTypeStr; - qc::OpType opType = qc::OpType::SWAP; + qc::OpType opType = SWAP; if (opTypeStr.size() > 0) { // if no opType is given, the default value is SWAP opType = qc::opTypeFromString(opTypeStr); @@ -180,21 +178,24 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { return path; } -Architecture internalsTestArchitecture{1, {}}; class InternalsTest : public HeuristicMapper, public testing::Test { protected: + static Architecture defaultArch; + InternalsTest() - : HeuristicMapper(qc::QuantumComputation{1}, internalsTestArchitecture) {} + : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } }; +Architecture InternalsTest::defaultArch{1, {}}; + TEST_F(InternalsTest, NodeCostCalculation) { const double tolerance = 1e-6; results.config.heuristic = Heuristic::GateCountMaxDistance; results.config.lookaheadHeuristic = LookaheadHeuristic::None; results.config.layering = Layering::Disjoint2qBlocks; - + architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); qc = qc::QuantumComputation{5}; qc.cx(qc::Control{0}, 1); @@ -211,7 +212,7 @@ TEST_F(InternalsTest, NodeCostCalculation) { << "layering failed, not able to test node cost calculation"; const std::vector swaps{Exchange(0, 1, qc::OpType::Teleportation), - Exchange(1, 2, qc::OpType::SWAP)}; + Exchange(1, 2, SWAP)}; HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, {{2, 3}}, 5., 0); @@ -277,6 +278,7 @@ class TestHeuristics std::string testCalibrationDir = "../extern/calibration/"; qc::QuantumComputation qc{}; + std::string circuitName{}; Architecture ibmqYorktown{}; // 5 qubits Architecture ibmqLondon{}; // 5 qubits (with calibration) std::unique_ptr ibmqYorktownMapper; @@ -285,9 +287,507 @@ class TestHeuristics std::unique_ptr ibmQX5Mapper; Configuration settings{}; const double tolerance = 1e-6; + + static std::unordered_map> optimalSolutions; + + static void SetUpTestSuite() { + // prepare precalculated optimal solutions to compare against + optimalSolutions = { + {"3_17_13", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,0,SWAP}}, {}, 0., 0., 1} + }}, + {"ex-1_166", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1} + }}, + {"ham3_102", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0} + }}, + {"miller_11", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0} + }}, + {"4gt11_84", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1} + }}, + {"4mod5-v0_20", { + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP},{3,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0} + }}, + {"mod5d1_63", { + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,0,SWAP},{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 3} + }}, + {"ising_model_10", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0} + }}, + {"rd73_140", { + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP},{2,3,SWAP},{3,4,SWAP},{5,4,SWAP},{6,7,SWAP}}, {}, 0., 0., 5}, + {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{2,3,SWAP},{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 5}, + {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{5,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP},{1,2,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{8,7,SWAP},{6,7,SWAP},{6,5,SWAP},{1,2,SWAP},{2,3,SWAP},{3,4,SWAP}}, {}, 0., 0., 6}, + {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{5,4,SWAP},{3,4,SWAP}}, {}, 0., 0., 4}, + {0, 0, {}, {}, {{2,3,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{9,10,SWAP},{11,10,SWAP},{12,11,SWAP},{12,5,SWAP},{5,4,SWAP},{3,4,SWAP},{2,3,SWAP},{5,4,SWAP}}, {}, 0., 0., 8}, + {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{6,5,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{6,5,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1,0,SWAP},{6,5,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3,4,SWAP},{15,2,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{5,4,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{5,4,SWAP},{15,0,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3,4,SWAP},{15,0,SWAP},{15,14,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,14,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{6,7,SWAP},{6,5,SWAP},{5,4,SWAP},{3,4,SWAP},{15,0,SWAP}}, {}, 0., 0., 5}, + {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP},{15,0,SWAP},{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 5}, + {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2,3,SWAP},{15,2,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,3,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{1,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{8,7,SWAP},{6,7,SWAP},{6,5,SWAP},{5,4,SWAP},{3,4,SWAP},{1,0,SWAP}}, {}, 0., 0., 6}, + {0, 0, {}, {}, {{15,0,SWAP},{15,14,SWAP},{13,14,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{13,14,SWAP},{2,3,SWAP},{15,0,SWAP}}, {}, 0., 0., 3}, + {0, 0, {}, {}, {{15,14,SWAP},{13,4,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2,3,SWAP},{15,14,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15,14,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2,3,SWAP},{3,14,SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1} + }} + }; + const std::unordered_map>> optimalSolutionQubits{ + {"3_17_13", { + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, + {2,1,0}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, + {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, + {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {2,1,0}, {2,1,0}, + {2,1,0}, {2,1,0}, {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, + {2,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, + {0,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, + {0,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, + {0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, + {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} + }}, + {"ex-1_166", { + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, + {2,1,0}, {2,1,0}, {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {0,1,2}, {1,0,2}, + {1,0,2}, {1,2,0}, {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} + }}, + {"ham3_102", { + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, + {2,0,1}, {2,1,0}, {0,1,2}, {1,0,2}, {1,0,2}, {0,1,2}, {1,0,2}, {1,0,2}, + {1,2,0}, {1,2,0}, {1,2,0} + }}, + {"miller_11", { + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, + {0,1,2}, {1,0,2}, {1,2,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,1,0}, + {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,0,1}, + {2,1,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,1,0}, {0,1,2}, {0,1,2}, + {0,2,1}, {0,2,1}, {0,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, + {0,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, + {2,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, {2,0,1}, {2,1,0}, + {2,1,0}, {1,2,0}, {1,2,0}, + {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {1,2,0}, {1,2,0}, + {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {1,2,0}, {1,2,0}, + {2,1,0}, {1,2,0}, {1,2,0}, + {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, + {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} + }}, + {"4gt11_84", { + {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, + {0,1,2,-1,4}, {2,1,0,3,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {1,0,2,-1,4}, + {1,2,0,-1,4}, {2,1,0,-1,4}, {2,0,1,-1,4}, {4,2,1,0,3}, {0,1,2,-1,4}, + {0,1,2,-1,4}, {0,2,1,-1,4}, {0,2,1,-1,4}, {2,0,1,-1,4}, {2,0,1,-1,4}, + {2,1,0,3,4} + }}, + {"4mod5-v0_20", { + {0,2,1,3,4}, {0,2,1,3,4}, {0,2,1,3,4}, {0,2,4,3,1}, {0,4,2,3,1}, + {0,4,1,3,2}, {0,4,2,3,1}, {0,4,2,3,1}, {4,0,2,1,3}, {4,2,0,1,3}, + {4,1,0,2,3}, {4,2,0,1,3}, {4,2,0,1,3}, {4,1,0,2,3}, {4,2,0,1,3}, + {4,2,0,1,3}, {0,2,1,3,4}, {0,2,1,3,4}, {0,2,3,1,4}, {0,3,2,4,1}, + {0,3,4,2,1}, {0,3,4,1,2}, {0,3,4,2,1}, {0,3,4,2,1} + }}, + {"mod5d1_63", { + {0,2,1,3,4}, {0,2,1,3,4}, {1,2,0,3,4}, {1,2,0,3,4}, {1,2,0,3,4}, + {1,2,4,3,0}, {4,2,1,3,0}, {4,2,0,3,1}, {4,2,1,3,0}, {4,2,1,3,0}, + {4,2,0,3,1}, {4,0,2,1,3}, {4,1,2,0,3}, {4,0,2,1,3}, {4,0,2,1,3}, + {4,0,2,1,3}, {4,1,2,0,3}, {4,1,2,0,3}, {4,0,2,1,3}, {4,1,2,0,3}, + {4,1,2,0,3}, {4,0,2,1,3}, {0,2,1,3,4}, {0,2,3,1,4}, {2,3,1,0,4}, + {2,3,1,0,4}, {2,3,1,0,4}, {2,3,1,4,0}, {2,3,4,1,0}, {2,3,4,0,1}, + {2,3,4,1,0}, {2,3,4,1,0}, {-1,3,1,2,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4} + }}, + {"ising_model_10", { + {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, + {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, + {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, + {0,1,2,3,4,5,6,7,8,9} + }}, + {"rd73_140", { + {0,1,2,3,4,5,6,7,8,9}, {0,2,3,4,5,1,7,6,8,9}, {2,3,4,0,7,5,1,6,8,9}, + {2,3,4,0,1,7,5,6,8,9}, {2,3,4,0,1,7,5,6,8,9}, {2,3,4,0,7,1,5,6,8,9}, + {2,7,3,4,0,1,5,6,8,9}, {2,3,4,0,7,8,1,5,6,9}, {3,4,2,8,0,7,1,5,6,9}, + {3,4,8,2,7,0,1,5,6,9}, {3,4,8,7,2,0,1,5,6,9}, {3,4,8,2,7,0,1,5,6,9}, + {3,8,4,2,7,0,1,5,6,9}, {3,8,9,4,7,2,1,5,6,-1,-1,-1,0}, + {8,3,9,4,7,2,1,5,6,-1,-1,-1,0}, {8,3,9,4,7,1,2,5,6,-1,-1,-1,0}, + {8,9,3,4,7,1,2,5,6,-1,-1,-1,0}, {8,9,3,4,7,2,1,5,6,-1,-1,-1,0}, + {9,8,3,4,7,1,2,5,6,-1,-1,-1,0}, {9,8,4,3,7,1,2,5,6,-1,-1,-1,0}, + {9,8,7,4,3,1,2,5,6,-1,-1,-1,0}, {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, + {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, {9,8,7,3,4,1,2,5,6,-1,-1,-1,0}, + {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, {9,8,4,3,7,1,2,5,6,-1,-1,-1,0}, + {9,8,4,3,2,7,1,5,6,-1,-1,-1,0}, + {9,8,-1,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,4}, + {9,-1,8,2,7,3,1,5,6,-1,-1,-1,0,-1,-1,4}, + {4,-1,8,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,9}, + {4,-1,8,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,9}, + {4,8,-1,2,7,3,1,5,6,-1,-1,-1,0,-1,-1,9}, + {9,8,-1,7,2,3,1,5,6,-1,-1,-1,0,-1,4}, + {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,4}, + {9,7,8,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, + {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, + {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, + {9,7,8,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, + {4,7,8,5,-1,2,3,1,6,-1,-1,-1,0,-1,-1,9}, + {9,7,5,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,8,7,3,-1,2,1,6,-1,-1,-1,0,-1,-1,4}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,4,5,7,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,8,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,7}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, + {9,5,8,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,7}, + {5,9,8,6,4,3,-1,2,1,-1,-1,-1,0,-1,-1,7}, + {7,9,8,6,4,3,-1,2,1,-1,-1,-1,0,5}, + {-1,9,6,8,4,3,-1,2,1,-1,-1,-1,0,-1,5,7}, + {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,7,5}, + {-1,9,8,6,-1,3,-1,2,1,-1,-1,-1,0,4,5,7}, + {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,5,7}, + {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,7,5}, + {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,7,4,5}, + {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,7,4,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,6,7,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,6,7,5}, + {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5} + }} + }; + for (const auto& [circuit, qubits] : optimalSolutionQubits) { + if (optimalSolutions.find(circuit) == optimalSolutions.end()) { + throw std::runtime_error("Missing precalculated optimal solutions for circuit " + circuit); + } + if (optimalSolutions.at(circuit).size() != qubits.size()) { + throw std::runtime_error("Missing some precalculated optimal solutions for circuit " + circuit); + } + for (std::size_t i = 0; i < qubits.size(); ++i) { + std::fill(optimalSolutions.at(circuit).at(i).qubits.begin(), optimalSolutions.at(circuit).at(i).qubits.end(), -1); + std::fill(optimalSolutions.at(circuit).at(i).locations.begin(), optimalSolutions.at(circuit).at(i).locations.end(), -1); + for (std::size_t j = 0; j < qubits.at(i).size(); ++j) { + if (qubits.at(i).at(j) >= 0) { + optimalSolutions.at(circuit).at(i).qubits[j] = qubits.at(i).at(j); + optimalSolutions.at(circuit).at(i).locations[static_cast(qubits.at(i).at(j))] = static_cast(j); + } + } + } + } + } void SetUp() override { - qc.import(testExampleDir + std::get<1>(GetParam()) + ".qasm"); + circuitName = std::get<1>(GetParam()); + qc.import(testExampleDir + circuitName + ".qasm"); ibmqYorktown.loadCouplingMap(AvailableArchitecture::IbmqYorktown); ibmqLondon.loadCouplingMap(testArchitectureDir + "ibmq_london.arch"); ibmqLondon.loadProperties(testCalibrationDir + "ibmq_london.csv"); @@ -305,6 +805,8 @@ class TestHeuristics } }; +std::unordered_map> TestHeuristics::optimalSolutions{}; + INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, testing::Combine( @@ -334,7 +836,14 @@ INSTANTIATE_TEST_SUITE_P( TEST_P(TestHeuristics, HeuristicProperties) { EXPECT_TRUE(!isAdmissible(settings.heuristic) || isPrincipallyAdmissible(settings.heuristic)) - << "Admissible heuristics are by definition also principally admissible"; + << "Admissible heuristics are by definition also principally admissible: " + << toString(settings.heuristic); + + EXPECT_TRUE(!(isTight(settings.heuristic) && + isFidelityAware(settings.heuristic))) + << "Fidelity-aware heuristics cannot be tight because of the " + "non-convexity of the fidelity-aware cost function: " + << toString(settings.heuristic); // list of nodes for each search process (i.e. each layer) in all mappings // each node is at the position corresponding to its id; positions of unused @@ -419,6 +928,24 @@ TEST_P(TestHeuristics, HeuristicProperties) { << " is not principally admissible " << layerNames.at(i) << " in node " << nodeId; } + if (isTight(settings.heuristic)) { + // Principally admissible heuristics are guaranteed to find a solution + // with optimal cost (given lookahead is disabled). If there are + // multiple optimal solutions, though, and the heuristic is not tight, + // the differences in heuristics can lead to a different node ordering + // and thereby different solutions (potentially even resulting in + // different costs in later layers) + // However, if a heuristic is both principally admissible and tight, + // it is guaranteed to always find the same solution as any other such + // heuristic. + if (optimalSolutions.find(circuitName) == optimalSolutions.end() || + optimalSolutions.at(circuitName).size() <= i) { + throw std::runtime_error("Missing precalculated optimal solution for circuit " + circuitName); + } + EXPECT_TRUE(finalSolutionNode == optimalSolutions.at(circuitName).at(i)) + << "Heuristic " << toString(settings.heuristic) + << " did not find the optimal solution " << layerNames.at(i); + } } for (std::size_t j = 0; j < nodes.size(); ++j) { From 63fbf1b36e57e5ca2fe42c1b391771235275b62a Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 00:26:27 +0100 Subject: [PATCH 16/47] fix register sizes in example circuits --- examples/0410184_169.qasm | 4 ++-- examples/3_17_13.qasm | 4 ++-- examples/4_49_16.qasm | 4 ++-- examples/4gt10-v1_81.qasm | 4 ++-- examples/4gt11_82.qasm | 4 ++-- examples/4gt11_83.qasm | 4 ++-- examples/4gt11_84.qasm | 4 ++-- examples/4gt12-v0_86.qasm | 4 ++-- examples/4gt12-v0_87.qasm | 4 ++-- examples/4gt12-v0_88.qasm | 4 ++-- examples/4gt12-v1_89.qasm | 4 ++-- examples/4gt13-v1_93.qasm | 4 ++-- examples/4gt13_90.qasm | 4 ++-- examples/4gt13_91.qasm | 4 ++-- examples/4gt13_92.qasm | 4 ++-- examples/4gt4-v0_72.qasm | 4 ++-- examples/4gt4-v0_73.qasm | 4 ++-- examples/4gt4-v0_78.qasm | 4 ++-- examples/4gt4-v0_79.qasm | 4 ++-- examples/4gt4-v0_80.qasm | 4 ++-- examples/4gt4-v1_74.qasm | 4 ++-- examples/4gt5_75.qasm | 4 ++-- examples/4gt5_76.qasm | 4 ++-- examples/4gt5_77.qasm | 4 ++-- examples/4mod5-bdd_287.qasm | 4 ++-- examples/4mod5-v0_18.qasm | 4 ++-- examples/4mod5-v0_19.qasm | 4 ++-- examples/4mod5-v0_20.qasm | 4 ++-- examples/4mod5-v1_22.qasm | 4 ++-- examples/4mod5-v1_23.qasm | 4 ++-- examples/4mod5-v1_24.qasm | 4 ++-- examples/4mod7-v0_94.qasm | 4 ++-- examples/4mod7-v1_96.qasm | 4 ++-- examples/9symml_195.qasm | 4 ++-- examples/C17_204.qasm | 4 ++-- examples/adr4_197.qasm | 4 ++-- examples/aj-e11_165.qasm | 4 ++-- examples/alu-bdd_288.qasm | 4 ++-- examples/alu-v0_26.qasm | 4 ++-- examples/alu-v0_27.qasm | 4 ++-- examples/alu-v1_28.qasm | 4 ++-- examples/alu-v1_29.qasm | 4 ++-- examples/alu-v2_30.qasm | 4 ++-- examples/alu-v2_31.qasm | 4 ++-- examples/alu-v2_32.qasm | 4 ++-- examples/alu-v2_33.qasm | 4 ++-- examples/alu-v3_34.qasm | 4 ++-- examples/alu-v3_35.qasm | 4 ++-- examples/alu-v4_36.qasm | 4 ++-- examples/alu-v4_37.qasm | 4 ++-- examples/clip_206.qasm | 4 ++-- examples/cm152a_212.qasm | 4 ++-- examples/cm42a_207.qasm | 4 ++-- examples/cm82a_208.qasm | 4 ++-- examples/cm85a_209.qasm | 4 ++-- examples/co14_215.qasm | 4 ++-- examples/con1_216.qasm | 4 ++-- examples/cycle10_2_110.qasm | 4 ++-- examples/dc1_220.qasm | 4 ++-- examples/dc2_222.qasm | 4 ++-- examples/decod24-bdd_294.qasm | 4 ++-- examples/decod24-enable_126.qasm | 4 ++-- examples/decod24-v0_38.qasm | 4 ++-- examples/decod24-v1_41.qasm | 4 ++-- examples/decod24-v2_43.qasm | 4 ++-- examples/decod24-v3_45.qasm | 4 ++-- examples/dist_223.qasm | 4 ++-- examples/ex-1_166.qasm | 4 ++-- examples/ex1_226.qasm | 4 ++-- examples/ex2_227.qasm | 4 ++-- examples/ex3_229.qasm | 4 ++-- examples/f2_232.qasm | 4 ++-- examples/graycode6_47.qasm | 4 ++-- examples/ground_state_estimation_10.qasm | 4 ++-- examples/ham15_107.qasm | 4 ++-- examples/ham3_102.qasm | 4 ++-- examples/ham7_104.qasm | 4 ++-- examples/hwb4_49.qasm | 4 ++-- examples/hwb5_53.qasm | 4 ++-- examples/hwb6_56.qasm | 4 ++-- examples/hwb7_59.qasm | 4 ++-- examples/hwb8_113.qasm | 4 ++-- examples/hwb9_119.qasm | 4 ++-- examples/ising_model_10.qasm | 4 ++-- examples/ising_model_13.qasm | 4 ++-- examples/life_238.qasm | 4 ++-- examples/majority_239.qasm | 4 ++-- examples/max46_240.qasm | 4 ++-- examples/miller_11.qasm | 4 ++-- examples/mini-alu_167.qasm | 4 ++-- examples/mini_alu_305.qasm | 4 ++-- examples/misex1_241.qasm | 4 ++-- examples/mod10_171.qasm | 4 ++-- examples/mod10_176.qasm | 4 ++-- examples/mod5adder_127.qasm | 4 ++-- examples/mod5d1_63.qasm | 4 ++-- examples/mod5d2_64.qasm | 4 ++-- examples/mod5mils_65.qasm | 4 ++-- examples/mod8-10_177.qasm | 4 ++-- examples/mod8-10_178.qasm | 4 ++-- examples/one-two-three-v0_97.qasm | 4 ++-- examples/one-two-three-v0_98.qasm | 4 ++-- examples/one-two-three-v1_99.qasm | 4 ++-- examples/one-two-three-v2_100.qasm | 4 ++-- examples/one-two-three-v3_101.qasm | 4 ++-- examples/plus63mod4096_163.qasm | 4 ++-- examples/plus63mod8192_164.qasm | 4 ++-- examples/pm1_249.qasm | 4 ++-- examples/qft_10.qasm | 4 ++-- examples/radd_250.qasm | 4 ++-- examples/rd32-v0_66.qasm | 4 ++-- examples/rd32-v1_68.qasm | 4 ++-- examples/rd32_270.qasm | 4 ++-- examples/rd53_130.qasm | 4 ++-- examples/rd53_131.qasm | 4 ++-- examples/rd53_133.qasm | 4 ++-- examples/rd53_135.qasm | 4 ++-- examples/rd53_138.qasm | 4 ++-- examples/rd53_251.qasm | 4 ++-- examples/rd53_311.qasm | 4 ++-- examples/rd73_140.qasm | 4 ++-- examples/rd73_252.qasm | 4 ++-- examples/rd84_142.qasm | 4 ++-- examples/rd84_253.qasm | 4 ++-- examples/root_255.qasm | 4 ++-- examples/sao2_257.qasm | 4 ++-- examples/sf_274.qasm | 4 ++-- examples/sf_276.qasm | 4 ++-- examples/sqn_258.qasm | 4 ++-- examples/sqrt8_260.qasm | 4 ++-- examples/squar5_261.qasm | 4 ++-- examples/square_root_7.qasm | 4 ++-- examples/sym10_262.qasm | 4 ++-- examples/sym6_145.qasm | 4 ++-- examples/sym6_316.qasm | 4 ++-- examples/sym9_146.qasm | 4 ++-- examples/sym9_148.qasm | 4 ++-- examples/sym9_193.qasm | 4 ++-- examples/sys6-v0_111.qasm | 4 ++-- examples/urf1_149.qasm | 4 ++-- examples/urf1_278.qasm | 4 ++-- examples/urf2_152.qasm | 4 ++-- examples/urf2_277.qasm | 4 ++-- examples/urf3_155.qasm | 4 ++-- examples/urf3_279.qasm | 4 ++-- examples/urf4_187.qasm | 4 ++-- examples/urf5_158.qasm | 4 ++-- examples/urf5_280.qasm | 4 ++-- examples/urf6_160.qasm | 4 ++-- examples/wim_266.qasm | 4 ++-- examples/xor5_254.qasm | 4 ++-- examples/z4_268.qasm | 4 ++-- 152 files changed, 304 insertions(+), 304 deletions(-) diff --git a/examples/0410184_169.qasm b/examples/0410184_169.qasm index e85dbbeec..e650f82b1 100644 --- a/examples/0410184_169.qasm +++ b/examples/0410184_169.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; cx q[4],q[3]; cx q[6],q[5]; cx q[8],q[7]; diff --git a/examples/3_17_13.qasm b/examples/3_17_13.qasm index 9481a3adb..55d211358 100644 --- a/examples/3_17_13.qasm +++ b/examples/3_17_13.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[3]; +creg c[3]; x q[2]; cx q[0],q[2]; cx q[2],q[1]; diff --git a/examples/4_49_16.qasm b/examples/4_49_16.qasm index b6815152b..07e4f5747 100644 --- a/examples/4_49_16.qasm +++ b/examples/4_49_16.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[3]; t q[4]; diff --git a/examples/4gt10-v1_81.qasm b/examples/4gt10-v1_81.qasm index 8db19386f..4ba7c0a32 100644 --- a/examples/4gt10-v1_81.qasm +++ b/examples/4gt10-v1_81.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; h q[1]; t q[2]; diff --git a/examples/4gt11_82.qasm b/examples/4gt11_82.qasm index 343656f8b..d5858a939 100644 --- a/examples/4gt11_82.qasm +++ b/examples/4gt11_82.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt11_83.qasm b/examples/4gt11_83.qasm index d10d1afae..2376ce29b 100644 --- a/examples/4gt11_83.qasm +++ b/examples/4gt11_83.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt11_84.qasm b/examples/4gt11_84.qasm index f20fd7a58..14efe0b9d 100644 --- a/examples/4gt11_84.qasm +++ b/examples/4gt11_84.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[0]; t q[2]; t q[1]; diff --git a/examples/4gt12-v0_86.qasm b/examples/4gt12-v0_86.qasm index 6fbdd6c5a..a5f6ebbf5 100644 --- a/examples/4gt12-v0_86.qasm +++ b/examples/4gt12-v0_86.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt12-v0_87.qasm b/examples/4gt12-v0_87.qasm index bb08b5316..edc9d32f7 100644 --- a/examples/4gt12-v0_87.qasm +++ b/examples/4gt12-v0_87.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt12-v0_88.qasm b/examples/4gt12-v0_88.qasm index 978a7d716..0f05bc7c2 100644 --- a/examples/4gt12-v0_88.qasm +++ b/examples/4gt12-v0_88.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[3]; t q[2]; t q[1]; diff --git a/examples/4gt12-v1_89.qasm b/examples/4gt12-v1_89.qasm index 331148078..d327f7e2f 100644 --- a/examples/4gt12-v1_89.qasm +++ b/examples/4gt12-v1_89.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; x q[0]; cx q[4],q[0]; h q[0]; diff --git a/examples/4gt13-v1_93.qasm b/examples/4gt13-v1_93.qasm index 67776a56d..cf8e01446 100644 --- a/examples/4gt13-v1_93.qasm +++ b/examples/4gt13-v1_93.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; cx q[4],q[0]; cx q[0],q[4]; diff --git a/examples/4gt13_90.qasm b/examples/4gt13_90.qasm index e6154accb..46f62d02e 100644 --- a/examples/4gt13_90.qasm +++ b/examples/4gt13_90.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt13_91.qasm b/examples/4gt13_91.qasm index 3777a6124..8de128c42 100644 --- a/examples/4gt13_91.qasm +++ b/examples/4gt13_91.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt13_92.qasm b/examples/4gt13_92.qasm index 16210fb13..8ce106bde 100644 --- a/examples/4gt13_92.qasm +++ b/examples/4gt13_92.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[4],q[0]; h q[0]; t q[1]; diff --git a/examples/4gt4-v0_72.qasm b/examples/4gt4-v0_72.qasm index cb1bfb19a..d51467102 100644 --- a/examples/4gt4-v0_72.qasm +++ b/examples/4gt4-v0_72.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[4],q[1]; h q[0]; t q[4]; diff --git a/examples/4gt4-v0_73.qasm b/examples/4gt4-v0_73.qasm index 9f7d31b37..999968926 100644 --- a/examples/4gt4-v0_73.qasm +++ b/examples/4gt4-v0_73.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[0],q[1]; cx q[2],q[1]; cx q[1],q[2]; diff --git a/examples/4gt4-v0_78.qasm b/examples/4gt4-v0_78.qasm index f260be24a..1138abab9 100644 --- a/examples/4gt4-v0_78.qasm +++ b/examples/4gt4-v0_78.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt4-v0_79.qasm b/examples/4gt4-v0_79.qasm index e092e0aa4..7c2aa12c8 100644 --- a/examples/4gt4-v0_79.qasm +++ b/examples/4gt4-v0_79.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[2],q[1]; cx q[1],q[2]; cx q[3],q[2]; diff --git a/examples/4gt4-v0_80.qasm b/examples/4gt4-v0_80.qasm index 32cc93d9e..8aa215665 100644 --- a/examples/4gt4-v0_80.qasm +++ b/examples/4gt4-v0_80.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[0]; t q[2]; t q[1]; diff --git a/examples/4gt4-v1_74.qasm b/examples/4gt4-v1_74.qasm index 1bb11c96f..18dbda4f5 100644 --- a/examples/4gt4-v1_74.qasm +++ b/examples/4gt4-v1_74.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; x q[0]; h q[1]; t q[0]; diff --git a/examples/4gt5_75.qasm b/examples/4gt5_75.qasm index 38ce1b44e..cf928c393 100644 --- a/examples/4gt5_75.qasm +++ b/examples/4gt5_75.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[4],q[1]; cx q[3],q[0]; cx q[1],q[4]; diff --git a/examples/4gt5_76.qasm b/examples/4gt5_76.qasm index e29ec26d2..55182dcd1 100644 --- a/examples/4gt5_76.qasm +++ b/examples/4gt5_76.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[0],q[1]; cx q[2],q[1]; cx q[1],q[2]; diff --git a/examples/4gt5_77.qasm b/examples/4gt5_77.qasm index 6df3bc119..a8d925e9b 100644 --- a/examples/4gt5_77.qasm +++ b/examples/4gt5_77.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; cx q[4],q[1]; cx q[1],q[4]; diff --git a/examples/4mod5-bdd_287.qasm b/examples/4mod5-bdd_287.qasm index 11d8f6586..682f1ff8b 100644 --- a/examples/4mod5-bdd_287.qasm +++ b/examples/4mod5-bdd_287.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; x q[4]; x q[6]; cx q[3],q[4]; diff --git a/examples/4mod5-v0_18.qasm b/examples/4mod5-v0_18.qasm index 3f2007bda..5c302014c 100644 --- a/examples/4mod5-v0_18.qasm +++ b/examples/4mod5-v0_18.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; x q[1]; h q[4]; diff --git a/examples/4mod5-v0_19.qasm b/examples/4mod5-v0_19.qasm index c402a6094..d75464785 100644 --- a/examples/4mod5-v0_19.qasm +++ b/examples/4mod5-v0_19.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[3]; cx q[1],q[3]; cx q[3],q[4]; diff --git a/examples/4mod5-v0_20.qasm b/examples/4mod5-v0_20.qasm index 7c145bd96..9b510865f 100644 --- a/examples/4mod5-v0_20.qasm +++ b/examples/4mod5-v0_20.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[1]; x q[0]; cx q[0],q[2]; diff --git a/examples/4mod5-v1_22.qasm b/examples/4mod5-v1_22.qasm index b32f89dd7..ac3e84353 100644 --- a/examples/4mod5-v1_22.qasm +++ b/examples/4mod5-v1_22.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[4]; cx q[0],q[2]; cx q[1],q[3]; diff --git a/examples/4mod5-v1_23.qasm b/examples/4mod5-v1_23.qasm index 58569e1d2..a417fab4d 100644 --- a/examples/4mod5-v1_23.qasm +++ b/examples/4mod5-v1_23.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[4]; h q[4]; t q[0]; diff --git a/examples/4mod5-v1_24.qasm b/examples/4mod5-v1_24.qasm index f75101120..3d6362e7f 100644 --- a/examples/4mod5-v1_24.qasm +++ b/examples/4mod5-v1_24.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[4]; cx q[3],q[1]; h q[0]; diff --git a/examples/4mod7-v0_94.qasm b/examples/4mod7-v0_94.qasm index ba4a5ee0d..a1e770153 100644 --- a/examples/4mod7-v0_94.qasm +++ b/examples/4mod7-v0_94.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[0]; t q[1]; t q[4]; diff --git a/examples/4mod7-v1_96.qasm b/examples/4mod7-v1_96.qasm index 838c97c17..87585452f 100644 --- a/examples/4mod7-v1_96.qasm +++ b/examples/4mod7-v1_96.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; x q[0]; h q[0]; diff --git a/examples/9symml_195.qasm b/examples/9symml_195.qasm index ee911faaf..f976c0dc5 100644 --- a/examples/9symml_195.qasm +++ b/examples/9symml_195.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; h q[1]; t q[6]; t q[10]; diff --git a/examples/C17_204.qasm b/examples/C17_204.qasm index f8807f5da..ee5b64cf3 100644 --- a/examples/C17_204.qasm +++ b/examples/C17_204.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; cx q[5],q[1]; cx q[5],q[0]; h q[1]; diff --git a/examples/adr4_197.qasm b/examples/adr4_197.qasm index e01f37eed..95900127c 100644 --- a/examples/adr4_197.qasm +++ b/examples/adr4_197.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[4]; t q[6]; t q[12]; diff --git a/examples/aj-e11_165.qasm b/examples/aj-e11_165.qasm index b4d54ba18..aaea255d3 100644 --- a/examples/aj-e11_165.qasm +++ b/examples/aj-e11_165.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[1],q[2]; cx q[2],q[3]; h q[2]; diff --git a/examples/alu-bdd_288.qasm b/examples/alu-bdd_288.qasm index 3172aea8a..614e5225b 100644 --- a/examples/alu-bdd_288.qasm +++ b/examples/alu-bdd_288.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; cx q[0],q[5]; h q[5]; t q[1]; diff --git a/examples/alu-v0_26.qasm b/examples/alu-v0_26.qasm index 8f7ac1762..4e8ddd6d3 100644 --- a/examples/alu-v0_26.qasm +++ b/examples/alu-v0_26.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; cx q[2],q[0]; h q[2]; diff --git a/examples/alu-v0_27.qasm b/examples/alu-v0_27.qasm index 7d3b15d58..95811ab13 100644 --- a/examples/alu-v0_27.qasm +++ b/examples/alu-v0_27.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[4]; cx q[2],q[1]; h q[2]; diff --git a/examples/alu-v1_28.qasm b/examples/alu-v1_28.qasm index 1aace02b6..7748feda8 100644 --- a/examples/alu-v1_28.qasm +++ b/examples/alu-v1_28.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[4],q[3]; cx q[1],q[2]; cx q[2],q[4]; diff --git a/examples/alu-v1_29.qasm b/examples/alu-v1_29.qasm index 13b0f0673..9e51d3b8f 100644 --- a/examples/alu-v1_29.qasm +++ b/examples/alu-v1_29.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[4]; x q[3]; cx q[1],q[2]; diff --git a/examples/alu-v2_30.qasm b/examples/alu-v2_30.qasm index b8d432248..b92af848d 100644 --- a/examples/alu-v2_30.qasm +++ b/examples/alu-v2_30.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[0],q[2]; cx q[2],q[0]; cx q[0],q[1]; diff --git a/examples/alu-v2_31.qasm b/examples/alu-v2_31.qasm index d1e567812..b74b1612d 100644 --- a/examples/alu-v2_31.qasm +++ b/examples/alu-v2_31.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[0],q[2]; h q[2]; t q[0]; diff --git a/examples/alu-v2_32.qasm b/examples/alu-v2_32.qasm index 2f4b09486..e760ed2b3 100644 --- a/examples/alu-v2_32.qasm +++ b/examples/alu-v2_32.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[0]; t q[4]; diff --git a/examples/alu-v2_33.qasm b/examples/alu-v2_33.qasm index edf7b92f8..afe8985ca 100644 --- a/examples/alu-v2_33.qasm +++ b/examples/alu-v2_33.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[4]; cx q[3],q[4]; cx q[2],q[1]; diff --git a/examples/alu-v3_34.qasm b/examples/alu-v3_34.qasm index 78d6b7769..8afe12483 100644 --- a/examples/alu-v3_34.qasm +++ b/examples/alu-v3_34.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[4]; t q[2]; diff --git a/examples/alu-v3_35.qasm b/examples/alu-v3_35.qasm index fb00199d2..c9fa3e3f2 100644 --- a/examples/alu-v3_35.qasm +++ b/examples/alu-v3_35.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[4],q[3]; cx q[2],q[1]; x q[2]; diff --git a/examples/alu-v4_36.qasm b/examples/alu-v4_36.qasm index 0e3544161..dbdf1603f 100644 --- a/examples/alu-v4_36.qasm +++ b/examples/alu-v4_36.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[2]; t q[0]; diff --git a/examples/alu-v4_37.qasm b/examples/alu-v4_37.qasm index 618f5f2e8..579d70992 100644 --- a/examples/alu-v4_37.qasm +++ b/examples/alu-v4_37.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[4]; cx q[2],q[1]; x q[2]; diff --git a/examples/clip_206.qasm b/examples/clip_206.qasm index 3ec43baaa..741a4dc64 100644 --- a/examples/clip_206.qasm +++ b/examples/clip_206.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; cx q[13],q[1]; cx q[8],q[0]; x q[7]; diff --git a/examples/cm152a_212.qasm b/examples/cm152a_212.qasm index 2f4744d36..0e0fb2e6e 100644 --- a/examples/cm152a_212.qasm +++ b/examples/cm152a_212.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; h q[0]; t q[1]; t q[11]; diff --git a/examples/cm42a_207.qasm b/examples/cm42a_207.qasm index 871ea5786..c729f5bbb 100644 --- a/examples/cm42a_207.qasm +++ b/examples/cm42a_207.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; x q[9]; x q[8]; x q[7]; diff --git a/examples/cm82a_208.qasm b/examples/cm82a_208.qasm index 7a0f22ec5..115593e01 100644 --- a/examples/cm82a_208.qasm +++ b/examples/cm82a_208.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; h q[0]; t q[7]; t q[3]; diff --git a/examples/cm85a_209.qasm b/examples/cm85a_209.qasm index d66b899ba..3e61f471c 100644 --- a/examples/cm85a_209.qasm +++ b/examples/cm85a_209.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; h q[1]; t q[4]; t q[13]; diff --git a/examples/co14_215.qasm b/examples/co14_215.qasm index 833c8ccb3..0cba559a1 100644 --- a/examples/co14_215.qasm +++ b/examples/co14_215.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; x q[12]; x q[11]; x q[10]; diff --git a/examples/con1_216.qasm b/examples/con1_216.qasm index b3abcdff9..16fda177e 100644 --- a/examples/con1_216.qasm +++ b/examples/con1_216.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; cx q[8],q[0]; cx q[4],q[0]; h q[1]; diff --git a/examples/cycle10_2_110.qasm b/examples/cycle10_2_110.qasm index 31b8539d1..632f329c4 100644 --- a/examples/cycle10_2_110.qasm +++ b/examples/cycle10_2_110.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; h q[0]; t q[4]; t q[11]; diff --git a/examples/dc1_220.qasm b/examples/dc1_220.qasm index 2dfaaa94f..8a4fb6a11 100644 --- a/examples/dc1_220.qasm +++ b/examples/dc1_220.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; x q[10]; h q[4]; t q[10]; diff --git a/examples/dc2_222.qasm b/examples/dc2_222.qasm index e5d2d6072..eb0c770fb 100644 --- a/examples/dc2_222.qasm +++ b/examples/dc2_222.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; cx q[7],q[0]; x q[14]; h q[6]; diff --git a/examples/decod24-bdd_294.qasm b/examples/decod24-bdd_294.qasm index 1e83fd69d..b3ecbfe79 100644 --- a/examples/decod24-bdd_294.qasm +++ b/examples/decod24-bdd_294.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; x q[3]; x q[4]; h q[2]; diff --git a/examples/decod24-enable_126.qasm b/examples/decod24-enable_126.qasm index 85ce0cea6..96f3a46e0 100644 --- a/examples/decod24-enable_126.qasm +++ b/examples/decod24-enable_126.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[2]; t q[1]; t q[4]; diff --git a/examples/decod24-v0_38.qasm b/examples/decod24-v0_38.qasm index f4ac0e1d4..6427c6f96 100644 --- a/examples/decod24-v0_38.qasm +++ b/examples/decod24-v0_38.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[4]; +creg c[4]; h q[0]; t q[3]; t q[2]; diff --git a/examples/decod24-v1_41.qasm b/examples/decod24-v1_41.qasm index db9d0dfc0..602331303 100644 --- a/examples/decod24-v1_41.qasm +++ b/examples/decod24-v1_41.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[1]; h q[0]; t q[1]; diff --git a/examples/decod24-v2_43.qasm b/examples/decod24-v2_43.qasm index 88702e2bc..05105b063 100644 --- a/examples/decod24-v2_43.qasm +++ b/examples/decod24-v2_43.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[4]; +creg c[4]; x q[0]; h q[0]; t q[3]; diff --git a/examples/decod24-v3_45.qasm b/examples/decod24-v3_45.qasm index 9edd82149..086a181e5 100644 --- a/examples/decod24-v3_45.qasm +++ b/examples/decod24-v3_45.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; x q[1]; h q[0]; diff --git a/examples/dist_223.qasm b/examples/dist_223.qasm index ef3fb03f6..784663697 100644 --- a/examples/dist_223.qasm +++ b/examples/dist_223.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; cx q[12],q[3]; cx q[12],q[2]; h q[1]; diff --git a/examples/ex-1_166.qasm b/examples/ex-1_166.qasm index 899aa1430..36aab83e2 100644 --- a/examples/ex-1_166.qasm +++ b/examples/ex-1_166.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[3]; +creg c[3]; cx q[0],q[1]; h q[0]; t q[1]; diff --git a/examples/ex1_226.qasm b/examples/ex1_226.qasm index 8115cd6d1..1ae17f190 100644 --- a/examples/ex1_226.qasm +++ b/examples/ex1_226.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[3],q[0]; cx q[1],q[0]; cx q[5],q[0]; diff --git a/examples/ex2_227.qasm b/examples/ex2_227.qasm index 6687064f1..7c85ea7d5 100644 --- a/examples/ex2_227.qasm +++ b/examples/ex2_227.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[0]; t q[2]; t q[6]; diff --git a/examples/ex3_229.qasm b/examples/ex3_229.qasm index 4fbb4dce0..e737ba838 100644 --- a/examples/ex3_229.qasm +++ b/examples/ex3_229.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[0]; t q[5]; t q[4]; diff --git a/examples/f2_232.qasm b/examples/f2_232.qasm index df66a501f..7e729ff22 100644 --- a/examples/f2_232.qasm +++ b/examples/f2_232.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; x q[7]; h q[0]; t q[7]; diff --git a/examples/graycode6_47.qasm b/examples/graycode6_47.qasm index 3e41f91c5..9ab2fa502 100644 --- a/examples/graycode6_47.qasm +++ b/examples/graycode6_47.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[1],q[0]; cx q[2],q[1]; cx q[3],q[2]; diff --git a/examples/ground_state_estimation_10.qasm b/examples/ground_state_estimation_10.qasm index 55c48cd2b..d4de234e6 100644 --- a/examples/ground_state_estimation_10.qasm +++ b/examples/ground_state_estimation_10.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; x q[3]; x q[4]; x q[5]; diff --git a/examples/ham15_107.qasm b/examples/ham15_107.qasm index 0765802e4..1b4d3d380 100644 --- a/examples/ham15_107.qasm +++ b/examples/ham15_107.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; h q[1]; t q[14]; t q[8]; diff --git a/examples/ham3_102.qasm b/examples/ham3_102.qasm index 97779313a..401a8d451 100644 --- a/examples/ham3_102.qasm +++ b/examples/ham3_102.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[3]; +creg c[3]; h q[0]; t q[1]; t q[2]; diff --git a/examples/ham7_104.qasm b/examples/ham7_104.qasm index 44bc230eb..6cd9a8d25 100644 --- a/examples/ham7_104.qasm +++ b/examples/ham7_104.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[2]; t q[6]; t q[3]; diff --git a/examples/hwb4_49.qasm b/examples/hwb4_49.qasm index d00c3d0af..5ed753d1c 100644 --- a/examples/hwb4_49.qasm +++ b/examples/hwb4_49.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[1]; cx q[2],q[3]; cx q[3],q[2]; diff --git a/examples/hwb5_53.qasm b/examples/hwb5_53.qasm index 858331d8f..7e59d822e 100644 --- a/examples/hwb5_53.qasm +++ b/examples/hwb5_53.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[3],q[1]; cx q[4],q[3]; h q[1]; diff --git a/examples/hwb6_56.qasm b/examples/hwb6_56.qasm index c79820ee3..bd98f3a35 100644 --- a/examples/hwb6_56.qasm +++ b/examples/hwb6_56.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[5]; t q[0]; t q[3]; diff --git a/examples/hwb7_59.qasm b/examples/hwb7_59.qasm index 78144cca1..65aa600b2 100644 --- a/examples/hwb7_59.qasm +++ b/examples/hwb7_59.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; h q[1]; t q[4]; t q[6]; diff --git a/examples/hwb8_113.qasm b/examples/hwb8_113.qasm index e1499c030..4ab0044d1 100644 --- a/examples/hwb8_113.qasm +++ b/examples/hwb8_113.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; h q[1]; t q[5]; t q[8]; diff --git a/examples/hwb9_119.qasm b/examples/hwb9_119.qasm index 8038dda83..5f866044d 100644 --- a/examples/hwb9_119.qasm +++ b/examples/hwb9_119.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; cx q[8],q[1]; h q[8]; t q[0]; diff --git a/examples/ising_model_10.qasm b/examples/ising_model_10.qasm index 8fa2e4d62..8ec8c4ed2 100644 --- a/examples/ising_model_10.qasm +++ b/examples/ising_model_10.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[0]; h q[1]; h q[2]; diff --git a/examples/ising_model_13.qasm b/examples/ising_model_13.qasm index e06d7e657..8dc66cf01 100644 --- a/examples/ising_model_13.qasm +++ b/examples/ising_model_13.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[0]; h q[1]; h q[2]; diff --git a/examples/life_238.qasm b/examples/life_238.qasm index bf74c097b..aa9276b22 100644 --- a/examples/life_238.qasm +++ b/examples/life_238.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; x q[7]; x q[4]; x q[3]; diff --git a/examples/majority_239.qasm b/examples/majority_239.qasm index a61d9c736..3b1f95472 100644 --- a/examples/majority_239.qasm +++ b/examples/majority_239.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; cx q[2],q[0]; x q[2]; h q[0]; diff --git a/examples/max46_240.qasm b/examples/max46_240.qasm index 3b0ca6c6a..020323e2c 100644 --- a/examples/max46_240.qasm +++ b/examples/max46_240.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; x q[3]; h q[0]; t q[1]; diff --git a/examples/miller_11.qasm b/examples/miller_11.qasm index 65fa7c9f3..a79ef1d48 100644 --- a/examples/miller_11.qasm +++ b/examples/miller_11.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[3]; +creg c[3]; cx q[2],q[1]; h q[2]; t q[1]; diff --git a/examples/mini-alu_167.qasm b/examples/mini-alu_167.qasm index d91256f7c..8c72fed31 100644 --- a/examples/mini-alu_167.qasm +++ b/examples/mini-alu_167.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[0]; t q[3]; diff --git a/examples/mini_alu_305.qasm b/examples/mini_alu_305.qasm index 59d9826f6..00635c27e 100644 --- a/examples/mini_alu_305.qasm +++ b/examples/mini_alu_305.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; x q[6]; x q[7]; x q[8]; diff --git a/examples/misex1_241.qasm b/examples/misex1_241.qasm index ab4e1d4d9..d35aef334 100644 --- a/examples/misex1_241.qasm +++ b/examples/misex1_241.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; x q[14]; h q[6]; t q[11]; diff --git a/examples/mod10_171.qasm b/examples/mod10_171.qasm index b0904c14c..310505ef8 100644 --- a/examples/mod10_171.qasm +++ b/examples/mod10_171.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[0],q[2]; h q[3]; t q[0]; diff --git a/examples/mod10_176.qasm b/examples/mod10_176.qasm index 8a703f9e6..698c5fd24 100644 --- a/examples/mod10_176.qasm +++ b/examples/mod10_176.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[1]; t q[3]; t q[2]; diff --git a/examples/mod5adder_127.qasm b/examples/mod5adder_127.qasm index ee11f4ae2..ee211814a 100644 --- a/examples/mod5adder_127.qasm +++ b/examples/mod5adder_127.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; x q[3]; x q[4]; x q[5]; diff --git a/examples/mod5d1_63.qasm b/examples/mod5d1_63.qasm index 6dabfbede..59153aa47 100644 --- a/examples/mod5d1_63.qasm +++ b/examples/mod5d1_63.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[1]; cx q[2],q[0]; cx q[1],q[4]; diff --git a/examples/mod5d2_64.qasm b/examples/mod5d2_64.qasm index a66c2f381..3a2398fe7 100644 --- a/examples/mod5d2_64.qasm +++ b/examples/mod5d2_64.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[2],q[1]; h q[0]; t q[3]; diff --git a/examples/mod5mils_65.qasm b/examples/mod5mils_65.qasm index bd525d094..d02d51b08 100644 --- a/examples/mod5mils_65.qasm +++ b/examples/mod5mils_65.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[1],q[3]; x q[3]; h q[4]; diff --git a/examples/mod8-10_177.qasm b/examples/mod8-10_177.qasm index 58de9d36e..d5606bc0a 100644 --- a/examples/mod8-10_177.qasm +++ b/examples/mod8-10_177.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[1],q[3]; cx q[1],q[2]; h q[5]; diff --git a/examples/mod8-10_178.qasm b/examples/mod8-10_178.qasm index 090258d1a..ab582df40 100644 --- a/examples/mod8-10_178.qasm +++ b/examples/mod8-10_178.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[2]; t q[4]; t q[3]; diff --git a/examples/one-two-three-v0_97.qasm b/examples/one-two-three-v0_97.qasm index 3c5968a81..3ba56f872 100644 --- a/examples/one-two-three-v0_97.qasm +++ b/examples/one-two-three-v0_97.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[3],q[2]; cx q[4],q[1]; h q[0]; diff --git a/examples/one-two-three-v0_98.qasm b/examples/one-two-three-v0_98.qasm index ef1d21f1c..afe2690f0 100644 --- a/examples/one-two-three-v0_98.qasm +++ b/examples/one-two-three-v0_98.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; cx q[4],q[1]; h q[0]; t q[4]; diff --git a/examples/one-two-three-v1_99.qasm b/examples/one-two-three-v1_99.qasm index aa0d613fa..31f6b5264 100644 --- a/examples/one-two-three-v1_99.qasm +++ b/examples/one-two-three-v1_99.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[1]; h q[1]; t q[2]; diff --git a/examples/one-two-three-v2_100.qasm b/examples/one-two-three-v2_100.qasm index 3b0f50382..b115182f4 100644 --- a/examples/one-two-three-v2_100.qasm +++ b/examples/one-two-three-v2_100.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; cx q[4],q[1]; cx q[2],q[0]; diff --git a/examples/one-two-three-v3_101.qasm b/examples/one-two-three-v3_101.qasm index 847ac28b6..cfe44c65a 100644 --- a/examples/one-two-three-v3_101.qasm +++ b/examples/one-two-three-v3_101.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; x q[0]; x q[1]; cx q[3],q[1]; diff --git a/examples/plus63mod4096_163.qasm b/examples/plus63mod4096_163.qasm index 8811dece7..cb9cb1174 100644 --- a/examples/plus63mod4096_163.qasm +++ b/examples/plus63mod4096_163.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[5]; t q[6]; t q[7]; diff --git a/examples/plus63mod8192_164.qasm b/examples/plus63mod8192_164.qasm index c084266f4..ec182af83 100644 --- a/examples/plus63mod8192_164.qasm +++ b/examples/plus63mod8192_164.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; h q[6]; t q[7]; t q[8]; diff --git a/examples/pm1_249.qasm b/examples/pm1_249.qasm index 871ea5786..c729f5bbb 100644 --- a/examples/pm1_249.qasm +++ b/examples/pm1_249.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; x q[9]; x q[8]; x q[7]; diff --git a/examples/qft_10.qasm b/examples/qft_10.qasm index 90add64a7..e02d13f23 100644 --- a/examples/qft_10.qasm +++ b/examples/qft_10.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[0]; rz(-0.7854) q[0]; cx q[0],q[1]; diff --git a/examples/radd_250.qasm b/examples/radd_250.qasm index 2014e348d..fed8abcb6 100644 --- a/examples/radd_250.qasm +++ b/examples/radd_250.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[2]; t q[8]; t q[10]; diff --git a/examples/rd32-v0_66.qasm b/examples/rd32-v0_66.qasm index ca105c4c0..651b8c4ea 100644 --- a/examples/rd32-v0_66.qasm +++ b/examples/rd32-v0_66.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[4]; +creg c[4]; h q[3]; t q[1]; t q[0]; diff --git a/examples/rd32-v1_68.qasm b/examples/rd32-v1_68.qasm index a9e5f13c7..527627811 100644 --- a/examples/rd32-v1_68.qasm +++ b/examples/rd32-v1_68.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[4]; +creg c[4]; x q[3]; h q[3]; t q[1]; diff --git a/examples/rd32_270.qasm b/examples/rd32_270.qasm index 925f5bbf9..72eefc6e7 100644 --- a/examples/rd32_270.qasm +++ b/examples/rd32_270.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[5]; +creg c[5]; h q[3]; t q[0]; t q[2]; diff --git a/examples/rd53_130.qasm b/examples/rd53_130.qasm index 5dc0b939d..5eea46271 100644 --- a/examples/rd53_130.qasm +++ b/examples/rd53_130.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; x q[5]; x q[6]; h q[2]; diff --git a/examples/rd53_131.qasm b/examples/rd53_131.qasm index ae4010810..0e1ce47de 100644 --- a/examples/rd53_131.qasm +++ b/examples/rd53_131.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[6]; t q[0]; t q[5]; diff --git a/examples/rd53_133.qasm b/examples/rd53_133.qasm index 442b55820..52ea94d86 100644 --- a/examples/rd53_133.qasm +++ b/examples/rd53_133.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[6]; t q[3]; t q[5]; diff --git a/examples/rd53_135.qasm b/examples/rd53_135.qasm index dc1ff0472..254b5b1d1 100644 --- a/examples/rd53_135.qasm +++ b/examples/rd53_135.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; cx q[1],q[5]; cx q[2],q[1]; cx q[1],q[0]; diff --git a/examples/rd53_138.qasm b/examples/rd53_138.qasm index f743fbf14..a62333ed1 100644 --- a/examples/rd53_138.qasm +++ b/examples/rd53_138.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; h q[5]; t q[0]; t q[1]; diff --git a/examples/rd53_251.qasm b/examples/rd53_251.qasm index 0b2175a29..494cc5737 100644 --- a/examples/rd53_251.qasm +++ b/examples/rd53_251.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; cx q[6],q[1]; h q[2]; t q[3]; diff --git a/examples/rd53_311.qasm b/examples/rd53_311.qasm index 157d13a04..8882559b4 100644 --- a/examples/rd53_311.qasm +++ b/examples/rd53_311.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; x q[11]; cx q[3],q[5]; h q[5]; diff --git a/examples/rd73_140.qasm b/examples/rd73_140.qasm index 6f8638ebb..2fe3e2fd9 100644 --- a/examples/rd73_140.qasm +++ b/examples/rd73_140.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[7]; t q[0]; t q[1]; diff --git a/examples/rd73_252.qasm b/examples/rd73_252.qasm index 089397a93..723130317 100644 --- a/examples/rd73_252.qasm +++ b/examples/rd73_252.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[2]; t q[8]; t q[6]; diff --git a/examples/rd84_142.qasm b/examples/rd84_142.qasm index ad37e3cd8..8efe801ae 100644 --- a/examples/rd84_142.qasm +++ b/examples/rd84_142.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; h q[8]; t q[0]; t q[1]; diff --git a/examples/rd84_253.qasm b/examples/rd84_253.qasm index 24f1e0d46..c6af1b6f6 100644 --- a/examples/rd84_253.qasm +++ b/examples/rd84_253.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; cx q[10],q[2]; cx q[8],q[2]; cx q[8],q[0]; diff --git a/examples/root_255.qasm b/examples/root_255.qasm index 81afd05c2..7a93a1dc3 100644 --- a/examples/root_255.qasm +++ b/examples/root_255.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[3]; t q[12]; t q[11]; diff --git a/examples/sao2_257.qasm b/examples/sao2_257.qasm index 02481d3fb..ea0fc4dc4 100644 --- a/examples/sao2_257.qasm +++ b/examples/sao2_257.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; x q[4]; cx q[4],q[1]; x q[8]; diff --git a/examples/sf_274.qasm b/examples/sf_274.qasm index 8e0623840..a028ce918 100644 --- a/examples/sf_274.qasm +++ b/examples/sf_274.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; h q[4]; t q[2]; t q[5]; diff --git a/examples/sf_276.qasm b/examples/sf_276.qasm index 47b628c08..884456ce5 100644 --- a/examples/sf_276.qasm +++ b/examples/sf_276.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; x q[0]; h q[5]; t q[0]; diff --git a/examples/sqn_258.qasm b/examples/sqn_258.qasm index bb92597a1..5079b757b 100644 --- a/examples/sqn_258.qasm +++ b/examples/sqn_258.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; x q[5]; h q[1]; t q[4]; diff --git a/examples/sqrt8_260.qasm b/examples/sqrt8_260.qasm index 0f092683f..fe5e99a9a 100644 --- a/examples/sqrt8_260.qasm +++ b/examples/sqrt8_260.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; h q[3]; t q[11]; t q[10]; diff --git a/examples/squar5_261.qasm b/examples/squar5_261.qasm index 750ebe76c..32a655f06 100644 --- a/examples/squar5_261.qasm +++ b/examples/squar5_261.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[13]; +creg c[13]; h q[5]; t q[11]; t q[10]; diff --git a/examples/square_root_7.qasm b/examples/square_root_7.qasm index c014ef480..b22bca7c3 100644 --- a/examples/square_root_7.qasm +++ b/examples/square_root_7.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; h q[0]; h q[1]; h q[2]; diff --git a/examples/sym10_262.qasm b/examples/sym10_262.qasm index b2b1aa8d4..16acb08d7 100644 --- a/examples/sym10_262.qasm +++ b/examples/sym10_262.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; h q[2]; t q[6]; t q[11]; diff --git a/examples/sym6_145.qasm b/examples/sym6_145.qasm index 4e8125c0f..b4059e212 100644 --- a/examples/sym6_145.qasm +++ b/examples/sym6_145.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[7]; +creg c[7]; h q[0]; t q[1]; t q[2]; diff --git a/examples/sym6_316.qasm b/examples/sym6_316.qasm index 7806fd882..947b5b54c 100644 --- a/examples/sym6_316.qasm +++ b/examples/sym6_316.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[14]; +creg c[14]; x q[12]; cx q[0],q[6]; h q[6]; diff --git a/examples/sym9_146.qasm b/examples/sym9_146.qasm index 9ec96aef3..7ee6f9ae0 100644 --- a/examples/sym9_146.qasm +++ b/examples/sym9_146.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[12]; +creg c[12]; h q[9]; t q[0]; t q[1]; diff --git a/examples/sym9_148.qasm b/examples/sym9_148.qasm index 7821105cd..f525bc414 100644 --- a/examples/sym9_148.qasm +++ b/examples/sym9_148.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[9]; t q[8]; t q[4]; diff --git a/examples/sym9_193.qasm b/examples/sym9_193.qasm index ee911faaf..f976c0dc5 100644 --- a/examples/sym9_193.qasm +++ b/examples/sym9_193.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; h q[1]; t q[6]; t q[10]; diff --git a/examples/sys6-v0_111.qasm b/examples/sys6-v0_111.qasm index d60df6446..3d15082ba 100644 --- a/examples/sys6-v0_111.qasm +++ b/examples/sys6-v0_111.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[6]; t q[0]; t q[1]; diff --git a/examples/urf1_149.qasm b/examples/urf1_149.qasm index be1e7dd8d..bcc0913ac 100644 --- a/examples/urf1_149.qasm +++ b/examples/urf1_149.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; h q[6]; t q[7]; t q[4]; diff --git a/examples/urf1_278.qasm b/examples/urf1_278.qasm index 5878d66b4..17ba2d237 100644 --- a/examples/urf1_278.qasm +++ b/examples/urf1_278.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; x q[0]; cx q[0],q[2]; cx q[2],q[0]; diff --git a/examples/urf2_152.qasm b/examples/urf2_152.qasm index f3d005ee5..f9e0a19d1 100644 --- a/examples/urf2_152.qasm +++ b/examples/urf2_152.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; h q[0]; t q[1]; t q[5]; diff --git a/examples/urf2_277.qasm b/examples/urf2_277.qasm index 95e03aab3..854f8aa31 100644 --- a/examples/urf2_277.qasm +++ b/examples/urf2_277.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[8]; +creg c[8]; x q[0]; cx q[3],q[2]; cx q[2],q[3]; diff --git a/examples/urf3_155.qasm b/examples/urf3_155.qasm index a01a36029..6c03aac80 100644 --- a/examples/urf3_155.qasm +++ b/examples/urf3_155.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; h q[3]; t q[1]; t q[7]; diff --git a/examples/urf3_279.qasm b/examples/urf3_279.qasm index 14a400890..232a952b2 100644 --- a/examples/urf3_279.qasm +++ b/examples/urf3_279.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[10]; +creg c[10]; x q[0]; cx q[3],q[2]; cx q[2],q[1]; diff --git a/examples/urf4_187.qasm b/examples/urf4_187.qasm index 11c5a01d9..e27df672e 100644 --- a/examples/urf4_187.qasm +++ b/examples/urf4_187.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; h q[8]; t q[10]; t q[9]; diff --git a/examples/urf5_158.qasm b/examples/urf5_158.qasm index 9e0a8d011..d5ee64cd2 100644 --- a/examples/urf5_158.qasm +++ b/examples/urf5_158.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; h q[1]; t q[8]; t q[7]; diff --git a/examples/urf5_280.qasm b/examples/urf5_280.qasm index 28368402a..cefb85f97 100644 --- a/examples/urf5_280.qasm +++ b/examples/urf5_280.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[9]; +creg c[9]; x q[0]; cx q[2],q[1]; cx q[2],q[3]; diff --git a/examples/urf6_160.qasm b/examples/urf6_160.qasm index 451e9463a..23b20d649 100644 --- a/examples/urf6_160.qasm +++ b/examples/urf6_160.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[15]; +creg c[15]; h q[1]; t q[14]; t q[12]; diff --git a/examples/wim_266.qasm b/examples/wim_266.qasm index 4b479b1d3..1b270d91b 100644 --- a/examples/wim_266.qasm +++ b/examples/wim_266.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; x q[6]; x q[5]; x q[4]; diff --git a/examples/xor5_254.qasm b/examples/xor5_254.qasm index 8115cd6d1..1ae17f190 100644 --- a/examples/xor5_254.qasm +++ b/examples/xor5_254.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[6]; +creg c[6]; cx q[3],q[0]; cx q[1],q[0]; cx q[5],q[0]; diff --git a/examples/z4_268.qasm b/examples/z4_268.qasm index 3fbb32159..aca704cc0 100644 --- a/examples/z4_268.qasm +++ b/examples/z4_268.qasm @@ -1,7 +1,7 @@ OPENQASM 2.0; include "qelib1.inc"; -qreg q[16]; -creg c[16]; +qreg q[11]; +creg c[11]; cx q[4],q[0]; cx q[10],q[0]; h q[3]; From d2106bb3c2f5efa3bc30f5ed40a3c29245521acb Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 00:40:43 +0100 Subject: [PATCH 17/47] adding documentation --- docs/source/library/Mapping.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/library/Mapping.rst b/docs/source/library/Mapping.rst index 727b0d2af..63f4fc9f8 100644 --- a/docs/source/library/Mapping.rst +++ b/docs/source/library/Mapping.rst @@ -18,10 +18,16 @@ The following classes provide a more explicit way of initializing the respective .. currentmodule:: mqt.qmap .. autoclass:: Method + + .. autoclass:: Heuristic + + .. autoclass:: LookaheadHeuristic .. autoclass:: Layering .. autoclass:: InitialLayout + + .. autoclass:: EarlyTermination .. autoclass:: Encoding From 74f706ae7be2155b79c7b51aff69298d9d50d1df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:41:34 +0000 Subject: [PATCH 18/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/source/library/Mapping.rst | 6 +- include/Architecture.hpp | 28 +- include/configuration/Heuristic.hpp | 2 +- include/heuristic/HeuristicMapper.hpp | 50 +- include/utils.hpp | 22 +- src/Architecture.cpp | 11 +- src/heuristic/HeuristicMapper.cpp | 283 ++--- src/utils.cpp | 45 +- test/test_general.cpp | 5 +- test/test_heuristic.cpp | 1367 +++++++++++++++---------- 10 files changed, 1088 insertions(+), 731 deletions(-) diff --git a/docs/source/library/Mapping.rst b/docs/source/library/Mapping.rst index 63f4fc9f8..f9f598f19 100644 --- a/docs/source/library/Mapping.rst +++ b/docs/source/library/Mapping.rst @@ -18,15 +18,15 @@ The following classes provide a more explicit way of initializing the respective .. currentmodule:: mqt.qmap .. autoclass:: Method - + .. autoclass:: Heuristic - + .. autoclass:: LookaheadHeuristic .. autoclass:: Layering .. autoclass:: InitialLayout - + .. autoclass:: EarlyTermination .. autoclass:: Encoding diff --git a/include/Architecture.hpp b/include/Architecture.hpp index 3153bac3d..b5ba189f2 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -249,11 +249,12 @@ class Architecture { return teleportationQubits; } - [[nodiscard]] const Matrix& getDistanceTable(bool includeReversalCost = true) const { + [[nodiscard]] const Matrix& + getDistanceTable(bool includeReversalCost = true) const { if (includeReversalCost) { return distanceTableReversals; } - return distanceTable; + return distanceTable; } [[nodiscard]] const Properties& getProperties() const { return properties; } @@ -387,7 +388,7 @@ class Architecture { } [[nodiscard]] bool bidirectional() const { return isBidirectional; } - + [[nodiscard]] bool unidirectional() const { return isUnidirectional; } [[nodiscard]] bool isArchitectureAvailable() const { @@ -403,7 +404,7 @@ class Architecture { couplingMap.clear(); distanceTable.clear(); distanceTableReversals.clear(); - isBidirectional = true; + isBidirectional = true; isUnidirectional = true; properties.clear(); fidelityAvailable = false; @@ -415,8 +416,7 @@ class Architecture { fidelityDistanceTables.clear(); } - [[nodiscard]] double distance(std::uint16_t control, - std::uint16_t target, + [[nodiscard]] double distance(std::uint16_t control, std::uint16_t target, bool includeReversalCost = true) const { if (currentTeleportations.empty()) { if (includeReversalCost) { @@ -489,14 +489,14 @@ class Architecture { static void printCouplingMap(const CouplingMap& cm, std::ostream& os); protected: - std::string name; - std::uint16_t nqubits = 0; - CouplingMap couplingMap = {}; - CouplingMap currentTeleportations = {}; - bool isBidirectional = true; - bool isUnidirectional = true; - Matrix distanceTable = {}; - Matrix distanceTableReversals = {}; + std::string name; + std::uint16_t nqubits = 0; + CouplingMap couplingMap = {}; + CouplingMap currentTeleportations = {}; + bool isBidirectional = true; + bool isUnidirectional = true; + Matrix distanceTable = {}; + Matrix distanceTableReversals = {}; std::vector> teleportationQubits{}; Properties properties = {}; bool fidelityAvailable = false; diff --git a/include/configuration/Heuristic.hpp b/include/configuration/Heuristic.hpp index 37efab2eb..7d6f54c60 100644 --- a/include/configuration/Heuristic.hpp +++ b/include/configuration/Heuristic.hpp @@ -48,7 +48,7 @@ enum class Heuristic { } /** - * A heuristic is non-decreasing if the estimated cost (i.e. c(n) + h(n)) is + * A heuristic is non-decreasing if the estimated cost (i.e. c(n) + h(n)) is * non-decreasing along any path. */ [[maybe_unused]] static inline bool isNonDecreasing(const Heuristic heuristic) { diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index f86bca530..9900066ea 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -50,24 +50,24 @@ class HeuristicMapper : public Mapper { */ std::array locations{}; /** current fixed cost - * + * * non-fidelity-aware: cost of all swaps used in the node - * - * fidelity-aware: fidelity cost of all swaps used in the node + fidelity + * + * fidelity-aware: fidelity cost of all swaps used in the node + fidelity * cost of all validly mapped gates at their current position */ double costFixed = 0.; - /** current fixed cost of reversals (only for non-fidelity-aware mapping + /** current fixed cost of reversals (only for non-fidelity-aware mapping * and only in goal nodes)*/ double costFixedReversals = 0.; - /** heuristic cost (i.e. expected difference from current cost to cost of + /** heuristic cost (i.e. expected difference from current cost to cost of * the best reachable goal node) */ double costHeur = 0.; /** heuristic cost expected for future swaps needed in later circuit layers * (further layers contribute less) */ double lookaheadPenalty = 0.; - /** number of swaps that were shared with another considered qubit such + /** number of swaps that were shared with another considered qubit such * that both qubits got closer to being validly mapped*/ std::size_t sharedSwaps = 0; /** depth in search tree (starting with 0 at the root) */ @@ -82,21 +82,21 @@ class HeuristicMapper : public Mapper { qubits.fill(DEFAULT_POSITION); locations.fill(DEFAULT_POSITION); }; - explicit Node(std::size_t nodeId) : id(nodeId){ + explicit Node(std::size_t nodeId) : id(nodeId) { qubits.fill(DEFAULT_POSITION); locations.fill(DEFAULT_POSITION); }; Node(std::size_t nodeId, std::size_t parentId, const std::array& q, const std::array& loc, - const std::vector& sw = {}, - const std::set& valid2QGates = {}, - const double initCostFixed = 0, - const double initCostFixedReversals = 0, - const std::size_t searchDepth = 0, - const std::size_t initSharedSwaps = 0) - : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), - depth(searchDepth), parent(parentId), id(nodeId), + const std::vector& sw = {}, + const std::set& valid2QGates = {}, + const double initCostFixed = 0, + const double initCostFixedReversals = 0, + const std::size_t searchDepth = 0, + const std::size_t initSharedSwaps = 0) + : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), + depth(searchDepth), parent(parentId), id(nodeId), sharedSwaps(initSharedSwaps) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); @@ -228,13 +228,15 @@ class HeuristicMapper : public Mapper { * @param reverse if true, the circuit is mapped from the end to the beginning */ virtual Node aStarMap(std::size_t layer, bool reverse); - + /** - * @brief Get all qubits that are acted on by a relevant gate in the given layer - * + * @brief Get all qubits that are acted on by a relevant gate in the given + * layer + * * @param layer the layer for which to get the considered qubits */ - const std::unordered_set& getConsideredQubits(std::size_t layer) const { + const std::unordered_set& + getConsideredQubits(std::size_t layer) const { if (fidelityAwareHeur) { return activeQubits.at(layer); } else { @@ -281,11 +283,11 @@ class HeuristicMapper : public Mapper { * @param node search node in which to apply the swap */ void applyTeleportation(const Edge& swap, std::size_t layer, Node& node); - + /** - * @brief increments `node.sharedSwaps` if the given swap is shared with + * @brief increments `node.sharedSwaps` if the given swap is shared with * another qubit such that both qubits get closer to being validly mapped - * + * * @param swap the swap to check * @param layer index of current circuit layer * @param node search node in which to update `sharedSwaps` @@ -319,7 +321,7 @@ class HeuristicMapper : public Mapper { void recalculateFixedCostNonFidelity(Node& node); /** - * @brief recalculates the gate-count-optimizing fixed cost of all reversals + * @brief recalculates the gate-count-optimizing fixed cost of all reversals * in the current mapping of a goal node or sets it to 0 otherwise * * @param layer index of current circuit layer @@ -506,7 +508,7 @@ inline bool operator>(const HeuristicMapper::Node& x, } inline bool operator==(const HeuristicMapper::Node& x, - const HeuristicMapper::Node& y) { + const HeuristicMapper::Node& y) { auto itx = x.qubits.begin(); // NOLINT (readability-qualified-auto) auto ity = y.qubits.begin(); // NOLINT (readability-qualified-auto) while (itx != x.qubits.end() && ity != y.qubits.end()) { diff --git a/include/utils.hpp b/include/utils.hpp index 0bf3ebf68..5623e7e2e 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -77,8 +77,8 @@ class Dijkstra { * e.g. in the case of fidelity-aware distances or distances on * mixed bi/unidirectional architectures) */ - static void buildTable(const CouplingMap& couplingMap, - Matrix& distanceTable, const Matrix& edgeWeights); + static void buildTable(const CouplingMap& couplingMap, Matrix& distanceTable, + const Matrix& edgeWeights); /** * @brief builds a 3d matrix containing the distance tables giving the minimal * distances between 2 qubit when upto k edges can be skipped. @@ -88,7 +88,7 @@ class Dijkstra { * * if k > edgeSkipDistanceTable.size() a cost of 0 can be assumed * - * @param distanceTable 2d matrix containing distances between any 2 qubits: + * @param distanceTable 2d matrix containing distances between any 2 qubits: * distanceTable[source][target] * @param couplingMap coupling map specifying all edges in the architecture * @param edgeSkipDistanceTable 3d target table @@ -100,29 +100,27 @@ class Dijkstra { * @brief builds a distance table containing the minimal costs for moving * logical qubits from one physical qubit to another (along the cheapest path) * while skipping a single edge, i.e. equivalent to buildEdgeSkipTable(...)[1] - * + * * An additional reversal cost can be specified, which is added to the cost if * the skipped edge is a back edge * - * @param distanceTable 2d matrix containing distances between any 2 qubits: + * @param distanceTable 2d matrix containing distances between any 2 qubits: * distanceTable[source][target] * @param couplingMap coupling map specifying all edges in the architecture * @param reversalCost cost for reversing an edge * @param edgeSkipDistanceTable target distance table */ - static void buildSingleEdgeSkipTable(const Matrix& distanceTable, - const CouplingMap& couplingMap, - const double reversalCost, - Matrix& edgeSkipDistanceTable); + static void buildSingleEdgeSkipTable(const Matrix& distanceTable, + const CouplingMap& couplingMap, + const double reversalCost, + Matrix& edgeSkipDistanceTable); protected: static void dijkstra(const CouplingMap& couplingMap, std::vector& nodes, std::uint16_t start, const Matrix& edgeWeights); struct NodeComparator { - bool operator()(const Node* x, const Node* y) { - return x->cost > y->cost; - } + bool operator()(const Node* x, const Node* y) { return x->cost > y->cost; } }; }; diff --git a/src/Architecture.cpp b/src/Architecture.cpp index 9ce0bc65d..ae137cf45 100644 --- a/src/Architecture.cpp +++ b/src/Architecture.cpp @@ -185,7 +185,7 @@ Architecture::Architecture(const std::uint16_t nQ, const CouplingMap& cm, } void Architecture::createDistanceTable() { - isBidirectional = true; + isBidirectional = true; isUnidirectional = true; Matrix edgeWeights(nqubits, std::vector( nqubits, std::numeric_limits::max())); @@ -201,14 +201,17 @@ void Architecture::createDistanceTable() { edgeWeights.at(edge.first).at(edge.second) = COST_BIDIRECTIONAL_SWAP; } } - + Matrix simpleDistanceTable{}; Dijkstra::buildTable(couplingMap, simpleDistanceTable, edgeWeights); - Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, 0., distanceTable); + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, 0., + distanceTable); if (bidirectional()) { distanceTableReversals = distanceTable; } else { - Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, COST_DIRECTION_REVERSE, distanceTableReversals); + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, couplingMap, + COST_DIRECTION_REVERSE, + distanceTableReversals); } } diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 863393005..4ce5bdfc5 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -15,13 +15,13 @@ void HeuristicMapper::map(const Configuration& configuration) { dataLogger = std::make_unique(configuration.dataLoggingPath, *architecture, qc); } - - tightHeur = isTight(configuration.heuristic); - fidelityAwareHeur = isFidelityAware(configuration.heuristic); - results = MappingResults{}; - results.config = configuration; - const auto& config = results.config; + tightHeur = isTight(configuration.heuristic); + fidelityAwareHeur = isFidelityAware(configuration.heuristic); + + results = MappingResults{}; + results.config = configuration; + const auto& config = results.config; if (config.layering == Layering::OddGates || config.layering == Layering::QubitTriangle) { throw QMAPException("Layering strategy " + toString(config.layering) + @@ -317,7 +317,7 @@ void HeuristicMapper::pseudoRouteCircuit(bool reverse) { config.debug = false; for (std::size_t i = 0; i < layers.size(); ++i) { - const auto layerIndex = (reverse ? layers.size() - i - 1 : i); + const auto layerIndex = (reverse ? layers.size() - i - 1 : i); const Node result = aStarMap(layerIndex, reverse); qubits = result.qubits; @@ -536,8 +536,8 @@ void HeuristicMapper::routeCircuit() { HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { const auto& config = results.config; - nextNodeId = 0; - + nextNodeId = 0; + const SingleQubitMultiplicity& singleQubitMultiplicity = singleQubitMultiplicities.at(layer); const TwoQubitMultiplicity& twoQubitMultiplicity = @@ -555,7 +555,8 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { updateLookaheadPenalty(layer, node); if (config.dataLoggingEnabled()) { - dataLogger->logSearchNode(layer, node.id, node.parent, node.costFixed + node.costFixedReversals, + dataLogger->logSearchNode(layer, node.id, node.parent, + node.costFixed + node.costFixedReversals, node.costHeur, node.lookaheadPenalty, node.qubits, node.validMapping, node.swaps, node.depth); } @@ -711,7 +712,7 @@ HeuristicMapper::Node HeuristicMapper::aStarMap(size_t layer, bool reverse) { } void HeuristicMapper::expandNode(Node& node, std::size_t layer) { - const auto& consideredQubits = getConsideredQubits(layer); + const auto& consideredQubits = getConsideredQubits(layer); std::vector> usedSwaps; usedSwaps.reserve(architecture->getNqubits()); for (int p = 0; p < architecture->getNqubits(); ++p) { @@ -788,7 +789,7 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, const std::size_t layer) { Node newNode = Node(nextNodeId++, node.id, node.qubits, node.locations, node.swaps, - node.validMappedTwoQubitGates, node.costFixed, + node.validMappedTwoQubitGates, node.costFixed, node.costFixedReversals, node.depth + 1, node.sharedSwaps); if (architecture->isEdgeConnected(swap) || @@ -800,10 +801,11 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, nodes.push(newNode); if (results.config.dataLoggingEnabled()) { - dataLogger->logSearchNode( - layer, newNode.id, newNode.parent, newNode.costFixed + newNode.costFixedReversals, newNode.costHeur, - newNode.lookaheadPenalty, newNode.qubits, newNode.validMapping, - newNode.swaps, newNode.depth); + dataLogger->logSearchNode(layer, newNode.id, newNode.parent, + newNode.costFixed + newNode.costFixedReversals, + newNode.costHeur, newNode.lookaheadPenalty, + newNode.qubits, newNode.validMapping, + newNode.swaps, newNode.depth); } } @@ -811,8 +813,8 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { node.validMappedTwoQubitGates.clear(); for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { const auto [q1, q2] = edge; - const auto physQ1 = static_cast(node.locations.at(q1)); - const auto physQ2 = static_cast(node.locations.at(q2)); + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); if (architecture->isEdgeConnected({physQ1, physQ2}) || architecture->isEdgeConnected({physQ2, physQ1})) { // validly mapped @@ -828,16 +830,18 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { recalculateFixedCostReversals(layer, node); } -void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, Node& node) { +void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, + Node& node) { node.costFixedReversals = 0.; - if (!fidelityAwareHeur && node.validMappedTwoQubitGates.size() == twoQubitMultiplicities.at(layer).size()) { + if (!fidelityAwareHeur && node.validMappedTwoQubitGates.size() == + twoQubitMultiplicities.at(layer).size()) { // only consider reversal costs as fixed in goal nodes for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q1, q2] = edge; + const auto [q1, q2] = edge; const auto [forwardMult, reverseMult] = mult; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - + if (!architecture->isEdgeConnected({physQ1, physQ2})) { node.costFixedReversals += forwardMult * COST_DIRECTION_REVERSE; } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { @@ -849,7 +853,7 @@ void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, Node& nod void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { node.costFixed = 0; - + // swap costs for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { @@ -913,7 +917,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); - + updateSharedSwaps(swap, layer, node); node.qubits.at(swap.first) = q2; @@ -937,7 +941,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q3, q4] = edge; + const auto [q3, q4] = edge; const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); @@ -945,20 +949,21 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || architecture->isEdgeConnected(Edge{physQ4, physQ3})) { // validly mapped now - if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == node.validMappedTwoQubitGates.end()) { + if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == + node.validMappedTwoQubitGates.end()) { // not mapped validly before // add cost of newly validly mapped gates node.costFixed += - mult.first * - architecture->getTwoQubitFidelityCost(physQ3, physQ4) + - mult.second * - architecture->getTwoQubitFidelityCost(physQ4, physQ3); + mult.first * + architecture->getTwoQubitFidelityCost(physQ3, physQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(physQ4, physQ3); } node.validMappedTwoQubitGates.emplace(edge); } else { // not mapped validly now if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { + node.validMappedTwoQubitGates.end()) { // mapped validly before // remove cost of now no longer validly mapped gates auto prevPhysQ3 = physQ3; @@ -973,12 +978,12 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else if (prevPhysQ4 == swap.second) { prevPhysQ4 = swap.first; } - + node.costFixed -= - mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, - prevPhysQ4) + - mult.second * - architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); + mult.first * architecture->getTwoQubitFidelityCost(prevPhysQ3, + prevPhysQ4) + + mult.second * + architecture->getTwoQubitFidelityCost(prevPhysQ4, prevPhysQ3); } node.validMappedTwoQubitGates.erase(edge); } @@ -1011,7 +1016,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.costFixed += COST_UNIDIRECTIONAL_SWAP; } } - + recalculateFixedCostReversals(layer, node); updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { @@ -1023,7 +1028,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, Node& node) { const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); - + updateSharedSwaps(swap, layer, node); node.qubits.at(swap.first) = q2; @@ -1077,7 +1082,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q3, q4] = edge; + const auto [q3, q4] = edge; const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); @@ -1092,7 +1097,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, } } } - + recalculateFixedCostReversals(layer, node); updateHeuristicCost(layer, node); if (results.config.lookaheadHeuristic != LookaheadHeuristic::None) { @@ -1101,13 +1106,13 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, } void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, - Node& node) { - const auto& consideredQubits = getConsideredQubits(layer); - const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - + Node& node) { + const auto& consideredQubits = getConsideredQubits(layer); + const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); + const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); - + if (consideredQubits.find(q1) != consideredQubits.end() && consideredQubits.find(q2) != consideredQubits.end()) { // TODO: handle single qubit gates for fidelity aware heuristic @@ -1125,53 +1130,61 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, logEdge2.second = edge.first; } } - if (// if both swapped qubits are acted on by a 2q gate - logEdge1.second != q1 && logEdge2.second != q2 && - // if it is not the same 2q gate acting on both qubits - logEdge1.second != q2) { - double logEdge1DistanceBefore; - double logEdge1DistanceNew; - double logEdge2DistanceBefore; - double logEdge2DistanceNew; - if (fidelityAwareHeur) { - logEdge1DistanceBefore = std::min( - architecture->fidelityDistance(swap.first, node.locations[logEdge1.second]), - architecture->fidelityDistance(node.locations[logEdge1.second], swap.first) - ); - logEdge1DistanceNew = std::min( - architecture->fidelityDistance(swap.second, node.locations[logEdge1.second]), - architecture->fidelityDistance(node.locations[logEdge1.second], swap.second) - ); - logEdge2DistanceBefore = std::min( - architecture->fidelityDistance(swap.second, node.locations[logEdge2.second]), - architecture->fidelityDistance(node.locations[logEdge2.second], swap.second) - ); - logEdge2DistanceNew = std::min( - architecture->fidelityDistance(swap.first, node.locations[logEdge2.second]), - architecture->fidelityDistance(node.locations[logEdge2.second], swap.first) - ); - } else { - logEdge1DistanceBefore = std::min( - architecture->distance(swap.first, node.locations[logEdge1.second], false), - architecture->distance(node.locations[logEdge1.second], swap.first, false) - ); - logEdge1DistanceNew = std::min( - architecture->distance(swap.second, node.locations[logEdge1.second], false), - architecture->distance(node.locations[logEdge1.second], swap.second, false) - ); - logEdge2DistanceBefore = std::min( - architecture->distance(swap.second, node.locations[logEdge2.second], false), - architecture->distance(node.locations[logEdge2.second], swap.second, false) - ); - logEdge2DistanceNew = std::min( - architecture->distance(swap.first, node.locations[logEdge2.second], false), - architecture->distance(node.locations[logEdge2.second], swap.first, false) - ); - } - if (logEdge1DistanceNew < logEdge1DistanceBefore && - logEdge2DistanceNew < logEdge2DistanceBefore) { - ++node.sharedSwaps; - } + if ( // if both swapped qubits are acted on by a 2q gate + logEdge1.second != q1 && logEdge2.second != q2 && + // if it is not the same 2q gate acting on both qubits + logEdge1.second != q2) { + double logEdge1DistanceBefore; + double logEdge1DistanceNew; + double logEdge2DistanceBefore; + double logEdge2DistanceNew; + if (fidelityAwareHeur) { + logEdge1DistanceBefore = + std::min(architecture->fidelityDistance( + swap.first, node.locations[logEdge1.second]), + architecture->fidelityDistance( + node.locations[logEdge1.second], swap.first)); + logEdge1DistanceNew = + std::min(architecture->fidelityDistance( + swap.second, node.locations[logEdge1.second]), + architecture->fidelityDistance( + node.locations[logEdge1.second], swap.second)); + logEdge2DistanceBefore = + std::min(architecture->fidelityDistance( + swap.second, node.locations[logEdge2.second]), + architecture->fidelityDistance( + node.locations[logEdge2.second], swap.second)); + logEdge2DistanceNew = + std::min(architecture->fidelityDistance( + swap.first, node.locations[logEdge2.second]), + architecture->fidelityDistance( + node.locations[logEdge2.second], swap.first)); + } else { + logEdge1DistanceBefore = + std::min(architecture->distance( + swap.first, node.locations[logEdge1.second], false), + architecture->distance(node.locations[logEdge1.second], + swap.first, false)); + logEdge1DistanceNew = + std::min(architecture->distance( + swap.second, node.locations[logEdge1.second], false), + architecture->distance(node.locations[logEdge1.second], + swap.second, false)); + logEdge2DistanceBefore = + std::min(architecture->distance( + swap.second, node.locations[logEdge2.second], false), + architecture->distance(node.locations[logEdge2.second], + swap.second, false)); + logEdge2DistanceNew = + std::min(architecture->distance( + swap.first, node.locations[logEdge2.second], false), + architecture->distance(node.locations[logEdge2.second], + swap.first, false)); + } + if (logEdge1DistanceNew < logEdge1DistanceBefore && + logEdge2DistanceNew < logEdge2DistanceBefore) { + ++node.sharedSwaps; + } } } } @@ -1211,18 +1224,22 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; + const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - + if (node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates if (!architecture->isEdgeConnected({physQ1, physQ2})) { - costHeur = std::max(costHeur, static_cast(forwardMult * COST_DIRECTION_REVERSE)); + costHeur = + std::max(costHeur, + static_cast(forwardMult * COST_DIRECTION_REVERSE)); } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { - costHeur = std::max(costHeur, static_cast(reverseMult * COST_DIRECTION_REVERSE)); + costHeur = + std::max(costHeur, + static_cast(reverseMult * COST_DIRECTION_REVERSE)); } } else { // not validly mapped 2-qubit-gates @@ -1246,11 +1263,11 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, double costHeur = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; + const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - + if (node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates @@ -1262,7 +1279,7 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, } else { // not validly mapped 2-qubit-gates double swapCost = 0.; - + if (forwardMult == 0) { // forwardMult == 0 && reverseMult > 0 swapCost = architecture->distance(physQ2, physQ1); @@ -1287,29 +1304,30 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( return 0.; } const auto& twoQubitGateMultiplicity = twoQubitMultiplicities.at(layer); - double costHeur = 0.; - double costReversals = 0.; + double costHeur = 0.; + double costReversals = 0.; std::vector nSwaps{}; nSwaps.reserve(twoQubitGateMultiplicity.size()); - + for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { - const auto& [q1, q2] = edge; + const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - + if (architecture->unidirectional()) { - // only for purely unidirectional architectures is it certain that at + // only for purely unidirectional architectures is it certain that at // least one of the two directions has to be reversed - costReversals += std::min(forwardMult, reverseMult) * COST_DIRECTION_REVERSE; + costReversals += + std::min(forwardMult, reverseMult) * COST_DIRECTION_REVERSE; } - + if (node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates continue; } - + double swapCost = 0.; if (forwardMult == 0) { // forwardMult == 0 && reverseMult > 0 @@ -1323,23 +1341,27 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( architecture->distance(physQ2, physQ1, false)); } costHeur += swapCost; - + // infer maximum number of swaps in this distance if (architecture->unidirectional()) { - nSwaps.emplace_back(static_cast(swapCost / COST_UNIDIRECTIONAL_SWAP)); + nSwaps.emplace_back( + static_cast(swapCost / COST_UNIDIRECTIONAL_SWAP)); } else { - nSwaps.emplace_back(static_cast(swapCost / COST_BIDIRECTIONAL_SWAP)); + nSwaps.emplace_back( + static_cast(swapCost / COST_BIDIRECTIONAL_SWAP)); } } - + // sort number of swaps in descending order std::sort(nSwaps.begin(), nSwaps.end(), std::greater()); - + // infer maximum number of shared swaps std::size_t maxSharedSwaps = 0; - for (std::size_t i = 0; i < nSwaps.size()-1; ++i) { - std::size_t maxSharedSwapsEdge = 0; // maximum number of shared swaps for this edge - for (std::size_t j = i + 1; j < nSwaps.size() && maxSharedSwapsEdge < nSwaps[i]; ++j) { + for (std::size_t i = 0; i < nSwaps.size() - 1; ++i) { + std::size_t maxSharedSwapsEdge = + 0; // maximum number of shared swaps for this edge + for (std::size_t j = i + 1; + j < nSwaps.size() && maxSharedSwapsEdge < nSwaps[i]; ++j) { if (nSwaps[j] > 0) { ++maxSharedSwapsEdge; --nSwaps[j]; @@ -1352,12 +1374,14 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( } else { maxSharedSwaps = 0; } - - double sharedSwapCostReduction = 0; + + double sharedSwapCostReduction = 0; if (architecture->bidirectional()) { - sharedSwapCostReduction = static_cast(maxSharedSwaps * COST_BIDIRECTIONAL_SWAP); + sharedSwapCostReduction = + static_cast(maxSharedSwaps * COST_BIDIRECTIONAL_SWAP); } else { - sharedSwapCostReduction = static_cast(maxSharedSwaps * COST_UNIDIRECTIONAL_SWAP); + sharedSwapCostReduction = + static_cast(maxSharedSwaps * COST_UNIDIRECTIONAL_SWAP); } return std::max(0., costHeur - sharedSwapCostReduction) + costReversals; @@ -1366,11 +1390,8 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( double HeuristicMapper::heuristicGateCountMaxDistanceOrSumDistanceMinusSharedSwaps( std::size_t layer, Node& node) { - - return std::max( - heuristicGateCountMaxDistance(layer, node), - heuristicGateCountSumDistanceMinusSharedSwaps(layer, node) - ); + return std::max(heuristicGateCountMaxDistance(layer, node), + heuristicGateCountSumDistanceMinusSharedSwaps(layer, node)); } double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, @@ -1530,9 +1551,9 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, } penalty = std::max(penalty, min); } else { - const auto cost = architecture->distance(static_cast(loc1), - static_cast(loc2)); - penalty = std::max(penalty, cost); + const auto cost = architecture->distance( + static_cast(loc1), static_cast(loc2)); + penalty = std::max(penalty, cost); } } @@ -1572,9 +1593,9 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, } penalty = min; } else { - const auto cost = architecture->distance(static_cast(loc1), - static_cast(loc2)); - penalty = cost; + const auto cost = architecture->distance( + static_cast(loc1), static_cast(loc2)); + penalty = cost; } } diff --git a/src/utils.cpp b/src/utils.cpp index a71de95e1..2bbdf4c26 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -7,22 +7,22 @@ #include -void Dijkstra::buildTable(const CouplingMap& couplingMap, - Matrix& distanceTable, const Matrix& edgeWeights) { +void Dijkstra::buildTable(const CouplingMap& couplingMap, Matrix& distanceTable, + const Matrix& edgeWeights) { const std::uint16_t n = edgeWeights.size(); // number of qubits - + distanceTable.clear(); distanceTable.resize(n, std::vector(n, -1.)); for (std::uint16_t i = 0; i < n; ++i) { std::vector nodes(n); for (std::uint16_t j = 0; j < n; ++j) { - nodes.at(j).visited = false; - nodes.at(j).pos = j; - nodes.at(j).cost = -1.; + nodes.at(j).visited = false; + nodes.at(j).pos = j; + nodes.at(j).cost = -1.; } - nodes.at(i).cost = 0; + nodes.at(i).cost = 0; dijkstra(couplingMap, nodes, i, edgeWeights); @@ -60,8 +60,8 @@ void Dijkstra::dijkstra(const CouplingMap& couplingMap, } Node newNode; - newNode.cost = current->cost + edgeWeights.at(*pos).at(*to); - newNode.pos = to; + newNode.cost = current->cost + edgeWeights.at(*pos).at(*to); + newNode.pos = to; if (nodes.at(*to).cost < 0 || newNode < nodes.at(*to)) { nodes.at(*to) = newNode; queue.push(&nodes.at(*to)); @@ -126,17 +126,18 @@ void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, } } -void Dijkstra::buildSingleEdgeSkipTable(const Matrix& distanceTable, - const CouplingMap& couplingMap, - const double reversalCost, +void Dijkstra::buildSingleEdgeSkipTable(const Matrix& distanceTable, + const CouplingMap& couplingMap, + const double reversalCost, Matrix& edgeSkipDistanceTable) { const std::size_t n = distanceTable.size(); edgeSkipDistanceTable.clear(); - edgeSkipDistanceTable.resize(n, std::vector(n, std::numeric_limits::max())); + edgeSkipDistanceTable.resize( + n, std::vector(n, std::numeric_limits::max())); for (std::size_t q = 0; q < n; ++q) { edgeSkipDistanceTable.at(q).at(q) = 0.; } - for (const auto& [e1, e2] : couplingMap) { // edge to be skipped + for (const auto& [e1, e2] : couplingMap) { // edge to be skipped for (std::size_t q1 = 0; q1 < n; ++q1) { // q1 ... source qubit for (std::size_t q2 = q1 + 1; q2 < n; ++q2) { // q2 ... target qubit edgeSkipDistanceTable.at(q1).at(q2) = @@ -144,18 +145,20 @@ void Dijkstra::buildSingleEdgeSkipTable(const Matrix& distanceTable, distanceTable.at(q1).at(e1) + distanceTable.at(e2).at(q2)); edgeSkipDistanceTable.at(q1).at(q2) = std::min(edgeSkipDistanceTable.at(q1).at(q2), - distanceTable.at(q1).at(e2) + distanceTable.at(e1).at(q2) + reversalCost); + distanceTable.at(q1).at(e2) + distanceTable.at(e1).at(q2) + + reversalCost); if (reversalCost == 0.) { - edgeSkipDistanceTable.at(q2).at(q1) = edgeSkipDistanceTable.at(q1).at(q2); - } else { edgeSkipDistanceTable.at(q2).at(q1) = - std::min(edgeSkipDistanceTable.at(q2).at(q1), - distanceTable.at(q2).at(e1) + distanceTable.at(e2).at(q1)); + edgeSkipDistanceTable.at(q1).at(q2); + } else { + edgeSkipDistanceTable.at(q2).at(q1) = std::min( + edgeSkipDistanceTable.at(q2).at(q1), + distanceTable.at(q2).at(e1) + distanceTable.at(e2).at(q1)); edgeSkipDistanceTable.at(q2).at(q1) = std::min(edgeSkipDistanceTable.at(q2).at(q1), - distanceTable.at(q2).at(e2) + distanceTable.at(e1).at(q1) + reversalCost); + distanceTable.at(q2).at(e2) + + distanceTable.at(e1).at(q1) + reversalCost); } - } } } diff --git a/test/test_general.cpp b/test/test_general.cpp index 9cbc7c1b2..05deb84c6 100644 --- a/test/test_general.cpp +++ b/test/test_general.cpp @@ -88,10 +88,11 @@ TEST(General, DijkstraCNOTReversal) { {0, 3, 0, 3, 0}, {0, 0, 3, 0, 3}, {0, 0, 0, 3, 0}}; - Matrix simpleDistanceTable{}; + Matrix simpleDistanceTable{}; Dijkstra::buildTable(cm, simpleDistanceTable, edgeWeights); Matrix distanceTable{}; - Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, cm, 1., distanceTable); + Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, cm, 1., + distanceTable); const Matrix targetTable2 = {{0, 0, 3, 6, 9}, {1, 0, 1, 3, 6}, diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index fe30bd4b9..f1a62febe 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -7,12 +7,12 @@ #include "nlohmann/json.hpp" #include "gtest/gtest.h" -#include #include #include #include #include #include +#include constexpr qc::OpType SWAP = qc::OpType::SWAP; @@ -52,7 +52,7 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, if (!layerNodeFile.is_open()) { throw std::runtime_error("Could not open file " + layerNodeFilePath); } - // iterating over the lines in the csv file and then over the entries + // iterating over the lines in the csv file and then over the entries // separated by ';' std::string line; while (std::getline(layerNodeFile, line)) { @@ -61,8 +61,8 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, } std::string col; std::size_t nodeId = 0; - - std::stringstream lineStream(line); + + std::stringstream lineStream(line); if (std::getline(lineStream, col, ';')) { nodeId = std::stoull(col); if (nodeId >= nodes.size()) { @@ -167,7 +167,8 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { auto node = &nodes[nodeId]; while (node->parent != node->id) { path.push_back(node->id); - if (node->parent >= nodes.size() || nodes[node->parent].id != node->parent) { + if (node->parent >= nodes.size() || + nodes[node->parent].id != node->parent) { throw std::runtime_error("Invalid parent id " + std::to_string(node->parent) + " for node " + std::to_string(node->id)); @@ -181,9 +182,8 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { class InternalsTest : public HeuristicMapper, public testing::Test { protected: static Architecture defaultArch; - - InternalsTest() - : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} + + InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } }; @@ -195,7 +195,7 @@ TEST_F(InternalsTest, NodeCostCalculation) { results.config.heuristic = Heuristic::GateCountMaxDistance; results.config.lookaheadHeuristic = LookaheadHeuristic::None; results.config.layering = Layering::Disjoint2qBlocks; - + architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); qc = qc::QuantumComputation{5}; qc.cx(qc::Control{0}, 1); @@ -287,498 +287,822 @@ class TestHeuristics std::unique_ptr ibmQX5Mapper; Configuration settings{}; const double tolerance = 1e-6; - - static std::unordered_map> optimalSolutions; - + + static std::unordered_map> + optimalSolutions; + static void SetUpTestSuite() { // prepare precalculated optimal solutions to compare against optimalSolutions = { - {"3_17_13", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,0,SWAP}}, {}, 0., 0., 1} - }}, - {"ex-1_166", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1} - }}, - {"ham3_102", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0} - }}, - {"miller_11", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0} - }}, - {"4gt11_84", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0,1,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1} - }}, - {"4mod5-v0_20", { - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP},{3,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0} - }}, - {"mod5d1_63", { - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP},{1,3,SWAP},{0,1,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,0,SWAP},{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 3} - }}, - {"ising_model_10", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0} - }}, - {"rd73_140", { - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP},{2,3,SWAP},{3,4,SWAP},{5,4,SWAP},{6,7,SWAP}}, {}, 0., 0., 5}, - {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{2,3,SWAP},{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 5}, - {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{5,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP},{1,2,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{8,7,SWAP},{6,7,SWAP},{6,5,SWAP},{1,2,SWAP},{2,3,SWAP},{3,4,SWAP}}, {}, 0., 0., 6}, - {0, 0, {}, {}, {{1,0,SWAP},{1,2,SWAP},{5,4,SWAP},{3,4,SWAP}}, {}, 0., 0., 4}, - {0, 0, {}, {}, {{2,3,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{9,10,SWAP},{11,10,SWAP},{12,11,SWAP},{12,5,SWAP},{5,4,SWAP},{3,4,SWAP},{2,3,SWAP},{5,4,SWAP}}, {}, 0., 0., 8}, - {0, 0, {}, {}, {{1,0,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{6,5,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{6,5,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1,0,SWAP},{6,5,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3,4,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3,4,SWAP},{15,2,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{5,4,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{5,4,SWAP},{15,0,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP},{5,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3,4,SWAP},{15,0,SWAP},{15,14,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,14,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{6,7,SWAP},{6,5,SWAP},{5,4,SWAP},{3,4,SWAP},{15,0,SWAP}}, {}, 0., 0., 5}, - {0, 0, {}, {}, {{6,5,SWAP},{5,4,SWAP},{15,0,SWAP},{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 5}, - {0, 0, {}, {}, {{1,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2,3,SWAP},{15,2,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{15,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,3,SWAP},{1,2,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{1,2,SWAP},{2,3,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15,2,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{8,7,SWAP},{6,7,SWAP},{6,5,SWAP},{5,4,SWAP},{3,4,SWAP},{1,0,SWAP}}, {}, 0., 0., 6}, - {0, 0, {}, {}, {{15,0,SWAP},{15,14,SWAP},{13,14,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{13,14,SWAP},{2,3,SWAP},{15,0,SWAP}}, {}, 0., 0., 3}, - {0, 0, {}, {}, {{15,14,SWAP},{13,4,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2,3,SWAP},{15,14,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2,3,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15,14,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2,3,SWAP},{3,14,SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13,14,SWAP}}, {}, 0., 0., 1} - }} - }; - const std::unordered_map>> optimalSolutionQubits{ - {"3_17_13", { - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, - {2,1,0}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, {2,0,1}, {2,0,1}, {2,1,0}, - {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, - {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {2,1,0}, {2,1,0}, - {2,1,0}, {2,1,0}, {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, - {2,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, - {0,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, - {0,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, - {0,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2}, - {2,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} - }}, - {"ex-1_166", { - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, - {2,1,0}, {2,1,0}, {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {0,1,2}, {1,0,2}, - {1,0,2}, {1,2,0}, {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} - }}, - {"ham3_102", { - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {0,1,2}, {1,0,2}, {1,0,2}, {1,2,0}, {1,2,0}, {2,1,0}, {2,1,0}, - {2,0,1}, {2,1,0}, {0,1,2}, {1,0,2}, {1,0,2}, {0,1,2}, {1,0,2}, {1,0,2}, - {1,2,0}, {1,2,0}, {1,2,0} - }}, - {"miller_11", { - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, - {0,1,2}, {1,0,2}, {1,2,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,1,0}, - {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,0,1}, - {2,1,0}, {2,1,0}, {2,0,1}, {2,1,0}, {2,1,0}, {2,1,0}, {0,1,2}, {0,1,2}, - {0,2,1}, {0,2,1}, {0,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, - {0,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, - {2,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}, {2,0,1}, {2,1,0}, - {2,1,0}, {1,2,0}, {1,2,0}, - {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {1,2,0}, {1,2,0}, - {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, {1,2,0}, {1,2,0}, - {2,1,0}, {1,2,0}, {1,2,0}, - {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0}, - {1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0} - }}, - {"4gt11_84", { - {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, - {0,1,2,-1,4}, {2,1,0,3,4}, {0,1,2,-1,4}, {0,1,2,-1,4}, {1,0,2,-1,4}, - {1,2,0,-1,4}, {2,1,0,-1,4}, {2,0,1,-1,4}, {4,2,1,0,3}, {0,1,2,-1,4}, - {0,1,2,-1,4}, {0,2,1,-1,4}, {0,2,1,-1,4}, {2,0,1,-1,4}, {2,0,1,-1,4}, - {2,1,0,3,4} - }}, - {"4mod5-v0_20", { - {0,2,1,3,4}, {0,2,1,3,4}, {0,2,1,3,4}, {0,2,4,3,1}, {0,4,2,3,1}, - {0,4,1,3,2}, {0,4,2,3,1}, {0,4,2,3,1}, {4,0,2,1,3}, {4,2,0,1,3}, - {4,1,0,2,3}, {4,2,0,1,3}, {4,2,0,1,3}, {4,1,0,2,3}, {4,2,0,1,3}, - {4,2,0,1,3}, {0,2,1,3,4}, {0,2,1,3,4}, {0,2,3,1,4}, {0,3,2,4,1}, - {0,3,4,2,1}, {0,3,4,1,2}, {0,3,4,2,1}, {0,3,4,2,1} - }}, - {"mod5d1_63", { - {0,2,1,3,4}, {0,2,1,3,4}, {1,2,0,3,4}, {1,2,0,3,4}, {1,2,0,3,4}, - {1,2,4,3,0}, {4,2,1,3,0}, {4,2,0,3,1}, {4,2,1,3,0}, {4,2,1,3,0}, - {4,2,0,3,1}, {4,0,2,1,3}, {4,1,2,0,3}, {4,0,2,1,3}, {4,0,2,1,3}, - {4,0,2,1,3}, {4,1,2,0,3}, {4,1,2,0,3}, {4,0,2,1,3}, {4,1,2,0,3}, - {4,1,2,0,3}, {4,0,2,1,3}, {0,2,1,3,4}, {0,2,3,1,4}, {2,3,1,0,4}, - {2,3,1,0,4}, {2,3,1,0,4}, {2,3,1,4,0}, {2,3,4,1,0}, {2,3,4,0,1}, - {2,3,4,1,0}, {2,3,4,1,0}, {-1,3,1,2,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4} - }}, - {"ising_model_10", { - {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, - {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, - {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, {0,1,2,3,4,5,6,7,8,9}, - {0,1,2,3,4,5,6,7,8,9} - }}, - {"rd73_140", { - {0,1,2,3,4,5,6,7,8,9}, {0,2,3,4,5,1,7,6,8,9}, {2,3,4,0,7,5,1,6,8,9}, - {2,3,4,0,1,7,5,6,8,9}, {2,3,4,0,1,7,5,6,8,9}, {2,3,4,0,7,1,5,6,8,9}, - {2,7,3,4,0,1,5,6,8,9}, {2,3,4,0,7,8,1,5,6,9}, {3,4,2,8,0,7,1,5,6,9}, - {3,4,8,2,7,0,1,5,6,9}, {3,4,8,7,2,0,1,5,6,9}, {3,4,8,2,7,0,1,5,6,9}, - {3,8,4,2,7,0,1,5,6,9}, {3,8,9,4,7,2,1,5,6,-1,-1,-1,0}, - {8,3,9,4,7,2,1,5,6,-1,-1,-1,0}, {8,3,9,4,7,1,2,5,6,-1,-1,-1,0}, - {8,9,3,4,7,1,2,5,6,-1,-1,-1,0}, {8,9,3,4,7,2,1,5,6,-1,-1,-1,0}, - {9,8,3,4,7,1,2,5,6,-1,-1,-1,0}, {9,8,4,3,7,1,2,5,6,-1,-1,-1,0}, - {9,8,7,4,3,1,2,5,6,-1,-1,-1,0}, {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, - {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, {9,8,7,3,4,1,2,5,6,-1,-1,-1,0}, - {9,8,3,7,4,1,2,5,6,-1,-1,-1,0}, {9,8,4,3,7,1,2,5,6,-1,-1,-1,0}, - {9,8,4,3,2,7,1,5,6,-1,-1,-1,0}, - {9,8,-1,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,4}, - {9,-1,8,2,7,3,1,5,6,-1,-1,-1,0,-1,-1,4}, - {4,-1,8,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,9}, - {4,-1,8,2,3,7,1,5,6,-1,-1,-1,0,-1,-1,9}, - {4,8,-1,2,7,3,1,5,6,-1,-1,-1,0,-1,-1,9}, - {9,8,-1,7,2,3,1,5,6,-1,-1,-1,0,-1,4}, - {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,4}, - {9,7,8,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, - {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, - {9,8,7,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, - {9,7,8,-1,2,3,1,5,6,-1,-1,-1,0,-1,-1,4}, - {4,7,8,5,-1,2,3,1,6,-1,-1,-1,0,-1,-1,9}, - {9,7,5,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,8,7,3,-1,2,1,6,-1,-1,-1,0,-1,-1,4}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,4,5,7,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,8,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,7}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,7,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,8}, - {9,5,8,4,3,-1,2,1,6,-1,-1,-1,0,-1,-1,7}, - {5,9,8,6,4,3,-1,2,1,-1,-1,-1,0,-1,-1,7}, - {7,9,8,6,4,3,-1,2,1,-1,-1,-1,0,5}, - {-1,9,6,8,4,3,-1,2,1,-1,-1,-1,0,-1,5,7}, - {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,7,5}, - {-1,9,8,6,-1,3,-1,2,1,-1,-1,-1,0,4,5,7}, - {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,5,7}, - {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,4,7,5}, - {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,7,4,5}, - {-1,9,6,8,-1,3,-1,2,1,-1,-1,-1,0,7,4,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,6,7,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,6,7,5}, - {-1,9,8,4,-1,3,-1,2,1,-1,-1,-1,0,7,6,5} - }} - }; + {"3_17_13", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 0, SWAP}}, {}, 0., 0., 1}}}, + {"ex-1_166", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}}}, + {"ham3_102", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, + {"miller_11", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, + {"4gt11_84", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}}}, + {"4mod5-v0_20", + {{0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, + 0, + {}, + {}, + {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}, {3, 4, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, + {"mod5d1_63", + {{0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{1, 0, SWAP}, {1, 2, SWAP}, {2, 3, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, + 0, + {}, + {}, + {{15, 0, SWAP}, {15, 2, SWAP}, {2, 3, SWAP}}, + {}, + 0., + 0., + 3}}}, + {"ising_model_10", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, + {"rd73_140", + {{0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, + 0, + {}, + {}, + {{1, 2, SWAP}, + {2, 3, SWAP}, + {3, 4, SWAP}, + {5, 4, SWAP}, + {6, 7, SWAP}}, + {}, + 0., + 0., + 5}, + {0, + 0, + {}, + {}, + {{1, 0, SWAP}, + {1, 2, SWAP}, + {2, 3, SWAP}, + {6, 5, SWAP}, + {5, 4, SWAP}}, + {}, + 0., + 0., + 5}, + {0, 0, {}, {}, {{6, 5, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{5, 4, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{3, 4, SWAP}, {2, 3, SWAP}, {1, 2, SWAP}}, + {}, + 0., + 0., + 3}, + {0, + 0, + {}, + {}, + {{8, 7, SWAP}, + {6, 7, SWAP}, + {6, 5, SWAP}, + {1, 2, SWAP}, + {2, 3, SWAP}, + {3, 4, SWAP}}, + {}, + 0., + 0., + 6}, + {0, + 0, + {}, + {}, + {{1, 0, SWAP}, {1, 2, SWAP}, {5, 4, SWAP}, {3, 4, SWAP}}, + {}, + 0., + 0., + 4}, + {0, 0, {}, {}, {{2, 3, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{9, 10, SWAP}, + {11, 10, SWAP}, + {12, 11, SWAP}, + {12, 5, SWAP}, + {5, 4, SWAP}, + {3, 4, SWAP}, + {2, 3, SWAP}, + {5, 4, SWAP}}, + {}, + 0., + 0., + 8}, + {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{6, 5, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{6, 5, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{1, 0, SWAP}, {6, 5, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{6, 5, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{3, 4, SWAP}, {15, 2, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{5, 4, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{5, 4, SWAP}, {15, 0, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, + {0, + 0, + {}, + {}, + {{3, 4, SWAP}, {15, 0, SWAP}, {15, 14, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 14, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{6, 7, SWAP}, + {6, 5, SWAP}, + {5, 4, SWAP}, + {3, 4, SWAP}, + {15, 0, SWAP}}, + {}, + 0., + 0., + 5}, + {0, + 0, + {}, + {}, + {{6, 5, SWAP}, + {5, 4, SWAP}, + {15, 0, SWAP}, + {15, 2, SWAP}, + {2, 3, SWAP}}, + {}, + 0., + 0., + 5}, + {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{2, 3, SWAP}, {15, 2, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{15, 2, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 3, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{1, 2, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, + {0, + 0, + {}, + {}, + {{8, 7, SWAP}, + {6, 7, SWAP}, + {6, 5, SWAP}, + {5, 4, SWAP}, + {3, 4, SWAP}, + {1, 0, SWAP}}, + {}, + 0., + 0., + 6}, + {0, + 0, + {}, + {}, + {{15, 0, SWAP}, {15, 14, SWAP}, {13, 14, SWAP}}, + {}, + 0., + 0., + 3}, + {0, + 0, + {}, + {}, + {{13, 14, SWAP}, {2, 3, SWAP}, {15, 0, SWAP}}, + {}, + 0., + 0., + 3}, + {0, 0, {}, {}, {{15, 14, SWAP}, {13, 4, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2, 3, SWAP}, {15, 14, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{15, 14, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{2, 3, SWAP}, {3, 14, SWAP}}, {}, 0., 0., 2}, + {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {}, {}, 0., 0., 0}, + {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, + {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}}}}; + const std::unordered_map>> + optimalSolutionQubits{ + {"3_17_13", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ex-1_166", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ham3_102", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, + {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {1, 2, 0}}}, + {"miller_11", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 2, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {0, 1, 2}, + {0, 1, 2}, + {0, 2, 1}, + {0, 2, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"4gt11_84", {{0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {2, 1, 0, 3, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {1, 0, 2, -1, 4}, {1, 2, 0, -1, 4}, {2, 1, 0, -1, 4}, + {2, 0, 1, -1, 4}, {4, 2, 1, 0, 3}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 2, 1, -1, 4}, {0, 2, 1, -1, 4}, + {2, 0, 1, -1, 4}, {2, 0, 1, -1, 4}, {2, 1, 0, 3, 4}}}, + {"4mod5-v0_20", + {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, + {0, 2, 4, 3, 1}, {0, 4, 2, 3, 1}, {0, 4, 1, 3, 2}, + {0, 4, 2, 3, 1}, {0, 4, 2, 3, 1}, {4, 0, 2, 1, 3}, + {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, + {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, + {4, 2, 0, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, + {0, 2, 3, 1, 4}, {0, 3, 2, 4, 1}, {0, 3, 4, 2, 1}, + {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {0, 3, 4, 2, 1}}}, + {"mod5d1_63", + {{0, 2, 1, 3, 4}, + {0, 2, 1, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 4, 3, 0}, + {4, 2, 1, 3, 0}, + {4, 2, 0, 3, 1}, + {4, 2, 1, 3, 0}, + {4, 2, 1, 3, 0}, + {4, 2, 0, 3, 1}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {4, 0, 2, 1, 3}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {0, 2, 1, 3, 4}, + {0, 2, 3, 1, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 4, 0}, + {2, 3, 4, 1, 0}, + {2, 3, 4, 0, 1}, + {2, 3, 4, 1, 0}, + {2, 3, 4, 1, 0}, + {-1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4}}}, + {"ising_model_10", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}, + {"rd73_140", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 2, 3, 4, 5, 1, 7, 6, 8, 9}, + {2, 3, 4, 0, 7, 5, 1, 6, 8, 9}, + {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, + {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, + {2, 3, 4, 0, 7, 1, 5, 6, 8, 9}, + {2, 7, 3, 4, 0, 1, 5, 6, 8, 9}, + {2, 3, 4, 0, 7, 8, 1, 5, 6, 9}, + {3, 4, 2, 8, 0, 7, 1, 5, 6, 9}, + {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 4, 8, 7, 2, 0, 1, 5, 6, 9}, + {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 4, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 4, 3, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 3, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 2, 7, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, -1, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, -1, 8, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, 8, -1, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 8, -1, 7, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, 7, 8, 5, -1, 2, 3, 1, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 7, 5, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 4, 5, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {5, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, -1, 7}, + {7, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, 5}, + {-1, 9, 6, 8, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 8, 6, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}}}}; for (const auto& [circuit, qubits] : optimalSolutionQubits) { if (optimalSolutions.find(circuit) == optimalSolutions.end()) { - throw std::runtime_error("Missing precalculated optimal solutions for circuit " + circuit); + throw std::runtime_error( + "Missing precalculated optimal solutions for circuit " + circuit); } if (optimalSolutions.at(circuit).size() != qubits.size()) { - throw std::runtime_error("Missing some precalculated optimal solutions for circuit " + circuit); + throw std::runtime_error( + "Missing some precalculated optimal solutions for circuit " + + circuit); } for (std::size_t i = 0; i < qubits.size(); ++i) { - std::fill(optimalSolutions.at(circuit).at(i).qubits.begin(), optimalSolutions.at(circuit).at(i).qubits.end(), -1); - std::fill(optimalSolutions.at(circuit).at(i).locations.begin(), optimalSolutions.at(circuit).at(i).locations.end(), -1); + std::fill(optimalSolutions.at(circuit).at(i).qubits.begin(), + optimalSolutions.at(circuit).at(i).qubits.end(), -1); + std::fill(optimalSolutions.at(circuit).at(i).locations.begin(), + optimalSolutions.at(circuit).at(i).locations.end(), -1); for (std::size_t j = 0; j < qubits.at(i).size(); ++j) { if (qubits.at(i).at(j) >= 0) { optimalSolutions.at(circuit).at(i).qubits[j] = qubits.at(i).at(j); - optimalSolutions.at(circuit).at(i).locations[static_cast(qubits.at(i).at(j))] = static_cast(j); + optimalSolutions.at(circuit) + .at(i) + .locations[static_cast(qubits.at(i).at(j))] = + static_cast(j); } } } @@ -805,7 +1129,8 @@ class TestHeuristics } }; -std::unordered_map> TestHeuristics::optimalSolutions{}; +std::unordered_map> + TestHeuristics::optimalSolutions{}; INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, @@ -838,20 +1163,20 @@ TEST_P(TestHeuristics, HeuristicProperties) { isPrincipallyAdmissible(settings.heuristic)) << "Admissible heuristics are by definition also principally admissible: " << toString(settings.heuristic); - - EXPECT_TRUE(!(isTight(settings.heuristic) && - isFidelityAware(settings.heuristic))) + + EXPECT_TRUE( + !(isTight(settings.heuristic) && isFidelityAware(settings.heuristic))) << "Fidelity-aware heuristics cannot be tight because of the " "non-convexity of the fidelity-aware cost function: " << toString(settings.heuristic); - + // list of nodes for each search process (i.e. each layer) in all mappings - // each node is at the position corresponding to its id; positions of unused + // each node is at the position corresponding to its id; positions of unused // ids are filled with default values (i.e. node.id = 0) std::vector> allNodes{}; std::vector layerNames{}; std::vector finalSolutionIds{}; - + // map to IBM Yorktown if possible if (qc.getNqubits() <= ibmqYorktown.getNqubits()) { if (isFidelityAware(settings.heuristic)) { @@ -862,14 +1187,15 @@ TEST_P(TestHeuristics, HeuristicProperties) { for (std::size_t i = 0; i < results.layerHeuristicBenchmark.size(); ++i) { allNodes.emplace_back( results.layerHeuristicBenchmark.at(i).generatedNodes); - layerNames.emplace_back("on ibmq_yorktown in layer " + std::to_string(i)); + layerNames.emplace_back("on ibmq_yorktown in layer " + + std::to_string(i)); parseNodesFromDatalog(settings.dataLoggingPath, i, allNodes.back()); finalSolutionIds.push_back( getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } } - + // map to IBM London if possible if (qc.getNqubits() <= ibmqLondon.getNqubits()) { ibmqLondonMapper->map(settings); @@ -883,7 +1209,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { getFinalNodeFromDatalog(settings.dataLoggingPath, i)); } } - + // map to IBM QX5 if possible if (qc.getNqubits() <= ibmQX5.getNqubits()) { if (isFidelityAware(settings.heuristic)) { @@ -908,39 +1234,42 @@ TEST_P(TestHeuristics, HeuristicProperties) { if (finalSolutionId >= nodes.size() || nodes.at(finalSolutionId).id != finalSolutionId) { - FAIL() << "Final solution node " << finalSolutionId - << " not found " << layerNames.at(i); + FAIL() << "Final solution node " << finalSolutionId << " not found " + << layerNames.at(i); } auto& finalSolutionNode = nodes.at(finalSolutionId); EXPECT_TRUE(finalSolutionNode.validMapping); if (isPrincipallyAdmissible(settings.heuristic)) { - // for principally admissible heuristics all nodes on the optimal - // solution path should have + // for principally admissible heuristics all nodes on the optimal + // solution path should have // node.costFixed+node.costHeur <= finalSolutionNode.costFixed auto solutionPath = getPathToRoot(nodes, finalSolutionId); for (auto nodeId : solutionPath) { if (nodes.at(nodeId).id != nodeId) { - throw std::runtime_error("Invalid node id " + std::to_string(nodeId) + " " + layerNames.at(i)); + throw std::runtime_error("Invalid node id " + std::to_string(nodeId) + + " " + layerNames.at(i)); } EXPECT_LE(nodes.at(nodeId).getTotalCost(), finalSolutionNode.costFixed) << "Heuristic " << toString(settings.heuristic) - << " is not principally admissible " << layerNames.at(i) + << " is not principally admissible " << layerNames.at(i) << " in node " << nodeId; } if (isTight(settings.heuristic)) { // Principally admissible heuristics are guaranteed to find a solution - // with optimal cost (given lookahead is disabled). If there are - // multiple optimal solutions, though, and the heuristic is not tight, - // the differences in heuristics can lead to a different node ordering - // and thereby different solutions (potentially even resulting in + // with optimal cost (given lookahead is disabled). If there are + // multiple optimal solutions, though, and the heuristic is not tight, + // the differences in heuristics can lead to a different node ordering + // and thereby different solutions (potentially even resulting in // different costs in later layers) // However, if a heuristic is both principally admissible and tight, - // it is guaranteed to always find the same solution as any other such + // it is guaranteed to always find the same solution as any other such // heuristic. - if (optimalSolutions.find(circuitName) == optimalSolutions.end() || + if (optimalSolutions.find(circuitName) == optimalSolutions.end() || optimalSolutions.at(circuitName).size() <= i) { - throw std::runtime_error("Missing precalculated optimal solution for circuit " + circuitName); + throw std::runtime_error( + "Missing precalculated optimal solution for circuit " + + circuitName); } EXPECT_TRUE(finalSolutionNode == optimalSolutions.at(circuitName).at(i)) << "Heuristic " << toString(settings.heuristic) @@ -959,17 +1288,17 @@ TEST_P(TestHeuristics, HeuristicProperties) { if (node.parent >= nodes.size() || nodes.at(node.parent).id != node.parent) { FAIL() << "Invalid parent id " << node.parent << " for node " - << node.id << " " << layerNames.at(i); + << node.id << " " << layerNames.at(i); } EXPECT_GE(node.getTotalCost(), nodes.at(node.parent).getTotalCost()) << "Heuristic " << toString(settings.heuristic) - << " does not result in non-decreasing cost estimation " + << " does not result in non-decreasing cost estimation " << layerNames.at(i) << " in node " << node.id; } } EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) - << "Lookahead penalty not 0 " << layerNames.at(i) + << "Lookahead penalty not 0 " << layerNames.at(i) << " even though lookahead has been deactivated"; if (node.validMapping) { @@ -984,16 +1313,16 @@ TEST_P(TestHeuristics, HeuristicProperties) { // for admissible heuristics all nodes should have // node.costFixed+node.costHeur <= solutionNode.costFixed, // where solutionNode is the best goal node reachable from the node; - // since reachability in a directed tree is equivalent to the being - // on the same path to the root, one can also check that all nodes on + // since reachability in a directed tree is equivalent to the being + // on the same path to the root, one can also check that all nodes on // the path to the root from any goal node fulfill this condition auto path = getPathToRoot(nodes, node.id); for (auto nodeId : path) { auto& n = nodes.at(nodeId); EXPECT_LE(n.getTotalCost(), node.costFixed) << "Heuristic " << toString(settings.heuristic) - << " is not admissible " << layerNames.at(i) - << " in node " << nodeId; + << " is not admissible " << layerNames.at(i) << " in node " + << nodeId; } } } From 9d56889390b3471f8c793a6a344b553427b0a2ba Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 00:54:56 +0100 Subject: [PATCH 19/47] fix test_compile --- test/python/test_compile.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/python/test_compile.py b/test/python/test_compile.py index 513e49875..6ef0ce7c3 100644 --- a/test/python/test_compile.py +++ b/test/python/test_compile.py @@ -154,11 +154,12 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: example_circuit, arch=arch, method="heuristic", - consider_fidelity=False, + heuristic="gate_count_max_distance", initial_layout="dynamic", iterative_bidirectional_routing_passes=1, layering="individual_gates", automatic_layer_splits_node_limit=5000, + lookahead_heuristic="gate_count_max_distance", lookaheads=15, lookahead_factor=0.5, use_teleportation=True, @@ -171,7 +172,8 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: visualizer=visualizer, ) assert results.configuration.method == qmap.Method.heuristic - assert results.configuration.consider_fidelity is False + assert results.configuration.heuristic is qmap.Heuristic.gate_count_max_distance + assert results.configuration.lookahead_heuristic is qmap.LookaheadHeuristic.gate_count_max_distance assert results.configuration.initial_layout == qmap.InitialLayout.dynamic assert results.configuration.iterative_bidirectional_routing is True assert results.configuration.iterative_bidirectional_routing_passes == 1 @@ -179,7 +181,6 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: assert results.configuration.automatic_layer_splits is True assert results.configuration.automatic_layer_splits_node_limit == 5000 assert results.configuration.lookaheads == 15 - assert results.configuration.lookahead is True assert results.configuration.lookahead_factor == 0.5 assert results.configuration.use_teleportation is True assert results.configuration.teleportation_fake is False @@ -194,12 +195,12 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: example_circuit, arch=arch, method="heuristic", - consider_fidelity=True, + heuristic="fidelity_best_location", initial_layout="identity", iterative_bidirectional_routing_passes=None, layering="disjoint_qubits", automatic_layer_splits_node_limit=None, - lookaheads=None, + lookahead_heuristic=None, use_teleportation=False, pre_mapping_optimizations=False, post_mapping_optimizations=False, @@ -207,7 +208,8 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: debug=False, ) assert results.configuration.method == qmap.Method.heuristic - assert results.configuration.consider_fidelity is True + assert results.configuration.heuristic is qmap.Heuristic.fidelity_best_location + assert results.configuration.lookahead_heuristic is qmap.LookaheadHeuristic.none assert results.configuration.initial_layout == qmap.InitialLayout.identity assert results.configuration.iterative_bidirectional_routing is False assert results.configuration.layering == qmap.Layering.disjoint_qubits From a1f0bb7dbaa6f23f53605f3aef3435701a4fcdb7 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 03:49:00 +0100 Subject: [PATCH 20/47] expose heuristic enums in python module --- src/mqt/qmap/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mqt/qmap/__init__.py b/src/mqt/qmap/__init__.py index 7d6e6d6a7..156a4bb0b 100644 --- a/src/mqt/qmap/__init__.py +++ b/src/mqt/qmap/__init__.py @@ -29,7 +29,9 @@ CommanderGrouping, Configuration, Encoding, + Heuristic, InitialLayout, + LookaheadHeuristic, Layering, MappingResults, Method, @@ -56,6 +58,8 @@ "Configuration", "MappingResults", "Architecture", + "Heuristic", + "LookaheadHeuristic", "SubarchitectureOrder", "SynthesisConfiguration", "SynthesisResults", From cc0cd8c2253c8335b00967c1453d1ff3b0c16aae Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Thu, 11 Jan 2024 23:20:26 +0100 Subject: [PATCH 21/47] fixing teleport mapping bug --- src/heuristic/HeuristicMapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 4ce5bdfc5..987af84e7 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -157,7 +157,7 @@ void HeuristicMapper::createInitialMapping() { mt.seed(config.teleportationSeed); } - std::uniform_int_distribution<> dis(0, architecture->getNqubits() - 1); + std::uniform_int_distribution<> dis(0, static_cast(architecture->getCouplingMap().size() - 1)); for (std::size_t i = 0; i < config.teleportationQubits; i += 2) { Edge e{}; From f077450c692d186f387e24fba7cad9f1abda0ea8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 22:21:24 +0000 Subject: [PATCH 22/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heuristic/HeuristicMapper.cpp | 4 +++- src/mqt/qmap/__init__.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 987af84e7..468de935c 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -157,7 +157,9 @@ void HeuristicMapper::createInitialMapping() { mt.seed(config.teleportationSeed); } - std::uniform_int_distribution<> dis(0, static_cast(architecture->getCouplingMap().size() - 1)); + std::uniform_int_distribution<> dis( + 0, + static_cast(architecture->getCouplingMap().size() - 1)); for (std::size_t i = 0; i < config.teleportationQubits; i += 2) { Edge e{}; diff --git a/src/mqt/qmap/__init__.py b/src/mqt/qmap/__init__.py index 156a4bb0b..92996363d 100644 --- a/src/mqt/qmap/__init__.py +++ b/src/mqt/qmap/__init__.py @@ -31,8 +31,8 @@ Encoding, Heuristic, InitialLayout, - LookaheadHeuristic, Layering, + LookaheadHeuristic, MappingResults, Method, QuantumComputation, From 4d6c89e1dbc7221c6cd12ef3df310e4d0972268b Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 00:29:36 +0100 Subject: [PATCH 23/47] adjust data logging paths for parallel testing --- src/DataLogger.cpp | 2 +- test/test_heuristic.cpp | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/DataLogger.cpp b/src/DataLogger.cpp index 6d94a2e19..b354da480 100644 --- a/src/DataLogger.cpp +++ b/src/DataLogger.cpp @@ -15,7 +15,7 @@ void DataLogger::initLog() { } const std::filesystem::path dirPath(dataLoggingPath); if (!std::filesystem::exists(dirPath)) { - std::filesystem::create_directory(dirPath); + std::filesystem::create_directories(dirPath); } clearLog(); }; diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index f1a62febe..2f4ea70d8 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -21,6 +21,9 @@ constexpr qc::OpType SWAP = qc::OpType::SWAP; */ std::size_t getFinalNodeFromDatalog(std::string dataLoggingPath, std::size_t layer) { + if (dataLoggingPath.back() != '/') { + dataLoggingPath += '/'; + } auto layerFile = std::ifstream(dataLoggingPath + "/layer_" + std::to_string(layer) + ".json"); if (!layerFile.is_open()) { @@ -46,6 +49,9 @@ std::size_t getFinalNodeFromDatalog(std::string dataLoggingPath, */ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::vector& nodes) { + if (dataLoggingPath.back() != '/') { + dataLoggingPath += '/'; + } std::string layerNodeFilePath = dataLoggingPath + "/nodes_layer_" + std::to_string(layer) + ".csv"; auto layerNodeFile = std::ifstream(layerNodeFilePath); @@ -1110,6 +1116,12 @@ class TestHeuristics } void SetUp() override { + std::string cn = std::get<1>(GetParam()); + std::replace(cn.begin(), cn.end(), '-', '_'); + std::stringstream ss{}; + ss << cn << "_" << toString(std::get<0>(GetParam())); + std::string testName = ss.str(); + circuitName = std::get<1>(GetParam()); qc.import(testExampleDir + circuitName + ".qasm"); ibmqYorktown.loadCouplingMap(AvailableArchitecture::IbmqYorktown); @@ -1125,7 +1137,7 @@ class TestHeuristics settings.layering = Layering::Disjoint2qBlocks; settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.heuristic = std::get<0>(GetParam()); - settings.dataLoggingPath = "test_log"; + settings.dataLoggingPath = "test_log/heur_properties_" + testName + "/"; } }; @@ -1535,7 +1547,7 @@ TEST(Functionality, InvalidCircuits) { } TEST(Functionality, DataLoggerAfterClose) { - const std::string dataLoggingPath = "test_log/"; + const std::string dataLoggingPath = "test_log/datalogger_after_close/"; qc::QuantumComputation qc{3}; qc.x(0); Architecture arch{3, {}}; @@ -1610,7 +1622,7 @@ TEST(Functionality, DataLogger) { settings.debug = true; settings.useTeleportation = false; // setting data logging path to enable data logging - settings.dataLoggingPath = "test_log"; + settings.dataLoggingPath = "test_log/datalogger"; // remove directory at data logging path if it already exists if (std::filesystem::exists(settings.dataLoggingPath)) { @@ -2183,7 +2195,6 @@ class HeuristicTest5Q : public testing::TestWithParam { ibmqYorktownMapper = std::make_unique(qc, ibmqYorktown); ibmqLondonMapper = std::make_unique(qc, ibmqLondon); settings.debug = true; - settings.verbose = true; settings.iterativeBidirectionalRouting = true; settings.iterativeBidirectionalRoutingPasses = 3; @@ -2768,7 +2779,7 @@ TEST(HeuristicTestFidelity, LayerSplitting) { settings.automaticLayerSplitsNodeLimit = 1; // force splittings after 1st expanded node until layers are // unsplittable - settings.dataLoggingPath = "test_log/"; + settings.dataLoggingPath = "test_log/layer_splitting/"; mapper->map(settings); mapper->dumpResult("simple_grid_mapped.qasm"); mapper->printResult(std::cout); From 7ac87c40beb3e7f55f9b775361cdbaf3e8c54036 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:30:07 +0000 Subject: [PATCH 24/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test_heuristic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 2f4ea70d8..0372e3bb1 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -1121,7 +1121,7 @@ class TestHeuristics std::stringstream ss{}; ss << cn << "_" << toString(std::get<0>(GetParam())); std::string testName = ss.str(); - + circuitName = std::get<1>(GetParam()); qc.import(testExampleDir + circuitName + ".qasm"); ibmqYorktown.loadCouplingMap(AvailableArchitecture::IbmqYorktown); @@ -1137,7 +1137,7 @@ class TestHeuristics settings.layering = Layering::Disjoint2qBlocks; settings.lookaheadHeuristic = LookaheadHeuristic::None; settings.heuristic = std::get<0>(GetParam()); - settings.dataLoggingPath = "test_log/heur_properties_" + testName + "/"; + settings.dataLoggingPath = "test_log/heur_properties_" + testName + "/"; } }; From 7ec24e525f7c760d8697b69904971224f3ba5fe9 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 02:37:49 +0100 Subject: [PATCH 25/47] fix mypy errors --- src/mqt/qmap/pyqmap.pyi | 24 ++++++++++++------------ test/python/test_compile.py | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/mqt/qmap/pyqmap.pyi b/src/mqt/qmap/pyqmap.pyi index a9f32ee64..15b2822d3 100644 --- a/src/mqt/qmap/pyqmap.pyi +++ b/src/mqt/qmap/pyqmap.pyi @@ -220,18 +220,18 @@ class InitialLayout: def value(self) -> int: ... class Heuristic: - __members__: ClassVar[dict[InitialLayout, int]] = ... # read-only - gate_count_max_distance: ClassVar[InitialLayout] = ... - gate_count_sum_distance: ClassVar[InitialLayout] = ... - gate_count_sum_distance_minus_shared_swaps: ClassVar[InitialLayout] = ... - gate_count_max_distance_or_sum_distance_minus_shared_swaps: ClassVar[InitialLayout] = ... - fidelity_best_location: ClassVar[InitialLayout] = ... + __members__: ClassVar[dict[Heuristic, int]] = ... # read-only + gate_count_max_distance: ClassVar[Heuristic] = ... + gate_count_sum_distance: ClassVar[Heuristic] = ... + gate_count_sum_distance_minus_shared_swaps: ClassVar[Heuristic] = ... + gate_count_max_distance_or_sum_distance_minus_shared_swaps: ClassVar[Heuristic] = ... + fidelity_best_location: ClassVar[Heuristic] = ... @overload def __init__(self, value: int) -> None: ... @overload def __init__(self, arg0: str) -> None: ... @overload - def __init__(self, arg0: InitialLayout) -> None: ... + def __init__(self, arg0: Heuristic) -> None: ... def __eq__(self, other: object) -> bool: ... def __getstate__(self) -> int: ... def __hash__(self) -> int: ... @@ -245,16 +245,16 @@ class Heuristic: def value(self) -> int: ... class LookaheadHeuristic: - __members__: ClassVar[dict[InitialLayout, int]] = ... # read-only - none: ClassVar[InitialLayout] = ... - gate_count_max_distance: ClassVar[InitialLayout] = ... - gate_count_sum_distance: ClassVar[InitialLayout] = ... + __members__: ClassVar[dict[LookaheadHeuristic, int]] = ... # read-only + none: ClassVar[LookaheadHeuristic] = ... + gate_count_max_distance: ClassVar[LookaheadHeuristic] = ... + gate_count_sum_distance: ClassVar[LookaheadHeuristic] = ... @overload def __init__(self, value: int) -> None: ... @overload def __init__(self, arg0: str) -> None: ... @overload - def __init__(self, arg0: InitialLayout) -> None: ... + def __init__(self, arg0: LookaheadHeuristic) -> None: ... def __eq__(self, other: object) -> bool: ... def __getstate__(self) -> int: ... def __hash__(self) -> int: ... diff --git a/test/python/test_compile.py b/test/python/test_compile.py index 6ef0ce7c3..7b7f4989f 100644 --- a/test/python/test_compile.py +++ b/test/python/test_compile.py @@ -215,7 +215,6 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: assert results.configuration.layering == qmap.Layering.disjoint_qubits assert results.configuration.automatic_layer_splits is False assert results.configuration.lookaheads == 0 - assert results.configuration.lookahead is False assert results.configuration.use_teleportation is False assert results.configuration.pre_mapping_optimizations is False assert results.configuration.post_mapping_optimizations is False From 57c0bb1fea767b14cab18f40e09f570f75e828e3 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 02:39:44 +0100 Subject: [PATCH 26/47] fix test_compile --- test/python/test_compile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/python/test_compile.py b/test/python/test_compile.py index 7b7f4989f..fc52b13a0 100644 --- a/test/python/test_compile.py +++ b/test/python/test_compile.py @@ -172,8 +172,8 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: visualizer=visualizer, ) assert results.configuration.method == qmap.Method.heuristic - assert results.configuration.heuristic is qmap.Heuristic.gate_count_max_distance - assert results.configuration.lookahead_heuristic is qmap.LookaheadHeuristic.gate_count_max_distance + assert results.configuration.heuristic == qmap.Heuristic.gate_count_max_distance + assert results.configuration.lookahead_heuristic == qmap.LookaheadHeuristic.gate_count_max_distance assert results.configuration.initial_layout == qmap.InitialLayout.dynamic assert results.configuration.iterative_bidirectional_routing is True assert results.configuration.iterative_bidirectional_routing_passes == 1 @@ -208,8 +208,8 @@ def test_parameters(example_circuit: QuantumCircuit) -> None: debug=False, ) assert results.configuration.method == qmap.Method.heuristic - assert results.configuration.heuristic is qmap.Heuristic.fidelity_best_location - assert results.configuration.lookahead_heuristic is qmap.LookaheadHeuristic.none + assert results.configuration.heuristic == qmap.Heuristic.fidelity_best_location + assert results.configuration.lookahead_heuristic == qmap.LookaheadHeuristic.none assert results.configuration.initial_layout == qmap.InitialLayout.identity assert results.configuration.iterative_bidirectional_routing is False assert results.configuration.layering == qmap.Layering.disjoint_qubits From b1ca64da3ff0f98023dd1d758c05599e70bc3a71 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 03:31:08 +0100 Subject: [PATCH 27/47] fix lint warnings --- include/heuristic/HeuristicMapper.hpp | 7 +- include/utils.hpp | 2 +- src/heuristic/HeuristicMapper.cpp | 140 ++++++++++++-------------- src/utils.cpp | 3 +- test/test_general.cpp | 6 +- test/test_heuristic.cpp | 91 +++++++++-------- 6 files changed, 117 insertions(+), 132 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 9900066ea..a7cfc9f95 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -96,8 +96,8 @@ class HeuristicMapper : public Mapper { const std::size_t searchDepth = 0, const std::size_t initSharedSwaps = 0) : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), - depth(searchDepth), parent(parentId), id(nodeId), - sharedSwaps(initSharedSwaps) { + sharedSwaps(initSharedSwaps), depth(searchDepth), parent(parentId), + id(nodeId) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); std::copy(sw.begin(), sw.end(), std::back_inserter(swaps)); @@ -239,9 +239,8 @@ class HeuristicMapper : public Mapper { getConsideredQubits(std::size_t layer) const { if (fidelityAwareHeur) { return activeQubits.at(layer); - } else { - return activeQubits2QGates.at(layer); } + return activeQubits2QGates.at(layer); } /** diff --git a/include/utils.hpp b/include/utils.hpp index 5623e7e2e..d0415564a 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -112,7 +112,7 @@ class Dijkstra { */ static void buildSingleEdgeSkipTable(const Matrix& distanceTable, const CouplingMap& couplingMap, - const double reversalCost, + double reversalCost, Matrix& edgeSkipDistanceTable); protected: diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 468de935c..d935f4fcf 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -30,9 +30,7 @@ void HeuristicMapper::map(const Configuration& configuration) { if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { throw QMAPException("No calibration data available for this architecture!"); } - if (fidelityAwareHeur && - !(isFidelityAware(config.lookaheadHeuristic) || - config.lookaheadHeuristic == LookaheadHeuristic::None)) { + if (fidelityAwareHeur && !isFidelityAware(config.lookaheadHeuristic) && config.lookaheadHeuristic != LookaheadHeuristic::None) { throw QMAPException("Fidelity-aware heuristics may only be used with " "fidelity-aware lookahead heuristics (or no " "lookahead)!"); @@ -944,7 +942,6 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { const auto [q3, q4] = edge; - const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); @@ -1085,7 +1082,6 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { const auto [q3, q4] = edge; - const auto [forwardMult, reverseMult] = mult; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); @@ -1114,79 +1110,69 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); + if (q1 == -1 || q2 == -1 || consideredQubits.find(static_cast(q1)) != consideredQubits.end() || consideredQubits.find(static_cast(q2)) != consideredQubits.end()) { + // the given swap can only be a shared swap if both qubits are active in + // the current layer + return; + } - if (consideredQubits.find(q1) != consideredQubits.end() && - consideredQubits.find(q2) != consideredQubits.end()) { - // TODO: handle single qubit gates for fidelity aware heuristic - Edge logEdge1 = {q1, q1}; - Edge logEdge2 = {q2, q2}; - for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { - if (edge.first == q1) { - logEdge1.second = edge.second; - } else if (edge.second == q1) { - logEdge1.second = edge.first; - } - if (edge.first == q2) { - logEdge2.second = edge.second; - } else if (edge.second == q2) { - logEdge2.second = edge.first; - } + // TODO: handle single qubit gates for fidelity aware heuristic, if + // `Node::sharedSwaps` is ever used in a fidelity aware heuristic + Edge logEdge1 = {q1, q1}; + Edge logEdge2 = {q2, q2}; + for (const auto& [edge, multiplicity] : twoQubitGateMultiplicity) { + if (edge.first == q1) { + logEdge1.second = edge.second; + } else if (edge.second == q1) { + logEdge1.second = edge.first; } - if ( // if both swapped qubits are acted on by a 2q gate - logEdge1.second != q1 && logEdge2.second != q2 && - // if it is not the same 2q gate acting on both qubits - logEdge1.second != q2) { - double logEdge1DistanceBefore; - double logEdge1DistanceNew; - double logEdge2DistanceBefore; - double logEdge2DistanceNew; - if (fidelityAwareHeur) { - logEdge1DistanceBefore = - std::min(architecture->fidelityDistance( - swap.first, node.locations[logEdge1.second]), - architecture->fidelityDistance( - node.locations[logEdge1.second], swap.first)); - logEdge1DistanceNew = - std::min(architecture->fidelityDistance( - swap.second, node.locations[logEdge1.second]), - architecture->fidelityDistance( - node.locations[logEdge1.second], swap.second)); - logEdge2DistanceBefore = - std::min(architecture->fidelityDistance( - swap.second, node.locations[logEdge2.second]), - architecture->fidelityDistance( - node.locations[logEdge2.second], swap.second)); - logEdge2DistanceNew = - std::min(architecture->fidelityDistance( - swap.first, node.locations[logEdge2.second]), - architecture->fidelityDistance( - node.locations[logEdge2.second], swap.first)); - } else { - logEdge1DistanceBefore = - std::min(architecture->distance( - swap.first, node.locations[logEdge1.second], false), - architecture->distance(node.locations[logEdge1.second], - swap.first, false)); - logEdge1DistanceNew = - std::min(architecture->distance( - swap.second, node.locations[logEdge1.second], false), - architecture->distance(node.locations[logEdge1.second], - swap.second, false)); - logEdge2DistanceBefore = - std::min(architecture->distance( - swap.second, node.locations[logEdge2.second], false), - architecture->distance(node.locations[logEdge2.second], - swap.second, false)); - logEdge2DistanceNew = - std::min(architecture->distance( - swap.first, node.locations[logEdge2.second], false), - architecture->distance(node.locations[logEdge2.second], - swap.first, false)); - } - if (logEdge1DistanceNew < logEdge1DistanceBefore && - logEdge2DistanceNew < logEdge2DistanceBefore) { - ++node.sharedSwaps; - } + if (edge.first == q2) { + logEdge2.second = edge.second; + } else if (edge.second == q2) { + logEdge2.second = edge.first; + } + } + if ( // if both swapped qubits are acted on by a 2q gate + logEdge1.second != q1 && logEdge2.second != q2 && + // if it is not the same 2q gate acting on both qubits + logEdge1.second != q2) { + auto physQ3 = static_cast(node.locations.at(logEdge1.second)); + auto physQ4 = static_cast(node.locations.at(logEdge2.second)); + + double logEdge1DistanceBefore = 0.; + double logEdge1DistanceNew = 0.; + double logEdge2DistanceBefore = 0.; + double logEdge2DistanceNew = 0.; + if (fidelityAwareHeur) { + logEdge1DistanceBefore = + std::min(architecture->fidelityDistance(swap.first, physQ3), + architecture->fidelityDistance(physQ3, swap.first)); + logEdge1DistanceNew = + std::min(architecture->fidelityDistance(swap.second, physQ3), + architecture->fidelityDistance(physQ3, swap.second)); + logEdge2DistanceBefore = + std::min(architecture->fidelityDistance(swap.second, physQ4), + architecture->fidelityDistance(physQ4, swap.second)); + logEdge2DistanceNew = + std::min(architecture->fidelityDistance(swap.first, physQ4), + architecture->fidelityDistance(physQ4, swap.first)); + } else { + logEdge1DistanceBefore = + std::min(architecture->distance(swap.first, physQ3, false), + architecture->distance(physQ3, swap.first, false)); + logEdge1DistanceNew = + std::min(architecture->distance(swap.second, physQ3, false), + architecture->distance(physQ3, swap.second, false)); + logEdge2DistanceBefore = + std::min(architecture->distance(swap.second, physQ4, false), + architecture->distance(physQ4,swap.second, false)); + logEdge2DistanceNew = + std::min(architecture->distance(swap.first, physQ4, false), + architecture->distance(physQ4,swap.first, false)); + } + if (logEdge1DistanceNew < logEdge1DistanceBefore && + logEdge2DistanceNew < logEdge2DistanceBefore) { + ++node.sharedSwaps; } } } @@ -1355,7 +1341,7 @@ double HeuristicMapper::heuristicGateCountSumDistanceMinusSharedSwaps( } // sort number of swaps in descending order - std::sort(nSwaps.begin(), nSwaps.end(), std::greater()); + std::sort(nSwaps.begin(), nSwaps.end(), std::greater<>()); // infer maximum number of shared swaps std::size_t maxSharedSwaps = 0; diff --git a/src/utils.cpp b/src/utils.cpp index 2bbdf4c26..d0f92e1ab 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -9,7 +9,8 @@ void Dijkstra::buildTable(const CouplingMap& couplingMap, Matrix& distanceTable, const Matrix& edgeWeights) { - const std::uint16_t n = edgeWeights.size(); // number of qubits + // number of qubits + const auto n = static_cast(edgeWeights.size()); distanceTable.clear(); distanceTable.resize(n, std::vector(n, -1.)); diff --git a/test/test_general.cpp b/test/test_general.cpp index 05deb84c6..6f7ca2d6e 100644 --- a/test/test_general.cpp +++ b/test/test_general.cpp @@ -90,16 +90,16 @@ TEST(General, DijkstraCNOTReversal) { {0, 0, 0, 3, 0}}; Matrix simpleDistanceTable{}; Dijkstra::buildTable(cm, simpleDistanceTable, edgeWeights); - Matrix distanceTable{}; + Matrix fullDistanceTable{}; Dijkstra::buildSingleEdgeSkipTable(simpleDistanceTable, cm, 1., - distanceTable); + fullDistanceTable); const Matrix targetTable2 = {{0, 0, 3, 6, 9}, {1, 0, 1, 3, 6}, {3, 0, 0, 0, 3}, {6, 3, 1, 0, 0}, {9, 6, 4, 1, 0}}; - EXPECT_EQ(distanceTable, targetTable2); + EXPECT_EQ(fullDistanceTable, targetTable2); } TEST(General, DijkstraSkipEdges) { diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 0372e3bb1..4dd72ad0a 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -15,6 +15,7 @@ #include constexpr qc::OpType SWAP = qc::OpType::SWAP; +constexpr double FLOAT_TOLERANCE = 1e-6; /** * @brief Get id of the final node in a given layer from a data log. @@ -52,7 +53,7 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, if (dataLoggingPath.back() != '/') { dataLoggingPath += '/'; } - std::string layerNodeFilePath = + const std::string layerNodeFilePath = dataLoggingPath + "/nodes_layer_" + std::to_string(layer) + ".csv"; auto layerNodeFile = std::ifstream(layerNodeFilePath); if (!layerNodeFile.is_open()) { @@ -106,7 +107,7 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, layerNodeFilePath); } if (std::getline(lineStream, col, ';')) { - std::size_t validMapping = std::stoull(col); + const std::size_t validMapping = std::stoull(col); if (validMapping > 1) { throw std::runtime_error("Non-boolean value " + std::to_string(validMapping) + @@ -128,9 +129,9 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::string entry; for (std::size_t i = 0; std::getline(qubitMapBuffer, entry, ','); ++i) { auto qubit = static_cast(std::stoi(entry)); - node.qubits[i] = qubit; + node.qubits.at(i) = qubit; if (qubit >= 0) { - node.locations[qubit] = static_cast(i); + node.locations.at(static_cast(qubit)) = static_cast(i); } } } else { @@ -141,12 +142,12 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::stringstream swapBuffer(col); std::string entry; while (std::getline(swapBuffer, entry, ',')) { - std::uint16_t q1 = 0; - std::uint16_t q2 = 0; - std::string opTypeStr = ""; + std::uint16_t q1 = 0; + std::uint16_t q2 = 0; + std::string opTypeStr; std::stringstream(entry) >> q1 >> q2 >> opTypeStr; qc::OpType opType = SWAP; - if (opTypeStr.size() > 0) { + if (!opTypeStr.empty()) { // if no opType is given, the default value is SWAP opType = qc::opTypeFromString(opTypeStr); } @@ -170,7 +171,7 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { if (nodeId >= nodes.size() || nodes[nodeId].id != nodeId) { throw std::runtime_error("Invalid node id " + std::to_string(nodeId)); } - auto node = &nodes[nodeId]; + auto* node = &nodes[nodeId]; while (node->parent != node->id) { path.push_back(node->id); if (node->parent >= nodes.size() || @@ -187,17 +188,15 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { class InternalsTest : public HeuristicMapper, public testing::Test { protected: - static Architecture defaultArch; + static Architecture defaultArch; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } }; -Architecture InternalsTest::defaultArch{1, {}}; +Architecture InternalsTest::defaultArch{1, {}}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) TEST_F(InternalsTest, NodeCostCalculation) { - const double tolerance = 1e-6; - results.config.heuristic = Heuristic::GateCountMaxDistance; results.config.lookaheadHeuristic = LookaheadHeuristic::None; results.config.layering = Layering::Disjoint2qBlocks; @@ -222,58 +221,58 @@ TEST_F(InternalsTest, NodeCostCalculation) { HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, {{2, 3}}, 5., 0); - EXPECT_NEAR(node.costFixed, 5., tolerance); - EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance); + EXPECT_NEAR(node.costFixed, 5., FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, 0., FLOAT_TOLERANCE); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 1); results.config.heuristic = Heuristic::GateCountSumDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE * 2, - tolerance); - EXPECT_NEAR(node.costFixed, 5., tolerance) + FLOAT_TOLERANCE); + EXPECT_NEAR(node.costFixed, 5., FLOAT_TOLERANCE) << "updateHeuristicCost should not change costFixed"; results.config.heuristic = Heuristic::GateCountMaxDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, - COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, tolerance); - EXPECT_NEAR(node.costFixed, 5., tolerance) + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, FLOAT_TOLERANCE); + EXPECT_NEAR(node.costFixed, 5., FLOAT_TOLERANCE) << "updateHeuristicCost should not change costFixed"; applySWAP({3, 4}, 0, node); - EXPECT_NEAR(node.costFixed, 5. + COST_UNIDIRECTIONAL_SWAP, tolerance); + EXPECT_NEAR(node.costFixed, 5. + COST_UNIDIRECTIONAL_SWAP, FLOAT_TOLERANCE); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, - tolerance); + FLOAT_TOLERANCE); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); node.lookaheadPenalty = 0.; EXPECT_NEAR(node.getTotalCost(), 5. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, - tolerance); + FLOAT_TOLERANCE); EXPECT_NEAR(node.getTotalFixedCost(), 5. + COST_UNIDIRECTIONAL_SWAP, - tolerance); + FLOAT_TOLERANCE); node.lookaheadPenalty = 2.; EXPECT_NEAR(node.getTotalCost(), 7. + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, - tolerance); + FLOAT_TOLERANCE); EXPECT_NEAR(node.getTotalFixedCost(), 7. + COST_UNIDIRECTIONAL_SWAP, - tolerance); + FLOAT_TOLERANCE); recalculateFixedCost(0, node); EXPECT_EQ(node.validMappedTwoQubitGates.size(), 0); EXPECT_NEAR(node.costFixed, COST_TELEPORTATION + COST_UNIDIRECTIONAL_SWAP * 2, - tolerance); + FLOAT_TOLERANCE); EXPECT_NEAR(node.costHeur, COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE, - tolerance); + FLOAT_TOLERANCE); EXPECT_NEAR(node.getTotalCost(), 2. + COST_TELEPORTATION + COST_UNIDIRECTIONAL_SWAP * 3 + COST_DIRECTION_REVERSE, - tolerance); + FLOAT_TOLERANCE); EXPECT_NEAR(node.getTotalFixedCost(), 2. + COST_TELEPORTATION + COST_UNIDIRECTIONAL_SWAP * 2, - tolerance); + FLOAT_TOLERANCE); } class TestHeuristics @@ -292,10 +291,9 @@ class TestHeuristics Architecture ibmQX5{}; // 16 qubits std::unique_ptr ibmQX5Mapper; Configuration settings{}; - const double tolerance = 1e-6; static std::unordered_map> - optimalSolutions; + optimalSolutions; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static void SetUpTestSuite() { // prepare precalculated optimal solutions to compare against @@ -1104,10 +1102,10 @@ class TestHeuristics optimalSolutions.at(circuit).at(i).locations.end(), -1); for (std::size_t j = 0; j < qubits.at(i).size(); ++j) { if (qubits.at(i).at(j) >= 0) { - optimalSolutions.at(circuit).at(i).qubits[j] = qubits.at(i).at(j); + optimalSolutions.at(circuit).at(i).qubits.at(j) = qubits.at(i).at(j); optimalSolutions.at(circuit) .at(i) - .locations[static_cast(qubits.at(i).at(j))] = + .locations.at(static_cast(qubits.at(i).at(j))) = static_cast(j); } } @@ -1120,7 +1118,7 @@ class TestHeuristics std::replace(cn.begin(), cn.end(), '-', '_'); std::stringstream ss{}; ss << cn << "_" << toString(std::get<0>(GetParam())); - std::string testName = ss.str(); + const std::string testName = ss.str(); circuitName = std::get<1>(GetParam()); qc.import(testExampleDir + circuitName + ".qasm"); @@ -1142,7 +1140,7 @@ class TestHeuristics }; std::unordered_map> - TestHeuristics::optimalSolutions{}; + TestHeuristics::optimalSolutions{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, @@ -1309,14 +1307,14 @@ TEST_P(TestHeuristics, HeuristicProperties) { } } - EXPECT_NEAR(node.lookaheadPenalty, 0., tolerance) + EXPECT_NEAR(node.lookaheadPenalty, 0., FLOAT_TOLERANCE) << "Lookahead penalty not 0 " << layerNames.at(i) << " even though lookahead has been deactivated"; if (node.validMapping) { if (isTight(settings.heuristic)) { // tight heuristics are 0 in any goal node - EXPECT_NEAR(node.costHeur, 0., tolerance) + EXPECT_NEAR(node.costHeur, 0., FLOAT_TOLERANCE) << "Heuristic " << toString(settings.heuristic) << " is not tight " << layerNames.at(i) << " in node " << node.id; } @@ -1838,9 +1836,10 @@ TEST(Functionality, DataLogger) { EXPECT_EQ(layerJson["final_search_depth"], finalSolutionNode.depth); std::vector layout{}; for (std::size_t j = 0; j < architecture.getNqubits(); ++j) { - layout.emplace_back(finalSolutionNode.qubits[j]); + layout.emplace_back(finalSolutionNode.qubits.at(j)); } std::vector> swaps{}; + swaps.reserve(finalSolutionNode.swaps.size()); for (auto& swap : finalSolutionNode.swaps) { swaps.emplace_back(swap.first, swap.second); } @@ -1855,17 +1854,17 @@ TEST(Functionality, DataLogger) { } for (std::size_t k = 0; k < architecture.getNqubits(); ++k) { - EXPECT_GE(node.qubits[k], -1); - EXPECT_LT(node.qubits[k], qc.getNqubits()); - EXPECT_GE(node.locations[k], -1); - EXPECT_LT(node.locations[k], architecture.getNqubits()); + EXPECT_GE(node.qubits.at(k), -1); + EXPECT_LT(node.qubits.at(k), qc.getNqubits()); + EXPECT_GE(node.locations.at(k), -1); + EXPECT_LT(node.locations.at(k), architecture.getNqubits()); - if (node.qubits[k] >= 0) { - EXPECT_EQ(node.locations[static_cast(node.qubits[k])], + if (node.qubits.at(k) >= 0) { + EXPECT_EQ(node.locations[static_cast(node.qubits.at(k))], static_cast(k)); } - if (node.locations[k] >= 0) { - EXPECT_EQ(node.qubits[static_cast(node.locations[k])], + if (node.locations.at(k) >= 0) { + EXPECT_EQ(node.qubits[static_cast(node.locations.at(k))], static_cast(k)); } } From 1df94d05b5c7c4d6caa9447a817f3af393b3f009 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Jan 2024 02:47:33 +0000 Subject: [PATCH 28/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/heuristic/HeuristicMapper.hpp | 2 +- include/utils.hpp | 2 +- src/heuristic/HeuristicMapper.cpp | 33 ++++++++++++++++----------- test/test_heuristic.cpp | 29 +++++++++++++---------- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index a7cfc9f95..1712d5ead 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -96,7 +96,7 @@ class HeuristicMapper : public Mapper { const std::size_t searchDepth = 0, const std::size_t initSharedSwaps = 0) : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), - sharedSwaps(initSharedSwaps), depth(searchDepth), parent(parentId), + sharedSwaps(initSharedSwaps), depth(searchDepth), parent(parentId), id(nodeId) { std::copy(q.begin(), q.end(), qubits.begin()); std::copy(loc.begin(), loc.end(), locations.begin()); diff --git a/include/utils.hpp b/include/utils.hpp index d0415564a..153a91691 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -112,7 +112,7 @@ class Dijkstra { */ static void buildSingleEdgeSkipTable(const Matrix& distanceTable, const CouplingMap& couplingMap, - double reversalCost, + double reversalCost, Matrix& edgeSkipDistanceTable); protected: diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index d935f4fcf..64737a993 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -30,7 +30,8 @@ void HeuristicMapper::map(const Configuration& configuration) { if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { throw QMAPException("No calibration data available for this architecture!"); } - if (fidelityAwareHeur && !isFidelityAware(config.lookaheadHeuristic) && config.lookaheadHeuristic != LookaheadHeuristic::None) { + if (fidelityAwareHeur && !isFidelityAware(config.lookaheadHeuristic) && + config.lookaheadHeuristic != LookaheadHeuristic::None) { throw QMAPException("Fidelity-aware heuristics may only be used with " "fidelity-aware lookahead heuristics (or no " "lookahead)!"); @@ -941,7 +942,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q3, q4] = edge; + const auto [q3, q4] = edge; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); @@ -1081,7 +1082,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q3, q4] = edge; + const auto [q3, q4] = edge; if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); @@ -1110,13 +1111,17 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); - if (q1 == -1 || q2 == -1 || consideredQubits.find(static_cast(q1)) != consideredQubits.end() || consideredQubits.find(static_cast(q2)) != consideredQubits.end()) { - // the given swap can only be a shared swap if both qubits are active in + if (q1 == -1 || q2 == -1 || + consideredQubits.find(static_cast(q1)) != + consideredQubits.end() || + consideredQubits.find(static_cast(q2)) != + consideredQubits.end()) { + // the given swap can only be a shared swap if both qubits are active in // the current layer return; } - // TODO: handle single qubit gates for fidelity aware heuristic, if + // TODO: handle single qubit gates for fidelity aware heuristic, if // `Node::sharedSwaps` is ever used in a fidelity aware heuristic Edge logEdge1 = {q1, q1}; Edge logEdge2 = {q2, q2}; @@ -1136,13 +1141,15 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, logEdge1.second != q1 && logEdge2.second != q2 && // if it is not the same 2q gate acting on both qubits logEdge1.second != q2) { - auto physQ3 = static_cast(node.locations.at(logEdge1.second)); - auto physQ4 = static_cast(node.locations.at(logEdge2.second)); - + auto physQ3 = + static_cast(node.locations.at(logEdge1.second)); + auto physQ4 = + static_cast(node.locations.at(logEdge2.second)); + double logEdge1DistanceBefore = 0.; - double logEdge1DistanceNew = 0.; + double logEdge1DistanceNew = 0.; double logEdge2DistanceBefore = 0.; - double logEdge2DistanceNew = 0.; + double logEdge2DistanceNew = 0.; if (fidelityAwareHeur) { logEdge1DistanceBefore = std::min(architecture->fidelityDistance(swap.first, physQ3), @@ -1165,10 +1172,10 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, architecture->distance(physQ3, swap.second, false)); logEdge2DistanceBefore = std::min(architecture->distance(swap.second, physQ4, false), - architecture->distance(physQ4,swap.second, false)); + architecture->distance(physQ4, swap.second, false)); logEdge2DistanceNew = std::min(architecture->distance(swap.first, physQ4, false), - architecture->distance(physQ4,swap.first, false)); + architecture->distance(physQ4, swap.first, false)); } if (logEdge1DistanceNew < logEdge1DistanceBefore && logEdge2DistanceNew < logEdge2DistanceBefore) { diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 4dd72ad0a..7d3c4a176 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -14,8 +14,8 @@ #include #include -constexpr qc::OpType SWAP = qc::OpType::SWAP; -constexpr double FLOAT_TOLERANCE = 1e-6; +constexpr qc::OpType SWAP = qc::OpType::SWAP; +constexpr double FLOAT_TOLERANCE = 1e-6; /** * @brief Get id of the final node in a given layer from a data log. @@ -128,10 +128,11 @@ void parseNodesFromDatalog(std::string dataLoggingPath, std::size_t layer, std::stringstream qubitMapBuffer(col); std::string entry; for (std::size_t i = 0; std::getline(qubitMapBuffer, entry, ','); ++i) { - auto qubit = static_cast(std::stoi(entry)); + auto qubit = static_cast(std::stoi(entry)); node.qubits.at(i) = qubit; if (qubit >= 0) { - node.locations.at(static_cast(qubit)) = static_cast(i); + node.locations.at(static_cast(qubit)) = + static_cast(i); } } } else { @@ -188,13 +189,15 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { class InternalsTest : public HeuristicMapper, public testing::Test { protected: - static Architecture defaultArch; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + static Architecture + defaultArch; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } }; -Architecture InternalsTest::defaultArch{1, {}}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +Architecture InternalsTest::defaultArch{ + 1, {}}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) TEST_F(InternalsTest, NodeCostCalculation) { results.config.heuristic = Heuristic::GateCountMaxDistance; @@ -236,7 +239,8 @@ TEST_F(InternalsTest, NodeCostCalculation) { results.config.heuristic = Heuristic::GateCountMaxDistance; updateHeuristicCost(0, node); EXPECT_NEAR(node.costHeur, - COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, FLOAT_TOLERANCE); + COST_UNIDIRECTIONAL_SWAP * 2 + COST_DIRECTION_REVERSE, + FLOAT_TOLERANCE); EXPECT_NEAR(node.costFixed, 5., FLOAT_TOLERANCE) << "updateHeuristicCost should not change costFixed"; @@ -1102,10 +1106,10 @@ class TestHeuristics optimalSolutions.at(circuit).at(i).locations.end(), -1); for (std::size_t j = 0; j < qubits.at(i).size(); ++j) { if (qubits.at(i).at(j) >= 0) { - optimalSolutions.at(circuit).at(i).qubits.at(j) = qubits.at(i).at(j); - optimalSolutions.at(circuit) - .at(i) - .locations.at(static_cast(qubits.at(i).at(j))) = + optimalSolutions.at(circuit).at(i).qubits.at(j) = + qubits.at(i).at(j); + optimalSolutions.at(circuit).at(i).locations.at( + static_cast(qubits.at(i).at(j))) = static_cast(j); } } @@ -1140,7 +1144,8 @@ class TestHeuristics }; std::unordered_map> - TestHeuristics::optimalSolutions{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + TestHeuristics:: + optimalSolutions{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, From 0af096f2d904af32cb3f5c80b37b75f964b2c192 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 06:24:14 +0100 Subject: [PATCH 29/47] fix lookahead --- include/heuristic/HeuristicMapper.hpp | 20 - src/heuristic/HeuristicMapper.cpp | 67 +- test/test_heuristic.cpp | 1092 ++++++------------------- 3 files changed, 316 insertions(+), 863 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 1712d5ead..b50d3dd83 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -159,26 +159,6 @@ class HeuristicMapper : public Mapper { */ virtual void staticInitialMapping(); - /** - * @brief returns distance of the given logical qubit pair according to the - * current mapping - */ - double distanceOnArchitectureOfLogicalQubits(std::uint16_t control, - std::uint16_t target) { - return architecture->distance( - static_cast(locations.at(control)), - static_cast(locations.at(target))); - } - - /** - * @brief returns distance of the given physical qubit pair on the - * architecture - */ - double distanceOnArchitectureOfPhysicalQubits(std::uint16_t control, - std::uint16_t target) { - return architecture->distance(control, target); - } - /** * @brief map the logical qubit `target` to a free physical qubit, that is * nearest to the physical qubit `source` is mapped to diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 64737a993..148c92429 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -288,7 +288,7 @@ void HeuristicMapper::mapToMinDistance(const std::uint16_t source, for (std::uint16_t i = 0; i < architecture->getNqubits(); ++i) { if (qubits.at(i) == DEFAULT_POSITION) { // TODO: Consider fidelity here if available - const auto distance = distanceOnArchitectureOfPhysicalQubits( + const auto distance = architecture->distance( static_cast(locations.at(source)), i); if (distance < min) { min = distance; @@ -1112,9 +1112,9 @@ void HeuristicMapper::updateSharedSwaps(const Edge& swap, std::size_t layer, const auto q1 = node.qubits.at(swap.first); const auto q2 = node.qubits.at(swap.second); if (q1 == -1 || q2 == -1 || - consideredQubits.find(static_cast(q1)) != + consideredQubits.find(static_cast(q1)) == consideredQubits.end() || - consideredQubits.find(static_cast(q2)) != + consideredQubits.find(static_cast(q2)) == consideredQubits.end()) { // the given swap can only be a shared swap if both qubits are active in // the current layer @@ -1486,6 +1486,7 @@ double HeuristicMapper::heuristicFidelityBestLocation(std::size_t layer, void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicMapper::Node& node) { const auto& config = results.config; + node.lookaheadPenalty = 0.; auto nextLayer = getNextLayer(layer); double factor = config.firstLookaheadFactor; @@ -1520,6 +1521,7 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; + const auto [forwardMult, reverseMult] = multiplicity; const auto loc1 = node.locations.at(q1); const auto loc2 = node.locations.at(q2); @@ -1530,8 +1532,14 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, 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( + if (forwardMult > 0) { + min = std::min(min, architecture->distance( j, static_cast(loc2))); + } + if (reverseMult > 0) { + min = std::min(min, architecture->distance( + static_cast(loc2), j)); + } } } penalty = std::max(penalty, min); @@ -1540,14 +1548,27 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, 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( + if (forwardMult > 0) { + min = std::min(min, architecture->distance( static_cast(loc1), j)); + } + if (reverseMult > 0) { + min = std::min(min, architecture->distance( + j, static_cast(loc1))); + } } } penalty = std::max(penalty, min); } else { - const auto cost = architecture->distance( - static_cast(loc1), static_cast(loc2)); + double cost = std::numeric_limits::max(); + if (forwardMult > 0) { + cost = std::min(cost, architecture->distance( + static_cast(loc1), static_cast(loc2))); + } + if (reverseMult > 0) { + cost = std::min(cost, architecture->distance( + static_cast(loc2), static_cast(loc1))); + } penalty = std::max(penalty, cost); } } @@ -1562,6 +1583,7 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { const auto& [q1, q2] = edge; + const auto [forwardMult, reverseMult] = multiplicity; const auto loc1 = node.locations.at(q1); const auto loc2 = node.locations.at(q2); @@ -1572,8 +1594,14 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, 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( + if (forwardMult > 0) { + min = std::min(min, architecture->distance( j, static_cast(loc2))); + } + if (reverseMult > 0) { + min = std::min(min, architecture->distance( + static_cast(loc2), j)); + } } } penalty += min; @@ -1582,15 +1610,28 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, 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( + if (forwardMult > 0) { + min = std::min(min, architecture->distance( static_cast(loc1), j)); + } + if (reverseMult > 0) { + min = std::min(min, architecture->distance( + j, static_cast(loc1))); + } } } - penalty = min; + penalty += min; } else { - const auto cost = architecture->distance( - static_cast(loc1), static_cast(loc2)); - penalty = cost; + double cost = std::numeric_limits::max(); + if (forwardMult > 0) { + cost = std::min(cost, architecture->distance( + static_cast(loc1), static_cast(loc2))); + } + if (reverseMult > 0) { + cost = std::min(cost, architecture->distance( + static_cast(loc2), static_cast(loc1))); + } + penalty += cost; } } diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 7d3c4a176..dc929d239 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -189,15 +189,15 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { class InternalsTest : public HeuristicMapper, public testing::Test { protected: - static Architecture - defaultArch; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + static Architecture defaultArch; InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } }; -Architecture InternalsTest::defaultArch{ - 1, {}}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +Architecture InternalsTest::defaultArch{1, {}}; TEST_F(InternalsTest, NodeCostCalculation) { results.config.heuristic = Heuristic::GateCountMaxDistance; @@ -206,6 +206,9 @@ TEST_F(InternalsTest, NodeCostCalculation) { architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); qc = qc::QuantumComputation{5}; + // layer 0 distances: + // 0-1: 2 swaps & 2 reversals + // 2-3: 0 swaps & 1 reversals qc.cx(qc::Control{0}, 1); qc.cx(qc::Control{0}, 1); qc.cx(qc::Control{0}, 1); @@ -214,6 +217,7 @@ TEST_F(InternalsTest, NodeCostCalculation) { qc.cx(qc::Control{1}, 0); qc.cx(qc::Control{1}, 0); qc.cx(qc::Control{3}, 2); + // Architecture::distance currently counts at most 1 reversal per qubit pair createLayers(); EXPECT_EQ(layers.size(), 1) @@ -279,6 +283,99 @@ TEST_F(InternalsTest, NodeCostCalculation) { FLOAT_TOLERANCE); } +TEST_F(InternalsTest, NodeLookaheadCalculation) { + results.config.heuristic = Heuristic::GateCountMaxDistance; + results.config.lookaheadHeuristic = LookaheadHeuristic::None; + results.config.layering = Layering::Disjoint2qBlocks; + + architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); + qc = qc::QuantumComputation{5}; + // layer 0 distances: + // 0-1: 2 swaps & 2 reversals + // 2-3: 0 swaps & 1 reversals + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{0}, 1); + qc.cx(qc::Control{1}, 0); + qc.cx(qc::Control{1}, 0); + qc.cx(qc::Control{3}, 2); + + // layer 1 distances: + // 0-4: 2 swaps & 0 reversals + // 1-2: 1 swaps & 1 reversals + qc.cx(qc::Control{0}, 4); + qc.cx(qc::Control{0}, 4); + qc.cx(qc::Control{1}, 2); + + // layer 2 distances: + // 0-1: 2 swaps & 0 reversals + qc.cx(qc::Control{0}, 1); + + // layer 3 distances: + // 0-4: 2 swaps & 0 reversals + qc.cx(qc::Control{4}, 0); + + // Architecture::distance currently counts at most 1 reversal per qubit pair + + createLayers(); + + EXPECT_EQ(layers.size(), 4) + << "layering failed, not able to test node cost calculation"; + + const std::vector swaps{Exchange(0, 1, qc::OpType::Teleportation), + Exchange(1, 2, SWAP)}; + + HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, + {{2, 3}}, 5., 0); + EXPECT_NEAR(node.lookaheadPenalty, 0., FLOAT_TOLERANCE); + + results.config.firstLookaheadFactor = 0.75; + results.config.lookaheadFactor = 0.5; + + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; + results.config.nrLookaheads = 1; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + results.config.nrLookaheads = 2; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + results.config.nrLookaheads = 3; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + results.config.nrLookaheads = 4; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountSumDistance; + results.config.nrLookaheads = 1; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); + results.config.nrLookaheads = 2; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + results.config.nrLookaheads = 3; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + results.config.nrLookaheads = 4; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + + node.qubits = {4, 3, 1, -1, -1}; + node.locations = {-1, 2, -1, 1, 0}; + + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; + results.config.nrLookaheads = 1; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); + + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountSumDistance; + results.config.nrLookaheads = 1; + updateLookaheadPenalty(0, node); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); +} + class TestHeuristics : public testing::TestWithParam> { protected: @@ -296,826 +393,7 @@ class TestHeuristics std::unique_ptr ibmQX5Mapper; Configuration settings{}; - static std::unordered_map> - optimalSolutions; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - - static void SetUpTestSuite() { - // prepare precalculated optimal solutions to compare against - optimalSolutions = { - {"3_17_13", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 0, SWAP}}, {}, 0., 0., 1}}}, - {"ex-1_166", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}}}, - {"ham3_102", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, - {"miller_11", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, - {"4gt11_84", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0, 1, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}}}, - {"4mod5-v0_20", - {{0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, - 0, - {}, - {}, - {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}, {3, 4, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, - {"mod5d1_63", - {{0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{0, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 4, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{3, 4, SWAP}, {1, 3, SWAP}, {0, 1, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{1, 0, SWAP}, {1, 2, SWAP}, {2, 3, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, - 0, - {}, - {}, - {{15, 0, SWAP}, {15, 2, SWAP}, {2, 3, SWAP}}, - {}, - 0., - 0., - 3}}}, - {"ising_model_10", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}}}, - {"rd73_140", - {{0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, - 0, - {}, - {}, - {{1, 2, SWAP}, - {2, 3, SWAP}, - {3, 4, SWAP}, - {5, 4, SWAP}, - {6, 7, SWAP}}, - {}, - 0., - 0., - 5}, - {0, - 0, - {}, - {}, - {{1, 0, SWAP}, - {1, 2, SWAP}, - {2, 3, SWAP}, - {6, 5, SWAP}, - {5, 4, SWAP}}, - {}, - 0., - 0., - 5}, - {0, 0, {}, {}, {{6, 5, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{5, 4, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{3, 4, SWAP}, {2, 3, SWAP}, {1, 2, SWAP}}, - {}, - 0., - 0., - 3}, - {0, - 0, - {}, - {}, - {{8, 7, SWAP}, - {6, 7, SWAP}, - {6, 5, SWAP}, - {1, 2, SWAP}, - {2, 3, SWAP}, - {3, 4, SWAP}}, - {}, - 0., - 0., - 6}, - {0, - 0, - {}, - {}, - {{1, 0, SWAP}, {1, 2, SWAP}, {5, 4, SWAP}, {3, 4, SWAP}}, - {}, - 0., - 0., - 4}, - {0, 0, {}, {}, {{2, 3, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{9, 10, SWAP}, - {11, 10, SWAP}, - {12, 11, SWAP}, - {12, 5, SWAP}, - {5, 4, SWAP}, - {3, 4, SWAP}, - {2, 3, SWAP}, - {5, 4, SWAP}}, - {}, - 0., - 0., - 8}, - {0, 0, {}, {}, {{1, 0, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{6, 5, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{6, 5, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{1, 0, SWAP}, {6, 5, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{3, 4, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{6, 5, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{3, 4, SWAP}, {15, 2, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{5, 4, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{5, 4, SWAP}, {15, 0, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}, {5, 4, SWAP}}, {}, 0., 0., 2}, - {0, - 0, - {}, - {}, - {{3, 4, SWAP}, {15, 0, SWAP}, {15, 14, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 14, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{6, 7, SWAP}, - {6, 5, SWAP}, - {5, 4, SWAP}, - {3, 4, SWAP}, - {15, 0, SWAP}}, - {}, - 0., - 0., - 5}, - {0, - 0, - {}, - {}, - {{6, 5, SWAP}, - {5, 4, SWAP}, - {15, 0, SWAP}, - {15, 2, SWAP}, - {2, 3, SWAP}}, - {}, - 0., - 0., - 5}, - {0, 0, {}, {}, {{1, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{2, 3, SWAP}, {15, 2, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{15, 2, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 3, SWAP}, {1, 2, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{1, 2, SWAP}, {2, 3, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{15, 2, SWAP}}, {}, 0., 0., 1}, - {0, - 0, - {}, - {}, - {{8, 7, SWAP}, - {6, 7, SWAP}, - {6, 5, SWAP}, - {5, 4, SWAP}, - {3, 4, SWAP}, - {1, 0, SWAP}}, - {}, - 0., - 0., - 6}, - {0, - 0, - {}, - {}, - {{15, 0, SWAP}, {15, 14, SWAP}, {13, 14, SWAP}}, - {}, - 0., - 0., - 3}, - {0, - 0, - {}, - {}, - {{13, 14, SWAP}, {2, 3, SWAP}, {15, 0, SWAP}}, - {}, - 0., - 0., - 3}, - {0, 0, {}, {}, {{15, 14, SWAP}, {13, 4, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2, 3, SWAP}, {15, 14, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{2, 3, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{15, 14, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{2, 3, SWAP}, {3, 14, SWAP}}, {}, 0., 0., 2}, - {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {}, {}, 0., 0., 0}, - {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}, - {0, 0, {}, {}, {{13, 14, SWAP}}, {}, 0., 0., 1}}}}; - const std::unordered_map>> - optimalSolutionQubits{ - {"3_17_13", - {{0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {1, 0, 2}, - {1, 2, 0}, - {1, 2, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 0, 1}, - {2, 1, 0}, - {2, 0, 1}, - {2, 0, 1}, - {2, 1, 0}, - {1, 0, 2}, - {1, 2, 0}, - {1, 2, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {2, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"ex-1_166", - {{0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {1, 0, 2}, - {1, 0, 2}, - {1, 2, 0}, - {1, 2, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {0, 1, 2}, - {0, 1, 2}, - {1, 0, 2}, - {1, 0, 2}, - {0, 1, 2}, - {1, 0, 2}, - {1, 0, 2}, - {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"ham3_102", - {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, - {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, - {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, - {1, 2, 0}, {1, 2, 0}, {1, 2, 0}}}, - {"miller_11", - {{0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {0, 1, 2}, - {1, 0, 2}, - {1, 2, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {2, 1, 0}, - {0, 1, 2}, - {0, 1, 2}, - {0, 2, 1}, - {0, 2, 1}, - {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {2, 0, 1}, - {2, 1, 0}, - {2, 1, 0}, - {1, 2, 0}, - {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, 0}, - {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, 0}, - {1, 2, 0}, - {2, 1, 0}, - {1, 2, 0}, - {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"4gt11_84", {{0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {2, 1, 0, 3, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {1, 0, 2, -1, 4}, {1, 2, 0, -1, 4}, {2, 1, 0, -1, 4}, - {2, 0, 1, -1, 4}, {4, 2, 1, 0, 3}, {0, 1, 2, -1, 4}, - {0, 1, 2, -1, 4}, {0, 2, 1, -1, 4}, {0, 2, 1, -1, 4}, - {2, 0, 1, -1, 4}, {2, 0, 1, -1, 4}, {2, 1, 0, 3, 4}}}, - {"4mod5-v0_20", - {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, - {0, 2, 4, 3, 1}, {0, 4, 2, 3, 1}, {0, 4, 1, 3, 2}, - {0, 4, 2, 3, 1}, {0, 4, 2, 3, 1}, {4, 0, 2, 1, 3}, - {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, - {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, - {4, 2, 0, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, - {0, 2, 3, 1, 4}, {0, 3, 2, 4, 1}, {0, 3, 4, 2, 1}, - {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {0, 3, 4, 2, 1}}}, - {"mod5d1_63", - {{0, 2, 1, 3, 4}, - {0, 2, 1, 3, 4}, - {1, 2, 0, 3, 4}, - {1, 2, 0, 3, 4}, - {1, 2, 0, 3, 4}, - {1, 2, 4, 3, 0}, - {4, 2, 1, 3, 0}, - {4, 2, 0, 3, 1}, - {4, 2, 1, 3, 0}, - {4, 2, 1, 3, 0}, - {4, 2, 0, 3, 1}, - {4, 0, 2, 1, 3}, - {4, 1, 2, 0, 3}, - {4, 0, 2, 1, 3}, - {4, 0, 2, 1, 3}, - {4, 0, 2, 1, 3}, - {4, 1, 2, 0, 3}, - {4, 1, 2, 0, 3}, - {4, 0, 2, 1, 3}, - {4, 1, 2, 0, 3}, - {4, 1, 2, 0, 3}, - {4, 0, 2, 1, 3}, - {0, 2, 1, 3, 4}, - {0, 2, 3, 1, 4}, - {2, 3, 1, 0, 4}, - {2, 3, 1, 0, 4}, - {2, 3, 1, 0, 4}, - {2, 3, 1, 4, 0}, - {2, 3, 4, 1, 0}, - {2, 3, 4, 0, 1}, - {2, 3, 4, 1, 0}, - {2, 3, 4, 1, 0}, - {-1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4}}}, - {"ising_model_10", - {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}, - {"rd73_140", - {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 2, 3, 4, 5, 1, 7, 6, 8, 9}, - {2, 3, 4, 0, 7, 5, 1, 6, 8, 9}, - {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, - {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, - {2, 3, 4, 0, 7, 1, 5, 6, 8, 9}, - {2, 7, 3, 4, 0, 1, 5, 6, 8, 9}, - {2, 3, 4, 0, 7, 8, 1, 5, 6, 9}, - {3, 4, 2, 8, 0, 7, 1, 5, 6, 9}, - {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, - {3, 4, 8, 7, 2, 0, 1, 5, 6, 9}, - {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, - {3, 8, 4, 2, 7, 0, 1, 5, 6, 9}, - {3, 8, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {8, 3, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {8, 3, 9, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {8, 9, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {8, 9, 3, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 7, 4, 3, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 7, 3, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 2, 7, 1, 5, 6, -1, -1, -1, 0}, - {9, 8, -1, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, -1, 8, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {4, 8, -1, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {9, 8, -1, 7, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, - {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {4, 7, 8, 5, -1, 2, 3, 1, 6, -1, -1, -1, 0, -1, -1, 9}, - {9, 7, 5, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 4, 5, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, - {5, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, -1, 7}, - {7, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, 5}, - {-1, 9, 6, 8, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, - {-1, 9, 8, 6, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}}}}; - for (const auto& [circuit, qubits] : optimalSolutionQubits) { - if (optimalSolutions.find(circuit) == optimalSolutions.end()) { - throw std::runtime_error( - "Missing precalculated optimal solutions for circuit " + circuit); - } - if (optimalSolutions.at(circuit).size() != qubits.size()) { - throw std::runtime_error( - "Missing some precalculated optimal solutions for circuit " + - circuit); - } - for (std::size_t i = 0; i < qubits.size(); ++i) { - std::fill(optimalSolutions.at(circuit).at(i).qubits.begin(), - optimalSolutions.at(circuit).at(i).qubits.end(), -1); - std::fill(optimalSolutions.at(circuit).at(i).locations.begin(), - optimalSolutions.at(circuit).at(i).locations.end(), -1); - for (std::size_t j = 0; j < qubits.at(i).size(); ++j) { - if (qubits.at(i).at(j) >= 0) { - optimalSolutions.at(circuit).at(i).qubits.at(j) = - qubits.at(i).at(j); - optimalSolutions.at(circuit).at(i).locations.at( - static_cast(qubits.at(i).at(j))) = - static_cast(j); - } - } - } - } - } + static const std::unordered_map>> optimalSolutions; void SetUp() override { std::string cn = std::get<1>(GetParam()); @@ -1143,9 +421,151 @@ class TestHeuristics } }; -std::unordered_map> - TestHeuristics:: - optimalSolutions{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +const std::unordered_map>> TestHeuristics::optimalSolutions{ + {"3_17_13", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 2, 0}, + {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 0, 1}, {2, 1, 0}, + {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 1}, + {2, 0, 1}, {2, 1, 0}, {1, 0, 2}, {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, + {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ex-1_166", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, + {1, 0, 2}, {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, + {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, + {1, 0, 2}, {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ham3_102", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, + {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {1, 2, 0}}}, + {"miller_11", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {1, 0, 2}, {1, 2, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, + {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, + {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, + {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {0, 1, 2}, {0, 1, 2}, + {0, 2, 1}, {0, 2, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {1, 2, 0}, {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {1, 2, 0}, {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"4gt11_84", {{0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {2, 1, 0, 3, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {1, 0, 2, -1, 4}, {1, 2, 0, -1, 4}, {2, 1, 0, -1, 4}, + {2, 0, 1, -1, 4}, {4, 2, 1, 0, 3}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 2, 1, -1, 4}, {0, 2, 1, -1, 4}, + {2, 0, 1, -1, 4}, {2, 0, 1, -1, 4}, {2, 1, 0, 3, 4}}}, + {"4mod5-v0_20", + {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, + {0, 2, 4, 3, 1}, {0, 4, 2, 3, 1}, {0, 4, 1, 3, 2}, + {0, 4, 2, 3, 1}, {0, 4, 2, 3, 1}, {4, 0, 2, 1, 3}, + {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, + {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, + {4, 2, 0, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, + {0, 2, 3, 1, 4}, {0, 3, 2, 4, 1}, {0, 3, 4, 2, 1}, + {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {0, 3, 4, 2, 1}}}, + {"mod5d1_63", + {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {1, 2, 0, 3, 4}, {1, 2, 0, 3, 4}, + {1, 2, 0, 3, 4}, {1, 2, 4, 3, 0}, {4, 2, 1, 3, 0}, {4, 2, 0, 3, 1}, + {4, 2, 1, 3, 0}, {4, 2, 1, 3, 0}, {4, 2, 0, 3, 1}, {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {4, 0, 2, 1, 3}, {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {4, 1, 2, 0, 3}, + {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 3, 1, 4}, + {2, 3, 1, 0, 4}, {2, 3, 1, 0, 4}, {2, 3, 1, 0, 4}, {2, 3, 1, 4, 0}, + {2, 3, 4, 1, 0}, {2, 3, 4, 0, 1}, {2, 3, 4, 1, 0}, {2, 3, 4, 1, 0}, + {-1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4}}}, + {"ising_model_10", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}, + {"rd73_140", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 2, 3, 4, 5, 1, 7, 6, 8, 9}, + {2, 3, 4, 0, 7, 5, 1, 6, 8, 9}, {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, + {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, {2, 3, 4, 0, 7, 1, 5, 6, 8, 9}, + {2, 7, 3, 4, 0, 1, 5, 6, 8, 9}, {2, 3, 4, 0, 7, 8, 1, 5, 6, 9}, + {3, 4, 2, 8, 0, 7, 1, 5, 6, 9}, {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 4, 8, 7, 2, 0, 1, 5, 6, 9}, {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 4, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 4, 3, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 3, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 2, 7, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, -1, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, -1, 8, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, 8, -1, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 8, -1, 7, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, 7, 8, 5, -1, 2, 3, 1, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 7, 5, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 4, 5, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {5, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, -1, 7}, + {7, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, 5}, + {-1, 9, 6, 8, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 8, 6, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}} + } +}; INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, @@ -1286,7 +706,18 @@ TEST_P(TestHeuristics, HeuristicProperties) { "Missing precalculated optimal solution for circuit " + circuitName); } - EXPECT_TRUE(finalSolutionNode == optimalSolutions.at(circuitName).at(i)) + std::size_t finalLayoutLastIndex = 0; + for (std::size_t j = finalSolutionNode.qubits.size()-1; j > 0; --j) { + if (finalSolutionNode.qubits.at(j) != -1) { + finalLayoutLastIndex = j; + break; + } + } + std::vector finalLayout{}; + std::copy(finalSolutionNode.qubits.begin(), + finalSolutionNode.qubits.begin() + finalLayoutLastIndex + 1, + std::back_inserter(finalLayout)); + EXPECT_EQ(finalLayout, optimalSolutions.at(circuitName).at(i)) << "Heuristic " << toString(settings.heuristic) << " did not find the optimal solution " << layerNames.at(i); } @@ -1865,11 +1296,11 @@ TEST(Functionality, DataLogger) { EXPECT_LT(node.locations.at(k), architecture.getNqubits()); if (node.qubits.at(k) >= 0) { - EXPECT_EQ(node.locations[static_cast(node.qubits.at(k))], + EXPECT_EQ(node.locations.at(static_cast(node.qubits.at(k))), static_cast(k)); } if (node.locations.at(k) >= 0) { - EXPECT_EQ(node.qubits[static_cast(node.locations.at(k))], + EXPECT_EQ(node.qubits.at(static_cast(node.locations.at(k))), static_cast(k)); } } @@ -2198,6 +1629,7 @@ class HeuristicTest5Q : public testing::TestWithParam { ibmqLondon.loadProperties(testCalibrationDir + "ibmq_london.csv"); ibmqYorktownMapper = std::make_unique(qc, ibmqYorktown); ibmqLondonMapper = std::make_unique(qc, ibmqLondon); + settings.verbose = true; settings.debug = true; settings.iterativeBidirectionalRouting = true; From 0bb568dba301132de5d901c7d9a1f1c50ab87c91 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Jan 2024 05:24:45 +0000 Subject: [PATCH 30/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heuristic/HeuristicMapper.cpp | 44 +-- test/test_heuristic.cpp | 531 ++++++++++++++++++++---------- 2 files changed, 374 insertions(+), 201 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 148c92429..0f7c8a4be 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -1487,8 +1487,8 @@ void HeuristicMapper::updateLookaheadPenalty(const std::size_t layer, HeuristicMapper::Node& node) { const auto& config = results.config; node.lookaheadPenalty = 0.; - auto nextLayer = getNextLayer(layer); - double factor = config.firstLookaheadFactor; + auto nextLayer = getNextLayer(layer); + double factor = config.firstLookaheadFactor; for (std::size_t i = 0; i < config.nrLookaheads; ++i) { if (nextLayer == std::numeric_limits::max()) { @@ -1520,7 +1520,7 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, double penalty = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; + const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto loc1 = node.locations.at(q1); @@ -1534,11 +1534,11 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, // TODO: Consider fidelity here if available if (forwardMult > 0) { min = std::min(min, architecture->distance( - j, static_cast(loc2))); + j, static_cast(loc2))); } if (reverseMult > 0) { min = std::min(min, architecture->distance( - static_cast(loc2), j)); + static_cast(loc2), j)); } } } @@ -1550,11 +1550,11 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, // TODO: Consider fidelity here if available if (forwardMult > 0) { min = std::min(min, architecture->distance( - static_cast(loc1), j)); + static_cast(loc1), j)); } if (reverseMult > 0) { min = std::min(min, architecture->distance( - j, static_cast(loc1))); + j, static_cast(loc1))); } } } @@ -1562,12 +1562,14 @@ HeuristicMapper::lookaheadGateCountMaxDistance(const std::size_t layer, } else { double cost = std::numeric_limits::max(); if (forwardMult > 0) { - cost = std::min(cost, architecture->distance( - static_cast(loc1), static_cast(loc2))); + cost = std::min( + cost, architecture->distance(static_cast(loc1), + static_cast(loc2))); } if (reverseMult > 0) { - cost = std::min(cost, architecture->distance( - static_cast(loc2), static_cast(loc1))); + cost = std::min( + cost, architecture->distance(static_cast(loc2), + static_cast(loc1))); } penalty = std::max(penalty, cost); } @@ -1582,7 +1584,7 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, double penalty = 0.; for (const auto& [edge, multiplicity] : twoQubitMultiplicities.at(layer)) { - const auto& [q1, q2] = edge; + const auto& [q1, q2] = edge; const auto [forwardMult, reverseMult] = multiplicity; const auto loc1 = node.locations.at(q1); @@ -1596,11 +1598,11 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, // TODO: Consider fidelity here if available if (forwardMult > 0) { min = std::min(min, architecture->distance( - j, static_cast(loc2))); + j, static_cast(loc2))); } if (reverseMult > 0) { min = std::min(min, architecture->distance( - static_cast(loc2), j)); + static_cast(loc2), j)); } } } @@ -1612,11 +1614,11 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, // TODO: Consider fidelity here if available if (forwardMult > 0) { min = std::min(min, architecture->distance( - static_cast(loc1), j)); + static_cast(loc1), j)); } if (reverseMult > 0) { min = std::min(min, architecture->distance( - j, static_cast(loc1))); + j, static_cast(loc1))); } } } @@ -1624,12 +1626,14 @@ HeuristicMapper::lookaheadGateCountSumDistance(const std::size_t layer, } else { double cost = std::numeric_limits::max(); if (forwardMult > 0) { - cost = std::min(cost, architecture->distance( - static_cast(loc1), static_cast(loc2))); + cost = std::min( + cost, architecture->distance(static_cast(loc1), + static_cast(loc2))); } if (reverseMult > 0) { - cost = std::min(cost, architecture->distance( - static_cast(loc2), static_cast(loc1))); + cost = std::min( + cost, architecture->distance(static_cast(loc2), + static_cast(loc1))); } penalty += cost; } diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index dc929d239..18be5df6e 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -190,7 +190,7 @@ getPathToRoot(std::vector& nodes, std::size_t nodeId) { class InternalsTest : public HeuristicMapper, public testing::Test { protected: // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - static Architecture defaultArch; + static Architecture defaultArch; InternalsTest() : HeuristicMapper(qc::QuantumComputation{1}, defaultArch) {} void SetUp() override { results = MappingResults{}; } @@ -284,9 +284,9 @@ TEST_F(InternalsTest, NodeCostCalculation) { } TEST_F(InternalsTest, NodeLookaheadCalculation) { - results.config.heuristic = Heuristic::GateCountMaxDistance; - results.config.lookaheadHeuristic = LookaheadHeuristic::None; - results.config.layering = Layering::Disjoint2qBlocks; + results.config.heuristic = Heuristic::GateCountMaxDistance; + results.config.lookaheadHeuristic = LookaheadHeuristic::None; + results.config.layering = Layering::Disjoint2qBlocks; architecture->loadCouplingMap(5, {{0, 1}, {1, 2}, {3, 1}, {4, 3}}); qc = qc::QuantumComputation{5}; @@ -301,24 +301,24 @@ TEST_F(InternalsTest, NodeLookaheadCalculation) { qc.cx(qc::Control{1}, 0); qc.cx(qc::Control{1}, 0); qc.cx(qc::Control{3}, 2); - + // layer 1 distances: // 0-4: 2 swaps & 0 reversals // 1-2: 1 swaps & 1 reversals qc.cx(qc::Control{0}, 4); qc.cx(qc::Control{0}, 4); qc.cx(qc::Control{1}, 2); - + // layer 2 distances: // 0-1: 2 swaps & 0 reversals qc.cx(qc::Control{0}, 1); - + // layer 3 distances: // 0-4: 2 swaps & 0 reversals qc.cx(qc::Control{4}, 0); - + // Architecture::distance currently counts at most 1 reversal per qubit pair - + createLayers(); EXPECT_EQ(layers.size(), 4) @@ -330,50 +330,79 @@ TEST_F(InternalsTest, NodeLookaheadCalculation) { HeuristicMapper::Node node(0, 0, {4, 3, 1, 2, 0}, {4, 2, 3, 1, 0}, swaps, {{2, 3}}, 5., 0); EXPECT_NEAR(node.lookaheadPenalty, 0., FLOAT_TOLERANCE); - + results.config.firstLookaheadFactor = 0.75; results.config.lookaheadFactor = 0.5; - + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; - results.config.nrLookaheads = 1; + results.config.nrLookaheads = 1; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); results.config.nrLookaheads = 2; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); results.config.nrLookaheads = 3; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); results.config.nrLookaheads = 4; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); - + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountSumDistance; - results.config.nrLookaheads = 1; + results.config.nrLookaheads = 1; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), + FLOAT_TOLERANCE); results.config.nrLookaheads = 2; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); results.config.nrLookaheads = 3; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); results.config.nrLookaheads = 4; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), FLOAT_TOLERANCE); - - node.qubits = {4, 3, 1, -1, -1}; + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (3 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE) + + 0.75 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP) + + 0.75 * 0.5 * 0.5 * (2 * COST_UNIDIRECTIONAL_SWAP), + FLOAT_TOLERANCE); + + node.qubits = {4, 3, 1, -1, -1}; node.locations = {-1, 2, -1, 1, 0}; - + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountMaxDistance; - results.config.nrLookaheads = 1; + results.config.nrLookaheads = 1; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); - + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), + FLOAT_TOLERANCE); + results.config.lookaheadHeuristic = LookaheadHeuristic::GateCountSumDistance; - results.config.nrLookaheads = 1; + results.config.nrLookaheads = 1; updateLookaheadPenalty(0, node); - EXPECT_NEAR(node.lookaheadPenalty, 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), FLOAT_TOLERANCE); + EXPECT_NEAR(node.lookaheadPenalty, + 0.75 * (2 * COST_UNIDIRECTIONAL_SWAP + COST_DIRECTION_REVERSE), + FLOAT_TOLERANCE); } class TestHeuristics @@ -393,7 +422,9 @@ class TestHeuristics std::unique_ptr ibmQX5Mapper; Configuration settings{}; - static const std::unordered_map>> optimalSolutions; + static const std::unordered_map>> + optimalSolutions; void SetUp() override { std::string cn = std::get<1>(GetParam()); @@ -421,151 +452,287 @@ class TestHeuristics } }; -const std::unordered_map>> TestHeuristics::optimalSolutions{ - {"3_17_13", - {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 2, 0}, - {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 0, 1}, {2, 1, 0}, - {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 1}, - {2, 0, 1}, {2, 1, 0}, {1, 0, 2}, {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, - {2, 1, 0}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {2, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, - {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"ex-1_166", - {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, - {1, 0, 2}, {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, - {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, - {1, 0, 2}, {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"ham3_102", - {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, - {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, - {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, - {1, 2, 0}, {1, 2, 0}, {1, 2, 0}}}, - {"miller_11", - {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, - {0, 1, 2}, {1, 0, 2}, {1, 2, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, - {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, - {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, - {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {2, 1, 0}, {0, 1, 2}, {0, 1, 2}, - {0, 2, 1}, {0, 2, 1}, - {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, - {2, 0, 1}, {2, 1, 0}, {2, 1, 0}, {1, 2, 0}, {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, 0}, {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {1, 2, 0}, {1, 2, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, - {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, - {"4gt11_84", {{0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {2, 1, 0, 3, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, - {1, 0, 2, -1, 4}, {1, 2, 0, -1, 4}, {2, 1, 0, -1, 4}, - {2, 0, 1, -1, 4}, {4, 2, 1, 0, 3}, {0, 1, 2, -1, 4}, - {0, 1, 2, -1, 4}, {0, 2, 1, -1, 4}, {0, 2, 1, -1, 4}, - {2, 0, 1, -1, 4}, {2, 0, 1, -1, 4}, {2, 1, 0, 3, 4}}}, - {"4mod5-v0_20", - {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, - {0, 2, 4, 3, 1}, {0, 4, 2, 3, 1}, {0, 4, 1, 3, 2}, - {0, 4, 2, 3, 1}, {0, 4, 2, 3, 1}, {4, 0, 2, 1, 3}, - {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, - {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, - {4, 2, 0, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, - {0, 2, 3, 1, 4}, {0, 3, 2, 4, 1}, {0, 3, 4, 2, 1}, - {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {0, 3, 4, 2, 1}}}, - {"mod5d1_63", - {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {1, 2, 0, 3, 4}, {1, 2, 0, 3, 4}, - {1, 2, 0, 3, 4}, {1, 2, 4, 3, 0}, {4, 2, 1, 3, 0}, {4, 2, 0, 3, 1}, - {4, 2, 1, 3, 0}, {4, 2, 1, 3, 0}, {4, 2, 0, 3, 1}, {4, 0, 2, 1, 3}, - {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {4, 0, 2, 1, 3}, {4, 0, 2, 1, 3}, - {4, 1, 2, 0, 3}, {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {4, 1, 2, 0, 3}, - {4, 1, 2, 0, 3}, {4, 0, 2, 1, 3}, {0, 2, 1, 3, 4}, {0, 2, 3, 1, 4}, - {2, 3, 1, 0, 4}, {2, 3, 1, 0, 4}, {2, 3, 1, 0, 4}, {2, 3, 1, 4, 0}, - {2, 3, 4, 1, 0}, {2, 3, 4, 0, 1}, {2, 3, 4, 1, 0}, {2, 3, 4, 1, 0}, - {-1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4}}}, - {"ising_model_10", - {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}, - {"rd73_140", - {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 2, 3, 4, 5, 1, 7, 6, 8, 9}, - {2, 3, 4, 0, 7, 5, 1, 6, 8, 9}, {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, - {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, {2, 3, 4, 0, 7, 1, 5, 6, 8, 9}, - {2, 7, 3, 4, 0, 1, 5, 6, 8, 9}, {2, 3, 4, 0, 7, 8, 1, 5, 6, 9}, - {3, 4, 2, 8, 0, 7, 1, 5, 6, 9}, {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, - {3, 4, 8, 7, 2, 0, 1, 5, 6, 9}, {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, - {3, 8, 4, 2, 7, 0, 1, 5, 6, 9}, - {3, 8, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {8, 3, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {8, 3, 9, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {8, 9, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {8, 9, 3, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 7, 4, 3, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 7, 3, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, - {9, 8, 4, 3, 2, 7, 1, 5, 6, -1, -1, -1, 0}, - {9, 8, -1, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, -1, 8, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {4, 8, -1, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, - {9, 8, -1, 7, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, - {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, - {4, 7, 8, 5, -1, 2, 3, 1, 6, -1, -1, -1, 0, -1, -1, 9}, - {9, 7, 5, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 4}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 4, 5, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, - {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, - {5, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, -1, 7}, - {7, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, 5}, - {-1, 9, 6, 8, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, - {-1, 9, 8, 6, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, - {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, - {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}} - } -}; +const std::unordered_map>> + TestHeuristics::optimalSolutions{ + {"3_17_13", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 0, 1}, + {2, 0, 1}, + {2, 1, 0}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {2, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2}, + {2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ex-1_166", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 0, 2}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"ham3_102", + {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, + {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {2, 1, 0}, {2, 1, 0}, {2, 0, 1}, {2, 1, 0}, + {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, {0, 1, 2}, {1, 0, 2}, {1, 0, 2}, + {1, 2, 0}, {1, 2, 0}, {1, 2, 0}}}, + {"miller_11", + {{0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {0, 1, 2}, + {1, 0, 2}, + {1, 2, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {2, 1, 0}, + {0, 1, 2}, + {0, 1, 2}, + {0, 2, 1}, + {0, 2, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1}, + {2, 0, 1}, + {2, 1, 0}, + {2, 1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {2, 1, 0}, + {1, 2, 0}, + {1, 2, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}, + {1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}}}, + {"4gt11_84", {{0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {2, 1, 0, 3, 4}, {0, 1, 2, -1, 4}, {0, 1, 2, -1, 4}, + {1, 0, 2, -1, 4}, {1, 2, 0, -1, 4}, {2, 1, 0, -1, 4}, + {2, 0, 1, -1, 4}, {4, 2, 1, 0, 3}, {0, 1, 2, -1, 4}, + {0, 1, 2, -1, 4}, {0, 2, 1, -1, 4}, {0, 2, 1, -1, 4}, + {2, 0, 1, -1, 4}, {2, 0, 1, -1, 4}, {2, 1, 0, 3, 4}}}, + {"4mod5-v0_20", + {{0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 4, 3, 1}, + {0, 4, 2, 3, 1}, {0, 4, 1, 3, 2}, {0, 4, 2, 3, 1}, {0, 4, 2, 3, 1}, + {4, 0, 2, 1, 3}, {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, + {4, 2, 0, 1, 3}, {4, 1, 0, 2, 3}, {4, 2, 0, 1, 3}, {4, 2, 0, 1, 3}, + {0, 2, 1, 3, 4}, {0, 2, 1, 3, 4}, {0, 2, 3, 1, 4}, {0, 3, 2, 4, 1}, + {0, 3, 4, 2, 1}, {0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {0, 3, 4, 2, 1}}}, + {"mod5d1_63", + {{0, 2, 1, 3, 4}, + {0, 2, 1, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 0, 3, 4}, + {1, 2, 4, 3, 0}, + {4, 2, 1, 3, 0}, + {4, 2, 0, 3, 1}, + {4, 2, 1, 3, 0}, + {4, 2, 1, 3, 0}, + {4, 2, 0, 3, 1}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {4, 0, 2, 1, 3}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {4, 1, 2, 0, 3}, + {4, 1, 2, 0, 3}, + {4, 0, 2, 1, 3}, + {0, 2, 1, 3, 4}, + {0, 2, 3, 1, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 0, 4}, + {2, 3, 1, 4, 0}, + {2, 3, 4, 1, 0}, + {2, 3, 4, 0, 1}, + {2, 3, 4, 1, 0}, + {2, 3, 4, 1, 0}, + {-1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4}}}, + {"ising_model_10", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}, + {"rd73_140", + {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {0, 2, 3, 4, 5, 1, 7, 6, 8, 9}, + {2, 3, 4, 0, 7, 5, 1, 6, 8, 9}, + {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, + {2, 3, 4, 0, 1, 7, 5, 6, 8, 9}, + {2, 3, 4, 0, 7, 1, 5, 6, 8, 9}, + {2, 7, 3, 4, 0, 1, 5, 6, 8, 9}, + {2, 3, 4, 0, 7, 8, 1, 5, 6, 9}, + {3, 4, 2, 8, 0, 7, 1, 5, 6, 9}, + {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 4, 8, 7, 2, 0, 1, 5, 6, 9}, + {3, 4, 8, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 4, 2, 7, 0, 1, 5, 6, 9}, + {3, 8, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {8, 3, 9, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {8, 9, 3, 4, 7, 2, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 4, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 4, 3, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 7, 3, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 3, 7, 4, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 7, 1, 2, 5, 6, -1, -1, -1, 0}, + {9, 8, 4, 3, 2, 7, 1, 5, 6, -1, -1, -1, 0}, + {9, 8, -1, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, -1, 8, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, -1, 8, 2, 3, 7, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {4, 8, -1, 2, 7, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 8, -1, 7, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 8, 7, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 7, 8, -1, 2, 3, 1, 5, 6, -1, -1, -1, 0, -1, -1, 4}, + {4, 7, 8, 5, -1, 2, 3, 1, 6, -1, -1, -1, 0, -1, -1, 9}, + {9, 7, 5, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 4}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 4, 5, 7, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 7, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 8}, + {9, 5, 8, 4, 3, -1, 2, 1, 6, -1, -1, -1, 0, -1, -1, 7}, + {5, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, -1, 7}, + {7, 9, 8, 6, 4, 3, -1, 2, 1, -1, -1, -1, 0, 5}, + {-1, 9, 6, 8, 4, 3, -1, 2, 1, -1, -1, -1, 0, -1, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 8, 6, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 5, 7}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 4, 7, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 6, 8, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 4, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 6, 7, 5}, + {-1, 9, 8, 4, -1, 3, -1, 2, 1, -1, -1, -1, 0, 7, 6, 5}}}}; INSTANTIATE_TEST_SUITE_P( Heuristic, TestHeuristics, @@ -707,7 +874,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { circuitName); } std::size_t finalLayoutLastIndex = 0; - for (std::size_t j = finalSolutionNode.qubits.size()-1; j > 0; --j) { + for (std::size_t j = finalSolutionNode.qubits.size() - 1; j > 0; --j) { if (finalSolutionNode.qubits.at(j) != -1) { finalLayoutLastIndex = j; break; @@ -1296,12 +1463,14 @@ TEST(Functionality, DataLogger) { EXPECT_LT(node.locations.at(k), architecture.getNqubits()); if (node.qubits.at(k) >= 0) { - EXPECT_EQ(node.locations.at(static_cast(node.qubits.at(k))), - static_cast(k)); + EXPECT_EQ( + node.locations.at(static_cast(node.qubits.at(k))), + static_cast(k)); } if (node.locations.at(k) >= 0) { - EXPECT_EQ(node.qubits.at(static_cast(node.locations.at(k))), - static_cast(k)); + EXPECT_EQ( + node.qubits.at(static_cast(node.locations.at(k))), + static_cast(k)); } } } From cd9fa90d1c447ce92cf8a51b8a415a91d5ecc280 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Fri, 12 Jan 2024 07:09:04 +0100 Subject: [PATCH 31/47] fixing case style of optimalSolutions --- test/test_heuristic.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index 18be5df6e..c505115f1 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -424,7 +424,7 @@ class TestHeuristics static const std::unordered_map>> - optimalSolutions; + OPTIMAL_SOLUTIONS; void SetUp() override { std::string cn = std::get<1>(GetParam()); @@ -453,7 +453,7 @@ class TestHeuristics }; const std::unordered_map>> - TestHeuristics::optimalSolutions{ + TestHeuristics::OPTIMAL_SOLUTIONS{ {"3_17_13", {{0, 1, 2}, {0, 1, 2}, @@ -867,8 +867,8 @@ TEST_P(TestHeuristics, HeuristicProperties) { // However, if a heuristic is both principally admissible and tight, // it is guaranteed to always find the same solution as any other such // heuristic. - if (optimalSolutions.find(circuitName) == optimalSolutions.end() || - optimalSolutions.at(circuitName).size() <= i) { + if (OPTIMAL_SOLUTIONS.find(circuitName) == OPTIMAL_SOLUTIONS.end() || + OPTIMAL_SOLUTIONS.at(circuitName).size() <= i) { throw std::runtime_error( "Missing precalculated optimal solution for circuit " + circuitName); @@ -884,7 +884,7 @@ TEST_P(TestHeuristics, HeuristicProperties) { std::copy(finalSolutionNode.qubits.begin(), finalSolutionNode.qubits.begin() + finalLayoutLastIndex + 1, std::back_inserter(finalLayout)); - EXPECT_EQ(finalLayout, optimalSolutions.at(circuitName).at(i)) + EXPECT_EQ(finalLayout, OPTIMAL_SOLUTIONS.at(circuitName).at(i)) << "Heuristic " << toString(settings.heuristic) << " did not find the optimal solution " << layerNames.at(i); } From 1c28eac071ba9624e7c6d08726143a7bc50d2246 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Sat, 13 Jan 2024 09:56:53 +0100 Subject: [PATCH 32/47] finish heuristic support for semidirectional architectures --- src/heuristic/HeuristicMapper.cpp | 46 +++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 0f7c8a4be..c89ae73de 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -834,20 +834,26 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, Node& node) { node.costFixedReversals = 0.; - if (!fidelityAwareHeur && node.validMappedTwoQubitGates.size() == - twoQubitMultiplicities.at(layer).size()) { - // only consider reversal costs as fixed in goal nodes - for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { - const auto [q1, q2] = edge; - const auto [forwardMult, reverseMult] = mult; - const auto physQ1 = static_cast(node.locations.at(q1)); - const auto physQ2 = static_cast(node.locations.at(q2)); + if (architecture->bidirectional() || fidelityAwareHeur || + node.validMappedTwoQubitGates.size() != + twoQubitMultiplicities.at(layer).size()) { + // costFixedReversals should only be non-zero in goal nodes for + // non-fidelity-aware heuristics and if there are unidirectional + // edges in the architecture + return; + } + + // only consider reversal costs as fixed in goal nodes + for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { + const auto [q1, q2] = edge; + const auto [forwardMult, reverseMult] = mult; + const auto physQ1 = static_cast(node.locations.at(q1)); + const auto physQ2 = static_cast(node.locations.at(q2)); - if (!architecture->isEdgeConnected({physQ1, physQ2})) { - node.costFixedReversals += forwardMult * COST_DIRECTION_REVERSE; - } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { - node.costFixedReversals += reverseMult * COST_DIRECTION_REVERSE; - } + if (!architecture->isEdgeConnected({physQ1, physQ2})) { + node.costFixedReversals += forwardMult * COST_DIRECTION_REVERSE; + } else if (!architecture->isEdgeConnected({physQ2, physQ1})) { + node.costFixedReversals += reverseMult * COST_DIRECTION_REVERSE; } } } @@ -860,8 +866,10 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { if (swap.op == qc::SWAP) { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else { + } else if (architecture->unidirectional() || !architecture->isEdgeConnected({swap.second, swap.first}) || !architecture->isEdgeConnected({swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; + } else { + node.costFixed += COST_BIDIRECTIONAL_SWAP; } } else if (swap.op == qc::Teleportation) { node.costFixed += COST_TELEPORTATION; @@ -1012,8 +1020,10 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else { + } else if (architecture->unidirectional() || !architecture->isEdgeConnected({swap.second, swap.first}) || !architecture->isEdgeConnected({swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; + } else { + node.costFixed += COST_BIDIRECTIONAL_SWAP; } } @@ -1224,7 +1234,8 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (node.validMappedTwoQubitGates.find(edge) != + if (!architecture->bidirectional() && + node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates if (!architecture->isEdgeConnected({physQ1, physQ2})) { @@ -1263,7 +1274,8 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (node.validMappedTwoQubitGates.find(edge) != + if (!architecture->bidirectional() && + node.validMappedTwoQubitGates.find(edge) != node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates if (!architecture->isEdgeConnected({physQ1, physQ2})) { From 477a4295d746b1cfaa9334e7a78ad561ab10d39b Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Sat, 13 Jan 2024 10:18:13 +0100 Subject: [PATCH 33/47] isEdgeBidirectional and considerDirection in isEdgeConnected --- include/Architecture.hpp | 13 +++++++++-- src/heuristic/HeuristicMapper.cpp | 37 +++++++++++-------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index b5ba189f2..334da9e11 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -240,8 +240,17 @@ class Architecture { createDistanceTable(); } - [[nodiscard]] bool isEdgeConnected(const Edge& edge) const { - return couplingMap.find(edge) != couplingMap.end(); + [[nodiscard]] bool isEdgeConnected(const Edge& edge, const bool considerDirection = true) const { + if (considerDirection) { + return couplingMap.find(edge) != couplingMap.end(); + } + return couplingMap.find(edge) != couplingMap.end() || + couplingMap.find({edge.second, edge.first}) != couplingMap.end(); + } + + [[nodiscard]] bool isEdgeBidirectional(const Edge& edge) const { + return couplingMap.find(edge) != couplingMap.end() && + couplingMap.find({edge.second, edge.first}) != couplingMap.end(); } CouplingMap& getCurrentTeleportations() { return currentTeleportations; } diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index c89ae73de..6ba021268 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -370,11 +370,8 @@ void HeuristicMapper::routeCircuit() { std::clog << "SWAP: " << swap.first << " <-> " << swap.second << "\n"; } - if (!architecture->isEdgeConnected({swap.first, swap.second}) && - !architecture->isEdgeConnected({swap.second, swap.first})) { - throw QMAPException("Invalid SWAP: " + std::to_string(swap.first) + - "<->" + std::to_string(swap.second)); - } + // check if SWAP is placed on a valid edge + assert(architecture->isEdgeConnected({swap.first, swap.second}, false)); qcMapped.swap(swap.first, swap.second); results.output.swaps++; } else if (swap.op == qc::Teleportation) { @@ -422,11 +419,8 @@ void HeuristicMapper::routeCircuit() { locations.at(gate.target)}; if (!architecture->isEdgeConnected(cnot)) { const Edge reversed = {cnot.second, cnot.first}; - if (!architecture->isEdgeConnected(reversed)) { - throw QMAPException( - "Invalid CNOT: " + std::to_string(reversed.first) + "-" + - std::to_string(reversed.second)); - } + // check if CNOT is placed on a valid edge + assert(architecture->isEdgeConnected(reversed)); qcMapped.h(reversed.first); qcMapped.h(reversed.second); qcMapped.cx(qc::Control{static_cast(reversed.first)}, @@ -793,8 +787,7 @@ void HeuristicMapper::expandNodeAddOneSwap(const Edge& swap, Node& node, node.validMappedTwoQubitGates, node.costFixed, node.costFixedReversals, node.depth + 1, node.sharedSwaps); - if (architecture->isEdgeConnected(swap) || - architecture->isEdgeConnected(Edge{swap.second, swap.first})) { + if (architecture->isEdgeConnected(swap, false)) { applySWAP(swap, layer, newNode); } else { applyTeleportation(swap, layer, newNode); @@ -817,8 +810,8 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (architecture->isEdgeConnected({physQ1, physQ2}) || - architecture->isEdgeConnected({physQ2, physQ1})) { // validly mapped + if (architecture->isEdgeConnected({physQ1, physQ2}, false)) { + // validly mapped node.validMappedTwoQubitGates.emplace(q1, q2); } } @@ -866,7 +859,7 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { if (swap.op == qc::SWAP) { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else if (architecture->unidirectional() || !architecture->isEdgeConnected({swap.second, swap.first}) || !architecture->isEdgeConnected({swap.first, swap.second})) { + } else if (architecture->unidirectional() || !architecture->isEdgeBidirectional({swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -941,8 +934,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, static_cast(swap.first); } - if (architecture->isEdgeConnected(swap) || - architecture->isEdgeConnected(Edge{swap.second, swap.first})) { + if (architecture->isEdgeConnected(swap, false)) { node.swaps.emplace_back(swap.first, swap.second, qc::SWAP); } else { throw QMAPException("Something wrong in applySWAP."); @@ -954,8 +946,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); - if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || - architecture->isEdgeConnected(Edge{physQ4, physQ3})) { + if (architecture->isEdgeConnected({physQ3, physQ4}, false)) { // validly mapped now if (fidelityAwareHeur && node.validMappedTwoQubitGates.find(edge) == node.validMappedTwoQubitGates.end()) { @@ -1020,7 +1011,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else if (architecture->unidirectional() || !architecture->isEdgeConnected({swap.second, swap.first}) || !architecture->isEdgeConnected({swap.first, swap.second})) { + } else if (architecture->unidirectional() || !architecture->isEdgeBidirectional({swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -1070,8 +1061,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, std::uint16_t source = std::numeric_limits::max(); std::uint16_t target = std::numeric_limits::max(); - if (architecture->isEdgeConnected({swap.first, middleAnc}) || - architecture->isEdgeConnected({middleAnc, swap.first})) { + if (architecture->isEdgeConnected({swap.first, middleAnc}, false)) { source = swap.first; target = swap.second; } else { @@ -1096,8 +1086,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, if (q3 == q1 || q3 == q2 || q4 == q1 || q4 == q2) { const auto physQ3 = static_cast(node.locations.at(q3)); const auto physQ4 = static_cast(node.locations.at(q4)); - if (architecture->isEdgeConnected(Edge{physQ3, physQ4}) || - architecture->isEdgeConnected(Edge{physQ4, physQ3})) { + if (architecture->isEdgeConnected({physQ3, physQ4}, false)) { // validly mapped now node.validMappedTwoQubitGates.emplace(edge); } else { From 3f4c604e57e6738ba7869745bb5843bb7d3fdb80 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Sat, 13 Jan 2024 10:20:41 +0100 Subject: [PATCH 34/47] adding comments for isBidirectional and isUnidirectional --- include/Architecture.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index 334da9e11..a89cf379a 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -502,8 +502,15 @@ class Architecture { std::uint16_t nqubits = 0; CouplingMap couplingMap = {}; CouplingMap currentTeleportations = {}; + + /** true if the coupling map contains no unidirectional edges */ bool isBidirectional = true; + /** true if the coupling map contains no bidirectional edges */ bool isUnidirectional = true; + // by this definition the empty coupling map is both bidirectional and + // unidirectional, and coupling maps containing both bidirectional and + // unidirectional edges are neither bidirectional nor unidirectional + Matrix distanceTable = {}; Matrix distanceTableReversals = {}; std::vector> teleportationQubits{}; From c37145d1fb192393f65c238e87b7200bb22592a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 13 Jan 2024 09:56:35 +0000 Subject: [PATCH 35/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Architecture.hpp | 25 +++++++++++++------------ src/heuristic/HeuristicMapper.cpp | 30 +++++++++++++++++------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index a89cf379a..07d5e8ee0 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -240,7 +240,8 @@ class Architecture { createDistanceTable(); } - [[nodiscard]] bool isEdgeConnected(const Edge& edge, const bool considerDirection = true) const { + [[nodiscard]] bool + isEdgeConnected(const Edge& edge, const bool considerDirection = true) const { if (considerDirection) { return couplingMap.find(edge) != couplingMap.end(); } @@ -499,20 +500,20 @@ class Architecture { protected: std::string name; - std::uint16_t nqubits = 0; - CouplingMap couplingMap = {}; - CouplingMap currentTeleportations = {}; - + std::uint16_t nqubits = 0; + CouplingMap couplingMap = {}; + CouplingMap currentTeleportations = {}; + /** true if the coupling map contains no unidirectional edges */ - bool isBidirectional = true; + bool isBidirectional = true; /** true if the coupling map contains no bidirectional edges */ - bool isUnidirectional = true; - // by this definition the empty coupling map is both bidirectional and - // unidirectional, and coupling maps containing both bidirectional and + bool isUnidirectional = true; + // by this definition the empty coupling map is both bidirectional and + // unidirectional, and coupling maps containing both bidirectional and // unidirectional edges are neither bidirectional nor unidirectional - - Matrix distanceTable = {}; - Matrix distanceTableReversals = {}; + + Matrix distanceTable = {}; + Matrix distanceTableReversals = {}; std::vector> teleportationQubits{}; Properties properties = {}; bool fidelityAvailable = false; diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 6ba021268..336053afa 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -371,7 +371,8 @@ void HeuristicMapper::routeCircuit() { << "\n"; } // check if SWAP is placed on a valid edge - assert(architecture->isEdgeConnected({swap.first, swap.second}, false)); + assert( + architecture->isEdgeConnected({swap.first, swap.second}, false)); qcMapped.swap(swap.first, swap.second); results.output.swaps++; } else if (swap.op == qc::Teleportation) { @@ -810,7 +811,7 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (architecture->isEdgeConnected({physQ1, physQ2}, false)) { + if (architecture->isEdgeConnected({physQ1, physQ2}, false)) { // validly mapped node.validMappedTwoQubitGates.emplace(q1, q2); } @@ -827,15 +828,15 @@ void HeuristicMapper::recalculateFixedCost(std::size_t layer, Node& node) { void HeuristicMapper::recalculateFixedCostReversals(std::size_t layer, Node& node) { node.costFixedReversals = 0.; - if (architecture->bidirectional() || fidelityAwareHeur || - node.validMappedTwoQubitGates.size() != - twoQubitMultiplicities.at(layer).size()) { + if (architecture->bidirectional() || fidelityAwareHeur || + node.validMappedTwoQubitGates.size() != + twoQubitMultiplicities.at(layer).size()) { // costFixedReversals should only be non-zero in goal nodes for // non-fidelity-aware heuristics and if there are unidirectional // edges in the architecture return; } - + // only consider reversal costs as fixed in goal nodes for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { const auto [q1, q2] = edge; @@ -859,7 +860,9 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { if (swap.op == qc::SWAP) { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else if (architecture->unidirectional() || !architecture->isEdgeBidirectional({swap.first, swap.second})) { + } else if (architecture->unidirectional() || + !architecture->isEdgeBidirectional( + {swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -1011,7 +1014,8 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else { if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; - } else if (architecture->unidirectional() || !architecture->isEdgeBidirectional({swap.first, swap.second})) { + } else if (architecture->unidirectional() || + !architecture->isEdgeBidirectional({swap.first, swap.second})) { node.costFixed += COST_UNIDIRECTIONAL_SWAP; } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; @@ -1223,9 +1227,9 @@ double HeuristicMapper::heuristicGateCountMaxDistance(std::size_t layer, const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (!architecture->bidirectional() && - node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { + if (!architecture->bidirectional() && + node.validMappedTwoQubitGates.find(edge) != + node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates if (!architecture->isEdgeConnected({physQ1, physQ2})) { costHeur = @@ -1263,9 +1267,9 @@ double HeuristicMapper::heuristicGateCountSumDistance(std::size_t layer, const auto physQ1 = static_cast(node.locations.at(q1)); const auto physQ2 = static_cast(node.locations.at(q2)); - if (!architecture->bidirectional() && + if (!architecture->bidirectional() && node.validMappedTwoQubitGates.find(edge) != - node.validMappedTwoQubitGates.end()) { + node.validMappedTwoQubitGates.end()) { // validly mapped 2-qubit-gates if (!architecture->isEdgeConnected({physQ1, physQ2})) { costHeur += forwardMult * COST_DIRECTION_REVERSE; From b6e471de8d0cd924ed96b01993d8445dc3aa8cb2 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 06:36:51 +0100 Subject: [PATCH 36/47] remove redundant code --- include/Architecture.hpp | 4 +- include/Mapper.hpp | 2 - include/heuristic/HeuristicMapper.hpp | 23 ++-------- src/Mapper.cpp | 1 - test/test_heuristic.cpp | 62 +++++++++++++-------------- 5 files changed, 37 insertions(+), 55 deletions(-) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index 07d5e8ee0..c40e3832c 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -397,8 +397,10 @@ class Architecture { return swapFidelityCosts.at(q1).at(q2); } + /** true if the coupling map contains no unidirectional edges */ [[nodiscard]] bool bidirectional() const { return isBidirectional; } - + + /** true if the coupling map contains no bidirectional edges */ [[nodiscard]] bool unidirectional() const { return isUnidirectional; } [[nodiscard]] bool isArchitectureAvailable() const { diff --git a/include/Mapper.hpp b/include/Mapper.hpp index 8d09e4c72..d15321684 100644 --- a/include/Mapper.hpp +++ b/include/Mapper.hpp @@ -41,7 +41,6 @@ using TwoQubitMultiplicity = using SingleQubitMultiplicity = std::vector; constexpr std::int16_t DEFAULT_POSITION = -1; -constexpr double INITIAL_FIDELITY = 1.0; class Mapper { protected: @@ -129,7 +128,6 @@ class Mapper { * The inverse of `qubits` */ std::array locations{}; - std::array fidelities{}; std::unordered_set usedDeviceQubits{}; diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index b50d3dd83..b53a65e30 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -465,11 +465,8 @@ inline bool operator>(const HeuristicMapper::Node& x, return xcost > ycost; } - if (x.validMapping && !y.validMapping) { - return false; - } - if (y.validMapping && !x.validMapping) { - return true; + if (x.validMapping != y.validMapping) { + return y.validMapping; } const auto xheur = x.costHeur + x.lookaheadPenalty; @@ -484,18 +481,4 @@ inline bool operator>(const HeuristicMapper::Node& x, } return x < y; -} - -inline bool operator==(const HeuristicMapper::Node& x, - const HeuristicMapper::Node& y) { - auto itx = x.qubits.begin(); // NOLINT (readability-qualified-auto) - auto ity = y.qubits.begin(); // NOLINT (readability-qualified-auto) - while (itx != x.qubits.end() && ity != y.qubits.end()) { - if (*itx != *ity) { - return false; - } - ++itx; - ++ity; - } - return true; -} +} \ No newline at end of file diff --git a/src/Mapper.cpp b/src/Mapper.cpp index ec8ade790..0111f5814 100644 --- a/src/Mapper.cpp +++ b/src/Mapper.cpp @@ -24,7 +24,6 @@ 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); // strip away qubits that are not used in the circuit qc.stripIdleQubits(true, true); diff --git a/test/test_heuristic.cpp b/test/test_heuristic.cpp index c505115f1..2f64c10d0 100644 --- a/test/test_heuristic.cpp +++ b/test/test_heuristic.cpp @@ -209,14 +209,14 @@ TEST_F(InternalsTest, NodeCostCalculation) { // layer 0 distances: // 0-1: 2 swaps & 2 reversals // 2-3: 0 swaps & 1 reversals - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{1}, 0); - qc.cx(qc::Control{1}, 0); - qc.cx(qc::Control{3}, 2); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(1, 0); + qc.cx(1, 0); + qc.cx(3, 2); // Architecture::distance currently counts at most 1 reversal per qubit pair createLayers(); @@ -293,29 +293,29 @@ TEST_F(InternalsTest, NodeLookaheadCalculation) { // layer 0 distances: // 0-1: 2 swaps & 2 reversals // 2-3: 0 swaps & 1 reversals - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{1}, 0); - qc.cx(qc::Control{1}, 0); - qc.cx(qc::Control{3}, 2); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(0, 1); + qc.cx(1, 0); + qc.cx(1, 0); + qc.cx(3, 2); // layer 1 distances: // 0-4: 2 swaps & 0 reversals // 1-2: 1 swaps & 1 reversals - qc.cx(qc::Control{0}, 4); - qc.cx(qc::Control{0}, 4); - qc.cx(qc::Control{1}, 2); + qc.cx(0, 4); + qc.cx(0, 4); + qc.cx(1, 2); // layer 2 distances: // 0-1: 2 swaps & 0 reversals - qc.cx(qc::Control{0}, 1); + qc.cx(0, 1); // layer 3 distances: // 0-4: 2 swaps & 0 reversals - qc.cx(qc::Control{4}, 0); + qc.cx(4, 0); // Architecture::distance currently counts at most 1 reversal per qubit pair @@ -957,9 +957,9 @@ TEST(Functionality, HeuristicBenchmark) { architecture.loadCouplingMap(5, cm); qc::QuantumComputation qc{5, 5}; - qc.cx(qc::Control{4}, 2); - qc.cx(qc::Control{3}, 1); - qc.cx(qc::Control{4}, 1); + qc.cx(4, 2); + qc.cx(3, 1); + qc.cx(4, 1); qc.barrier({0, 1, 2, 3, 4}); for (size_t i = 0; i < 5; ++i) { @@ -1038,7 +1038,7 @@ TEST(Functionality, EmptyDump) { TEST(Functionality, BenchmarkGeneratedNodes) { qc::QuantumComputation qc{16, 16}; - qc.cx(qc::Control{0}, 6); + qc.cx(0, 6); for (std::size_t i = 0; i < 16; ++i) { qc.measure(static_cast(i), i); } @@ -1517,7 +1517,7 @@ TEST(Functionality, terminationStrategyFromString) { TEST(Functionality, earlyTermination) { qc::QuantumComputation qc{7, 7}; qc.x(0); - qc.cx(qc::Control{1}, 2); + qc.cx(1, 2); for (std::size_t i = 0; i < 7; ++i) { qc.measure(static_cast(i), i); } @@ -1696,9 +1696,9 @@ class LayeringTest : public testing::Test { qc = qc::QuantumComputation{4, 4}; qc.x(0); qc.x(1); - qc.cx(qc::Control{0}, 1); - qc.cx(qc::Control{2}, 3); - qc.cx(qc::Control{1}, 2); + qc.cx(0, 1); + qc.cx(2, 3); + qc.cx(1, 2); qc.x(3); qc.barrier({0, 1, 2}); for (size_t i = 0; i < 3; ++i) { @@ -2361,8 +2361,8 @@ TEST(HeuristicTestFidelity, LayerSplitting) { qc.x(5); qc.x(7); for (std::size_t i = 0; i < 5; ++i) { - qc.cx(qc::Control{3}, 0); - qc.cx(qc::Control{9}, 2); + qc.cx(3, 0); + qc.cx(9, 2); } for (size_t i = 0; i < 12; ++i) { From 76e3006fbfe3e69a42fc40b848ad74bcc20bee05 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 06:48:23 +0100 Subject: [PATCH 37/47] simplify buildEdgeSkipTable --- include/utils.hpp | 21 +++++++++++++-------- src/Architecture.cpp | 5 +---- src/utils.cpp | 27 ++++++++++++++------------- test/test_general.cpp | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/utils.hpp b/include/utils.hpp index 153a91691..1237fd10b 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -84,18 +84,23 @@ class Dijkstra { * distances between 2 qubit when upto k edges can be skipped. * * e.g. cost of moving qubit q1 onto q2 skipping upto 3 edges: - * edgeSkipDistanceTable[3][q1][q2] + * distanceTables[3][q1][q2] * - * if k > edgeSkipDistanceTable.size() a cost of 0 can be assumed + * if k > distanceTables.size() a cost of 0 can be assumed * - * @param distanceTable 2d matrix containing distances between any 2 qubits: - * distanceTable[source][target] * @param couplingMap coupling map specifying all edges in the architecture - * @param edgeSkipDistanceTable 3d target table + * @param distanceTables vector to fill with target tables (from 0 skips in + * the first entry to k skips in the last entry, where k is the last index + * not containing a matrix of pure 0s i.e. k+1 = diameter of the coupling + * graph) + * @param edgeWeights matrix containing costs for swapping any two, connected + * qubits (this might be uniform for all edges or different for each edge, as + * e.g. in the case of fidelity-aware distances or distances on + * mixed bi/unidirectional architectures) */ - static void buildEdgeSkipTable(const Matrix& distanceTable, - const CouplingMap& couplingMap, - std::vector& edgeSkipDistanceTable); + static void buildEdgeSkipTable(const CouplingMap& couplingMap, + std::vector& distanceTables, + const Matrix& edgeWeights); /** * @brief builds a distance table containing the minimal costs for moving * logical qubits from one physical qubit to another (along the cheapest path) diff --git a/src/Architecture.cpp b/src/Architecture.cpp index ae137cf45..67d5d8fc1 100644 --- a/src/Architecture.cpp +++ b/src/Architecture.cpp @@ -276,10 +276,7 @@ void Architecture::createFidelityTable() { fidelityDistanceTables.clear(); if (fidelityAvailable) { - Matrix distances = {}; - Dijkstra::buildTable(couplingMap, distances, swapFidelityCosts); - Dijkstra::buildEdgeSkipTable(distances, couplingMap, - fidelityDistanceTables); + Dijkstra::buildEdgeSkipTable(couplingMap, fidelityDistanceTables, swapFidelityCosts); } } diff --git a/src/utils.cpp b/src/utils.cpp index d0f92e1ab..24f5ff05d 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -72,9 +72,9 @@ void Dijkstra::dijkstra(const CouplingMap& couplingMap, } } -void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, - const CouplingMap& couplingMap, - std::vector& edgeSkipDistanceTable) { +void Dijkstra::buildEdgeSkipTable(const CouplingMap& couplingMap, + std::vector& distanceTables, + const Matrix& edgeWeights) { /* to find the cheapest distance between 2 qubits skipping any 1 edge, we iterate over all edges, for each assume the current edge to be the one skipped and are thereby able to retrieve the distance by just adding the distances @@ -85,14 +85,15 @@ void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, edge taking not the regular distance but the previously calculated distance skipping 1 edge. The same approach can be used for skipping any 3 edges, etc. */ - edgeSkipDistanceTable.clear(); - edgeSkipDistanceTable.emplace_back(distanceTable); - const std::size_t n = distanceTable.size(); + distanceTables.clear(); + distanceTables.emplace_back(); + buildTable(couplingMap, distanceTables.back(), edgeWeights); + const std::size_t n = edgeWeights.size(); for (std::size_t k = 1; k <= n; ++k) { // k...number of edges to be skipped along each path - edgeSkipDistanceTable.emplace_back( + distanceTables.emplace_back( n, std::vector(n, std::numeric_limits::max())); - Matrix* currentTable = &edgeSkipDistanceTable.back(); + Matrix* currentTable = &distanceTables.back(); for (std::size_t q = 0; q < n; ++q) { currentTable->at(q).at(q) = 0.; } @@ -105,12 +106,12 @@ void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, for (std::size_t q2 = q1 + 1; q2 < n; ++q2) { // q2 ... target qubit currentTable->at(q1).at(q2) = std::min(currentTable->at(q1).at(q2), - edgeSkipDistanceTable.at(l).at(q1).at(e1) + - edgeSkipDistanceTable.at(k - l - 1).at(e2).at(q2)); + distanceTables.at(l).at(q1).at(e1) + + distanceTables.at(k - l - 1).at(e2).at(q2)); currentTable->at(q1).at(q2) = std::min(currentTable->at(q1).at(q2), - edgeSkipDistanceTable.at(l).at(q1).at(e2) + - edgeSkipDistanceTable.at(k - l - 1).at(e1).at(q2)); + distanceTables.at(l).at(q1).at(e2) + + distanceTables.at(k - l - 1).at(e1).at(q2)); currentTable->at(q2).at(q1) = currentTable->at(q1).at(q2); if (done && currentTable->at(q2).at(q1) > 0) { done = false; @@ -121,7 +122,7 @@ void Dijkstra::buildEdgeSkipTable(const Matrix& distanceTable, } if (done) { // all distances of the last matrix where 0 - edgeSkipDistanceTable.pop_back(); + distanceTables.pop_back(); break; } } diff --git a/test/test_general.cpp b/test/test_general.cpp index 6f7ca2d6e..2440f273f 100644 --- a/test/test_general.cpp +++ b/test/test_general.cpp @@ -181,6 +181,6 @@ TEST(General, DijkstraSkipEdges) { {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; std::vector edgeSkipDistanceTable = {}; - Dijkstra::buildEdgeSkipTable(distanceTable, cm, edgeSkipDistanceTable); + Dijkstra::buildEdgeSkipTable(cm, edgeSkipDistanceTable, edgeWeights); EXPECT_EQ(edgeSkipDistanceTable, edgeSkipTargetTable); } From 8bcb9ce75c3b8928288ad511ac806cf424caed07 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 07:37:17 +0100 Subject: [PATCH 38/47] expose heuristic properties in config json --- src/configuration/Configuration.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index b9091fa9e..a51d6a359 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -21,10 +21,17 @@ nlohmann::json Configuration::json() const { if (method == Method::Heuristic) { auto& heuristicJson = config["settings"]; heuristicJson["heuristic"] = ::toString(heuristic); + auto& heuristicPropertiesJson = heuristicJson["heuristic_properties"]; + heuristicPropertiesJson["admissible"] = isAdmissible(heuristic); + heuristicPropertiesJson["principally_admissible"] = isPrincipallyAdmissible(heuristic); + heuristicPropertiesJson["tight"] = isTight(heuristic); + heuristicPropertiesJson["fidelity_aware"] = isFidelityAware(heuristic); heuristicJson["initial_layout"] = ::toString(initialLayout); if (lookaheadHeuristic != LookaheadHeuristic::None) { auto& lookaheadSettings = heuristicJson["lookahead"]; lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); + auto& lookaheadHeuristicPropertiesJson = lookaheadSettings["heuristic_properties"]; + heuristicPropertiesJson["fidelity_aware"] = isFidelityAware(lookaheadHeuristic); lookaheadSettings["lookaheads"] = nrLookaheads; lookaheadSettings["first_factor"] = firstLookaheadFactor; lookaheadSettings["factor"] = lookaheadFactor; From 2d1e36188f0d5789b858f89d5003a9d6da7a4303 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 07:43:40 +0100 Subject: [PATCH 39/47] checkParameters --- include/heuristic/HeuristicMapper.hpp | 5 ++++ src/heuristic/HeuristicMapper.cpp | 43 ++++++++++++++++----------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index b53a65e30..f6cc1df48 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -144,6 +144,11 @@ class HeuristicMapper : public Mapper { bool principallyAdmissibleHeur = true; bool tightHeur = true; bool fidelityAwareHeur = false; + + /** + * @brief check the `results.config` for any invalid settings + */ + virtual void checkParameters(); /** * @brief creates an initial mapping of logical qubits to physical qubits with diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 336053afa..abbd93515 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -22,24 +22,7 @@ void HeuristicMapper::map(const Configuration& configuration) { results = MappingResults{}; results.config = configuration; const auto& config = results.config; - if (config.layering == Layering::OddGates || - config.layering == Layering::QubitTriangle) { - throw QMAPException("Layering strategy " + toString(config.layering) + - " not suitable for heuristic mapper!"); - } - if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { - throw QMAPException("No calibration data available for this architecture!"); - } - if (fidelityAwareHeur && !isFidelityAware(config.lookaheadHeuristic) && - config.lookaheadHeuristic != LookaheadHeuristic::None) { - throw QMAPException("Fidelity-aware heuristics may only be used with " - "fidelity-aware lookahead heuristics (or no " - "lookahead)!"); - } - if (fidelityAwareHeur && config.teleportationQubits > 0) { - throw QMAPException("Teleportation is not yet supported for heuristic " - "mapper using fidelity-aware mapping!"); - } + checkParameters(); const auto start = std::chrono::steady_clock::now(); initResults(); @@ -135,6 +118,30 @@ void HeuristicMapper::staticInitialMapping() { } } +void HeuristicMapper::checkParameters() { + const auto& config = results.config; + if (config.layering == Layering::OddGates || + config.layering == Layering::QubitTriangle) { + throw QMAPException("Layering strategy " + toString(config.layering) + + " not suitable for heuristic mapper!"); + } + if (fidelityAwareHeur && !architecture->isFidelityAvailable()) { + throw QMAPException("Fidelity aware heuristic chosen, but no or " + "insufficient calibration data available for this " + "architecture!"); + } + if (fidelityAwareHeur && !isFidelityAware(config.lookaheadHeuristic) && + config.lookaheadHeuristic != LookaheadHeuristic::None) { + throw QMAPException("Fidelity-aware heuristics may only be used with " + "fidelity-aware lookahead heuristics (or no " + "lookahead)!"); + } + if (fidelityAwareHeur && config.teleportationQubits > 0) { + throw QMAPException("Teleportation is not yet supported for heuristic " + "mapper using fidelity-aware mapping!"); + } +} + void HeuristicMapper::createInitialMapping() { auto& config = results.config; From c940d490ef42076cb83a0be23e1000bf051ae259 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 07:54:21 +0100 Subject: [PATCH 40/47] ignore bugprone-branch-clone lint warning --- src/heuristic/HeuristicMapper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index abbd93515..2feb9c220 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -865,6 +865,9 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { // swap costs for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { + // branch clone intended for performance reasons (checking edge-wise for + // bidirectionality is not O(1)) + // NOLINTBEGIN(bugprone-branch-clone) if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; } else if (architecture->unidirectional() || @@ -874,6 +877,7 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; } + // NOLINTEND(bugprone-branch-clone) } else if (swap.op == qc::Teleportation) { node.costFixed += COST_TELEPORTATION; } @@ -1019,6 +1023,9 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); } else { + // branch clone intended for performance reasons (checking edge-wise for + // bidirectionality is not O(1)) + // NOLINTBEGIN(bugprone-branch-clone) if (architecture->bidirectional()) { node.costFixed += COST_BIDIRECTIONAL_SWAP; } else if (architecture->unidirectional() || @@ -1027,6 +1034,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, } else { node.costFixed += COST_BIDIRECTIONAL_SWAP; } + // NOLINTEND(bugprone-branch-clone) } recalculateFixedCostReversals(layer, node); From e599ab871726f404b20d149731593989b605e793 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 06:54:54 +0000 Subject: [PATCH 41/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Architecture.hpp | 2 +- include/heuristic/HeuristicMapper.hpp | 4 ++-- include/utils.hpp | 10 +++++----- src/Architecture.cpp | 3 ++- src/configuration/Configuration.cpp | 23 +++++++++++++---------- src/heuristic/HeuristicMapper.cpp | 4 ++-- src/utils.cpp | 4 ++-- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/include/Architecture.hpp b/include/Architecture.hpp index c40e3832c..b6a9c3777 100644 --- a/include/Architecture.hpp +++ b/include/Architecture.hpp @@ -399,7 +399,7 @@ class Architecture { /** true if the coupling map contains no unidirectional edges */ [[nodiscard]] bool bidirectional() const { return isBidirectional; } - + /** true if the coupling map contains no bidirectional edges */ [[nodiscard]] bool unidirectional() const { return isUnidirectional; } diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index f6cc1df48..ab071670d 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -144,7 +144,7 @@ class HeuristicMapper : public Mapper { bool principallyAdmissibleHeur = true; bool tightHeur = true; bool fidelityAwareHeur = false; - + /** * @brief check the `results.config` for any invalid settings */ @@ -486,4 +486,4 @@ inline bool operator>(const HeuristicMapper::Node& x, } return x < y; -} \ No newline at end of file +} diff --git a/include/utils.hpp b/include/utils.hpp index 1237fd10b..0ae25a851 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -89,18 +89,18 @@ class Dijkstra { * if k > distanceTables.size() a cost of 0 can be assumed * * @param couplingMap coupling map specifying all edges in the architecture - * @param distanceTables vector to fill with target tables (from 0 skips in - * the first entry to k skips in the last entry, where k is the last index - * not containing a matrix of pure 0s i.e. k+1 = diameter of the coupling + * @param distanceTables vector to fill with target tables (from 0 skips in + * the first entry to k skips in the last entry, where k is the last index + * not containing a matrix of pure 0s i.e. k+1 = diameter of the coupling * graph) * @param edgeWeights matrix containing costs for swapping any two, connected * qubits (this might be uniform for all edges or different for each edge, as * e.g. in the case of fidelity-aware distances or distances on * mixed bi/unidirectional architectures) */ - static void buildEdgeSkipTable(const CouplingMap& couplingMap, + static void buildEdgeSkipTable(const CouplingMap& couplingMap, std::vector& distanceTables, - const Matrix& edgeWeights); + const Matrix& edgeWeights); /** * @brief builds a distance table containing the minimal costs for moving * logical qubits from one physical qubit to another (along the cheapest path) diff --git a/src/Architecture.cpp b/src/Architecture.cpp index 67d5d8fc1..e613d1c93 100644 --- a/src/Architecture.cpp +++ b/src/Architecture.cpp @@ -276,7 +276,8 @@ void Architecture::createFidelityTable() { fidelityDistanceTables.clear(); if (fidelityAvailable) { - Dijkstra::buildEdgeSkipTable(couplingMap, fidelityDistanceTables, swapFidelityCosts); + Dijkstra::buildEdgeSkipTable(couplingMap, fidelityDistanceTables, + swapFidelityCosts); } } diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index a51d6a359..b1eb3f2a7 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -19,19 +19,22 @@ nlohmann::json Configuration::json() const { config["debug"] = debug; if (method == Method::Heuristic) { - auto& heuristicJson = config["settings"]; - heuristicJson["heuristic"] = ::toString(heuristic); - auto& heuristicPropertiesJson = heuristicJson["heuristic_properties"]; + auto& heuristicJson = config["settings"]; + heuristicJson["heuristic"] = ::toString(heuristic); + auto& heuristicPropertiesJson = heuristicJson["heuristic_properties"]; heuristicPropertiesJson["admissible"] = isAdmissible(heuristic); - heuristicPropertiesJson["principally_admissible"] = isPrincipallyAdmissible(heuristic); - heuristicPropertiesJson["tight"] = isTight(heuristic); + heuristicPropertiesJson["principally_admissible"] = + isPrincipallyAdmissible(heuristic); + heuristicPropertiesJson["tight"] = isTight(heuristic); heuristicPropertiesJson["fidelity_aware"] = isFidelityAware(heuristic); - heuristicJson["initial_layout"] = ::toString(initialLayout); + heuristicJson["initial_layout"] = ::toString(initialLayout); if (lookaheadHeuristic != LookaheadHeuristic::None) { - auto& lookaheadSettings = heuristicJson["lookahead"]; - lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); - auto& lookaheadHeuristicPropertiesJson = lookaheadSettings["heuristic_properties"]; - heuristicPropertiesJson["fidelity_aware"] = isFidelityAware(lookaheadHeuristic); + auto& lookaheadSettings = heuristicJson["lookahead"]; + lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); + auto& lookaheadHeuristicPropertiesJson = + lookaheadSettings["heuristic_properties"]; + heuristicPropertiesJson["fidelity_aware"] = + isFidelityAware(lookaheadHeuristic); lookaheadSettings["lookaheads"] = nrLookaheads; lookaheadSettings["first_factor"] = firstLookaheadFactor; lookaheadSettings["factor"] = lookaheadFactor; diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 2feb9c220..afc829b28 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -865,7 +865,7 @@ void HeuristicMapper::recalculateFixedCostNonFidelity(Node& node) { // swap costs for (auto& swap : node.swaps) { if (swap.op == qc::SWAP) { - // branch clone intended for performance reasons (checking edge-wise for + // branch clone intended for performance reasons (checking edge-wise for // bidirectionality is not O(1)) // NOLINTBEGIN(bugprone-branch-clone) if (architecture->bidirectional()) { @@ -1023,7 +1023,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.costFixed += architecture->getSwapFidelityCost(swap.first, swap.second); } else { - // branch clone intended for performance reasons (checking edge-wise for + // branch clone intended for performance reasons (checking edge-wise for // bidirectionality is not O(1)) // NOLINTBEGIN(bugprone-branch-clone) if (architecture->bidirectional()) { diff --git a/src/utils.cpp b/src/utils.cpp index 24f5ff05d..55e664031 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -72,9 +72,9 @@ void Dijkstra::dijkstra(const CouplingMap& couplingMap, } } -void Dijkstra::buildEdgeSkipTable(const CouplingMap& couplingMap, +void Dijkstra::buildEdgeSkipTable(const CouplingMap& couplingMap, std::vector& distanceTables, - const Matrix& edgeWeights) { + const Matrix& edgeWeights) { /* to find the cheapest distance between 2 qubits skipping any 1 edge, we iterate over all edges, for each assume the current edge to be the one skipped and are thereby able to retrieve the distance by just adding the distances From 8b7cdf1e018b00ce2a83c440c00514ac2b3d605c Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 08:29:01 +0100 Subject: [PATCH 42/47] fix linter warning in Configuration::json --- src/configuration/Configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index b1eb3f2a7..0cf126101 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -33,7 +33,7 @@ nlohmann::json Configuration::json() const { lookaheadSettings["heuristic"] = ::toString(lookaheadHeuristic); auto& lookaheadHeuristicPropertiesJson = lookaheadSettings["heuristic_properties"]; - heuristicPropertiesJson["fidelity_aware"] = + lookaheadHeuristicPropertiesJson["fidelity_aware"] = isFidelityAware(lookaheadHeuristic); lookaheadSettings["lookaheads"] = nrLookaheads; lookaheadSettings["first_factor"] = firstLookaheadFactor; From 36b8a8a0cc77e69fdfa02117dd7baf3596515ae1 Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 10:28:27 +0100 Subject: [PATCH 43/47] use asserts for internal error checking --- src/heuristic/HeuristicMapper.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index afc829b28..37a5579db 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -929,6 +929,7 @@ void HeuristicMapper::recalculateFixedCostFidelity(std::size_t layer, void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, Node& node) { + assert(architecture->isEdgeConnected(swap, false)); const auto& singleQubitGateMultiplicity = singleQubitMultiplicities.at(layer); const auto q1 = node.qubits.at(swap.first); @@ -947,12 +948,8 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.locations.at(static_cast(q2)) = static_cast(swap.first); } - - if (architecture->isEdgeConnected(swap, false)) { - node.swaps.emplace_back(swap.first, swap.second, qc::SWAP); - } else { - throw QMAPException("Something wrong in applySWAP."); - } + + node.swaps.emplace_back(swap.first, swap.second, qc::SWAP); // check if swap created or destroyed any valid mappings of qubit pairs for (const auto& [edge, mult] : twoQubitMultiplicities.at(layer)) { @@ -1071,12 +1068,9 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, middleAnc = static_cast(qpair.first); } } - - if (middleAnc == std::numeric_limits::max()) { - throw QMAPException("Teleportation between seemingly wrong qubits: " + - std::to_string(swap.first) + " <--> " + - std::to_string(swap.second)); - } + + // Teleportation between wrong qubits + assert(middleAnc != std::numeric_limits::max()); std::uint16_t source = std::numeric_limits::max(); std::uint16_t target = std::numeric_limits::max(); From 08c75882463ef2787ca6aec86d9bec08021f772a Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Mon, 15 Jan 2024 10:38:00 +0100 Subject: [PATCH 44/47] use copy constructor for Node members --- include/heuristic/HeuristicMapper.hpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index ab071670d..6feb96fc9 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -95,16 +95,11 @@ class HeuristicMapper : public Mapper { const double initCostFixedReversals = 0, const std::size_t searchDepth = 0, const std::size_t initSharedSwaps = 0) - : costFixed(initCostFixed), costFixedReversals(initCostFixedReversals), + : validMappedTwoQubitGates(valid2QGates), swaps(sw), qubits(q), + locations(loc), costFixed(initCostFixed), + costFixedReversals(initCostFixedReversals), sharedSwaps(initSharedSwaps), depth(searchDepth), parent(parentId), - id(nodeId) { - std::copy(q.begin(), q.end(), qubits.begin()); - std::copy(loc.begin(), loc.end(), locations.begin()); - std::copy(sw.begin(), sw.end(), std::back_inserter(swaps)); - std::copy(valid2QGates.begin(), valid2QGates.end(), - std::inserter(validMappedTwoQubitGates, - validMappedTwoQubitGates.begin())); - } + id(nodeId) {} /** * @brief returns costFixed + costHeur + lookaheadPenalty From ad9cf4a9ab3340d22554121059a46d5e06398dba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:38:32 +0000 Subject: [PATCH 45/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/heuristic/HeuristicMapper.hpp | 6 +++--- src/heuristic/HeuristicMapper.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 6feb96fc9..2e9ba0aec 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -95,9 +95,9 @@ class HeuristicMapper : public Mapper { const double initCostFixedReversals = 0, const std::size_t searchDepth = 0, const std::size_t initSharedSwaps = 0) - : validMappedTwoQubitGates(valid2QGates), swaps(sw), qubits(q), - locations(loc), costFixed(initCostFixed), - costFixedReversals(initCostFixedReversals), + : validMappedTwoQubitGates(valid2QGates), swaps(sw), qubits(q), + locations(loc), costFixed(initCostFixed), + costFixedReversals(initCostFixedReversals), sharedSwaps(initSharedSwaps), depth(searchDepth), parent(parentId), id(nodeId) {} diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 37a5579db..5d78a0c66 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -948,7 +948,7 @@ void HeuristicMapper::applySWAP(const Edge& swap, std::size_t layer, node.locations.at(static_cast(q2)) = static_cast(swap.first); } - + node.swaps.emplace_back(swap.first, swap.second, qc::SWAP); // check if swap created or destroyed any valid mappings of qubit pairs @@ -1068,7 +1068,7 @@ void HeuristicMapper::applyTeleportation(const Edge& swap, std::size_t layer, middleAnc = static_cast(qpair.first); } } - + // Teleportation between wrong qubits assert(middleAnc != std::numeric_limits::max()); From 08514f2e6c1a586c053fda36659ac6f27e08aa3b Mon Sep 17 00:00:00 2001 From: Elias Foramitti Date: Tue, 16 Jan 2024 00:39:20 +0100 Subject: [PATCH 46/47] user ordered sets for activeQubits --- include/Mapper.hpp | 12 +++++------ include/heuristic/HeuristicMapper.hpp | 2 +- include/utils.hpp | 2 -- src/Mapper.cpp | 30 +++++++++++++-------------- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/include/Mapper.hpp b/include/Mapper.hpp index d15321684..fa4bc854e 100644 --- a/include/Mapper.hpp +++ b/include/Mapper.hpp @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include /** * number of two-qubit gates acting on pairs of logical qubits in some layer @@ -100,19 +101,19 @@ class Mapper { * @brief For each layer the set of all logical qubits, which are acted on by * a gate in the layer */ - std::vector> activeQubits{}; + std::vector> activeQubits{}; /** * @brief For each layer the set of all logical qubits, which are acted on by * a 1Q-gate in the layer */ - std::vector> activeQubits1QGates{}; + std::vector> activeQubits1QGates{}; /** * @brief For each layer the set of all logical qubits, which are acted on by * a 2Q-gate in the layer */ - std::vector> activeQubits2QGates{}; + std::vector> activeQubits2QGates{}; /** * @brief containing the logical qubit currently mapped to each physical @@ -129,8 +130,6 @@ class Mapper { */ std::array locations{}; - std::unordered_set usedDeviceQubits{}; - MappingResults results{}; /** @@ -359,7 +358,6 @@ class Mapper { layers.clear(); qubits.fill(DEFAULT_POSITION); locations.fill(DEFAULT_POSITION); - usedDeviceQubits.clear(); results = MappingResults(); } diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 6feb96fc9..537f7577d 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -215,7 +215,7 @@ class HeuristicMapper : public Mapper { * * @param layer the layer for which to get the considered qubits */ - const std::unordered_set& + const std::set& getConsideredQubits(std::size_t layer) const { if (fidelityAwareHeur) { return activeQubits.at(layer); diff --git a/include/utils.hpp b/include/utils.hpp index 0ae25a851..d333d96c9 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include using Matrix = std::vector>; diff --git a/src/Mapper.cpp b/src/Mapper.cpp index 0111f5814..66819ce20 100644 --- a/src/Mapper.cpp +++ b/src/Mapper.cpp @@ -216,12 +216,12 @@ void Mapper::createLayers() { layers.size(), SingleQubitMultiplicity(architecture->getNqubits(), 0)); twoQubitMultiplicities = std::vector(layers.size(), TwoQubitMultiplicity{}); - activeQubits = std::vector>( - layers.size(), std::unordered_set{}); - activeQubits1QGates = std::vector>( - layers.size(), std::unordered_set{}); - activeQubits2QGates = std::vector>( - layers.size(), std::unordered_set{}); + activeQubits = std::vector>( + layers.size(), std::set{}); + activeQubits1QGates = std::vector>( + layers.size(), std::set{}); + activeQubits2QGates = std::vector>( + layers.size(), std::set{}); for (std::size_t i = 0; i < layers.size(); ++i) { for (const auto& gate : layers[i]) { @@ -288,12 +288,12 @@ void Mapper::splitLayer(std::size_t index, Architecture& arch) { SingleQubitMultiplicity singleQubitMultiplicity1(arch.getNqubits(), 0); TwoQubitMultiplicity twoQubitMultiplicity0{}; TwoQubitMultiplicity twoQubitMultiplicity1{}; - std::unordered_set activeQubits0{}; - std::unordered_set activeQubits1QGates0{}; - std::unordered_set activeQubits2QGates0{}; - std::unordered_set activeQubits1{}; - std::unordered_set activeQubits1QGates1{}; - std::unordered_set activeQubits2QGates1{}; + std::set activeQubits0{}; + std::set activeQubits1QGates0{}; + std::set activeQubits2QGates0{}; + std::set activeQubits1{}; + std::set activeQubits1QGates1{}; + std::set activeQubits2QGates1{}; // 2Q-gates bool even = false; @@ -392,7 +392,7 @@ void Mapper::splitLayer(std::size_t index, Architecture& arch) { activeQubits.insert( activeQubits.begin() + static_cast< - std::vector>::difference_type>( + std::vector>::difference_type>( index) + 1, activeQubits1); @@ -400,7 +400,7 @@ void Mapper::splitLayer(std::size_t index, Architecture& arch) { activeQubits1QGates.insert( activeQubits1QGates.begin() + static_cast< - std::vector>::difference_type>( + std::vector>::difference_type>( index) + 1, activeQubits1QGates1); @@ -408,7 +408,7 @@ void Mapper::splitLayer(std::size_t index, Architecture& arch) { activeQubits2QGates.insert( activeQubits2QGates.begin() + static_cast< - std::vector>::difference_type>( + std::vector>::difference_type>( index) + 1, activeQubits2QGates1); From ade1f5413994ea45643d8234b7810897fb63eb26 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:39:50 +0000 Subject: [PATCH 47/47] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Mapper.hpp | 4 ++-- include/heuristic/HeuristicMapper.hpp | 3 +-- src/Mapper.cpp | 9 +++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/Mapper.hpp b/include/Mapper.hpp index fa4bc854e..109c7781a 100644 --- a/include/Mapper.hpp +++ b/include/Mapper.hpp @@ -14,10 +14,10 @@ #include #include #include +#include #include -#include #include -#include +#include /** * number of two-qubit gates acting on pairs of logical qubits in some layer diff --git a/include/heuristic/HeuristicMapper.hpp b/include/heuristic/HeuristicMapper.hpp index 5982e3902..74d282dc9 100644 --- a/include/heuristic/HeuristicMapper.hpp +++ b/include/heuristic/HeuristicMapper.hpp @@ -215,8 +215,7 @@ class HeuristicMapper : public Mapper { * * @param layer the layer for which to get the considered qubits */ - const std::set& - getConsideredQubits(std::size_t layer) const { + const std::set& getConsideredQubits(std::size_t layer) const { if (fidelityAwareHeur) { return activeQubits.at(layer); } diff --git a/src/Mapper.cpp b/src/Mapper.cpp index 66819ce20..c6026ee40 100644 --- a/src/Mapper.cpp +++ b/src/Mapper.cpp @@ -391,24 +391,21 @@ void Mapper::splitLayer(std::size_t index, Architecture& arch) { activeQubits[index] = activeQubits0; activeQubits.insert( activeQubits.begin() + - static_cast< - std::vector>::difference_type>( + static_cast>::difference_type>( index) + 1, activeQubits1); activeQubits1QGates[index] = activeQubits1QGates0; activeQubits1QGates.insert( activeQubits1QGates.begin() + - static_cast< - std::vector>::difference_type>( + static_cast>::difference_type>( index) + 1, activeQubits1QGates1); activeQubits2QGates[index] = activeQubits2QGates0; activeQubits2QGates.insert( activeQubits2QGates.begin() + - static_cast< - std::vector>::difference_type>( + static_cast>::difference_type>( index) + 1, activeQubits2QGates1);