diff --git a/extern/qfr b/extern/qfr index 6fc0527e0..9dbdebce6 160000 --- a/extern/qfr +++ b/extern/qfr @@ -1 +1 @@ -Subproject commit 6fc0527e0a68805462e6a920f7425a33bb9ba191 +Subproject commit 9dbdebce6f0c2f5246d7ecfe240f34a3ec6c8ea9 diff --git a/include/cliffordsynthesis/Tableau.hpp b/include/cliffordsynthesis/Tableau.hpp index cce0e5b4d..6e304cb49 100644 --- a/include/cliffordsynthesis/Tableau.hpp +++ b/include/cliffordsynthesis/Tableau.hpp @@ -87,6 +87,9 @@ class Tableau { void applyCY(std::size_t control, std::size_t target); void applyCZ(std::size_t control, std::size_t target); void applySwap(std::size_t q1, std::size_t q2); + void applyISwap(std::size_t q1, std::size_t q2); + void applyDCX(std::size_t q1, std::size_t q2); + void applyECR(std::size_t q1, std::size_t q2); [[gnu::pure]] friend bool operator==(const Tableau& lhs, const Tableau& rhs) { return lhs.tableau == rhs.tableau; diff --git a/include/configuration/CommanderGrouping.hpp b/include/configuration/CommanderGrouping.hpp index 903468e16..c346f83d4 100644 --- a/include/configuration/CommanderGrouping.hpp +++ b/include/configuration/CommanderGrouping.hpp @@ -10,8 +10,7 @@ enum class CommanderGrouping { Halves, Fixed2, Fixed3, Logarithm }; -[[maybe_unused]] static inline std::string -toString(const CommanderGrouping grouping) { +static inline std::string toString(const CommanderGrouping grouping) { switch (grouping) { case CommanderGrouping::Fixed2: return "fixed2"; @@ -25,8 +24,7 @@ toString(const CommanderGrouping grouping) { return " "; } -[[maybe_unused]] static CommanderGrouping -groupingFromString(const std::string& grouping) { +static CommanderGrouping groupingFromString(const std::string& grouping) { if (grouping == "halves" || grouping == "0") { return CommanderGrouping::Halves; } @@ -41,3 +39,17 @@ groupingFromString(const std::string& grouping) { } throw std::invalid_argument("Invalid grouping value: " + grouping); } + +[[maybe_unused]] static inline std::ostream& +operator<<(std::ostream& os, const CommanderGrouping& grouping) { + os << toString(grouping); + return os; +} + +[[maybe_unused]] static inline std::istream& +operator>>(std::istream& is, CommanderGrouping& grouping) { + std::string s; + is >> s; + grouping = groupingFromString(s); + return is; +} diff --git a/include/configuration/Encoding.hpp b/include/configuration/Encoding.hpp index ce2928036..15d4834a2 100644 --- a/include/configuration/Encoding.hpp +++ b/include/configuration/Encoding.hpp @@ -10,7 +10,7 @@ enum class Encoding { Naive, Commander, Bimander }; -[[maybe_unused]] static inline std::string toString(const Encoding encoding) { +static inline std::string toString(const Encoding encoding) { switch (encoding) { case Encoding::Naive: return "naive"; @@ -22,8 +22,7 @@ enum class Encoding { Naive, Commander, Bimander }; return " "; } -[[maybe_unused]] static Encoding -encodingFromString(const std::string& encoding) { +static Encoding encodingFromString(const std::string& encoding) { if (encoding == "naive" || encoding == "0") { return Encoding::Naive; } @@ -35,3 +34,17 @@ encodingFromString(const std::string& encoding) { } throw std::invalid_argument("Invalid encoding value: " + encoding); } + +[[maybe_unused]] static inline std::ostream& +operator<<(std::ostream& os, const Encoding& encoding) { + os << toString(encoding); + return os; +} + +[[maybe_unused]] static inline std::istream& operator>>(std::istream& is, + Encoding& encoding) { + std::string s; + is >> s; + encoding = encodingFromString(s); + return is; +} diff --git a/src/cliffordsynthesis/Tableau.cpp b/src/cliffordsynthesis/Tableau.cpp index fd866534d..533b48692 100644 --- a/src/cliffordsynthesis/Tableau.cpp +++ b/src/cliffordsynthesis/Tableau.cpp @@ -88,6 +88,21 @@ void Tableau::applyGate(const qc::Operation* const gate) { applySwap(target, target2); break; } + case qc::OpType::iSWAP: { + const auto target2 = static_cast(gate->getTargets().at(1U)); + applyISwap(target, target2); + break; + } + case qc::OpType::DCX: { + const auto target2 = static_cast(gate->getTargets().at(1U)); + applyDCX(target, target2); + break; + } + case qc::OpType::ECR: { + const auto target2 = static_cast(gate->getTargets().at(1U)); + applyECR(target, target2); + break; + } default: // unsupported non-controlled gate type util::fatal("Tableau::applyGate: Unsupported non-controlled gate type " + @@ -295,6 +310,35 @@ void Tableau::applySwap(const std::size_t q1, const std::size_t q2) { applyCX(q1, q2); } +void Tableau::applyISwap(const std::size_t q1, const std::size_t q2) { + assert(q1 < nQubits); + assert(q2 < nQubits); + assert(q1 != q2); + applyS(q2); + applyS(q1); + applyH(q1); + applyDCX(q1, q2); + applyH(q2); +} + +void Tableau::applyDCX(const std::size_t q1, const std::size_t q2) { + assert(q1 < nQubits); + assert(q2 < nQubits); + assert(q1 != q2); + applyCX(q1, q2); + applyCX(q2, q1); +} + +void Tableau::applyECR(const std::size_t q1, const std::size_t q2) { + assert(q1 < nQubits); + assert(q2 < nQubits); + assert(q1 != q2); + applyS(q1); + applySx(q2); + applyCX(q1, q2); + applyX(q1); +} + Tableau::Tableau(const qc::QuantumComputation& qc, const std::size_t begin, const std::size_t end) : Tableau(qc.getNqubits()) { diff --git a/src/exact/ExactMapper.cpp b/src/exact/ExactMapper.cpp index 28fdf9e5d..20bf90f68 100644 --- a/src/exact/ExactMapper.cpp +++ b/src/exact/ExactMapper.cpp @@ -278,8 +278,7 @@ void ExactMapper::map(const Configuration& settings) { qcMapped.emplace_back( qcMapped.getNqubits(), locations.at(gate.target), op->getType(), - op->getParameter().at(0), op->getParameter().at(1), - op->getParameter().at(2)); + op->getParameter()); } else { const Edge cnot = {locations.at(static_cast(gate.control)), locations.at(gate.target)}; diff --git a/src/heuristic/HeuristicMapper.cpp b/src/heuristic/HeuristicMapper.cpp index 4a107a577..a92edacc9 100644 --- a/src/heuristic/HeuristicMapper.cpp +++ b/src/heuristic/HeuristicMapper.cpp @@ -82,15 +82,13 @@ void HeuristicMapper::map(const Configuration& configuration) { if (locations.at(gate.target) == DEFAULT_POSITION) { qcMapped.emplace_back( qcMapped.getNqubits(), gate.target, op->getType(), - op->getParameter().at(0), op->getParameter().at(1), - op->getParameter().at(2)); + op->getParameter()); gatesToAdjust.push_back(gateidx); gateidx++; } else { qcMapped.emplace_back( qcMapped.getNqubits(), locations.at(gate.target), op->getType(), - op->getParameter().at(0), op->getParameter().at(1), - op->getParameter().at(2)); + op->getParameter()); gateidx++; } } else { diff --git a/test/test_architecture.cpp b/test/test_architecture.cpp index 4e3460479..5aabacb67 100644 --- a/test/test_architecture.cpp +++ b/test/test_architecture.cpp @@ -6,6 +6,7 @@ #include "Architecture.hpp" #include "gtest/gtest.h" +#include class TestArchitecture : public testing::TestWithParam { protected: @@ -160,3 +161,69 @@ TEST(TestArchitecture, TestCouplingLimitRing) { architecture.loadCouplingMap(5, cm); EXPECT_EQ(architecture.getCouplingLimit(), 2); } + +TEST(TestArchitecture, opTypeFromString) { + Architecture arch{2, {{0, 1}}}; + auto& props = arch.getProperties(); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<> dis(0., 1.); + + const std::vector> singleQubitGates = { + {"i", qc::OpType::I}, + {"x", qc::OpType::X}, + {"y", qc::OpType::Y}, + {"z", qc::OpType::Z}, + {"sx", qc::OpType::SX}, + {"sxdg", qc::OpType::SXdag}, + {"h", qc::OpType::H}, + {"s", qc::OpType::S}, + {"sdg", qc::OpType::Sdag}, + {"t", qc::OpType::T}, + {"tdg", qc::OpType::Tdag}, + {"rx", qc::OpType::RX}, + {"ry", qc::OpType::RY}, + {"rz", qc::OpType::RZ}, + {"u1", qc::OpType::Phase}, + {"u2", qc::OpType::U2}, + {"u3", qc::OpType::U3}, + {"reset", qc::OpType::Reset}, + {"measure", qc::OpType::Measure}}; + + for (const auto& [opName, opType] : singleQubitGates) { + const auto errorRate = dis(gen); + + props.setSingleQubitErrorRate(0, opName, errorRate); + EXPECT_EQ(props.getSingleQubitErrorRate(0, opName), errorRate); + } + + const std::vector> twoQubitGates = { + {"cx", qc::OpType::X}, + {"cz", qc::OpType::Z}, + {"cy", qc::OpType::Y}, + {"ch", qc::OpType::H}, + {"swap", qc::OpType::SWAP}, + {"crx", qc::OpType::RX}, + {"ry", qc::OpType::RY}, + {"crz", qc::OpType::RZ}, + {"cu1", qc::OpType::Phase}, + {"cu2", qc::OpType::U2}, + {"cu3", qc::OpType::U3}, + {"iswap", qc::OpType::iSWAP}, + {"ecr", qc::OpType::ECR}, + {"dcx", qc::OpType::DCX}, + {"rxx", qc::OpType::RXX}, + {"rzz", qc::OpType::RZZ}, + {"ryy", qc::OpType::RYY}, + {"rzx", qc::OpType::RZX}, + {"xx_minus_yy", qc::OpType::XXminusYY}, + {"xx_plus_yy", qc::OpType::XXplusYY}}; + + for (const auto& [opName, opType] : twoQubitGates) { + const auto errorRate = dis(gen); + + props.setTwoQubitErrorRate(0, 1, errorRate, opName); + EXPECT_EQ(props.getTwoQubitErrorRate(0, 1, opName), errorRate); + } +} diff --git a/test/test_tableau.cpp b/test/test_tableau.cpp index 963c06d00..474962255 100644 --- a/test/test_tableau.cpp +++ b/test/test_tableau.cpp @@ -243,6 +243,9 @@ TEST_F(TestTableau, CircuitTranslation) { qc.y(1, 0_pc); qc.z(1, 0_pc); qc.swap(0, 1); + qc.iswap(0, 1); + qc.dcx(0, 1); + qc.ecr(0, 1); auto compOP = std::make_unique(2U); compOP->emplace_back(2U, 0, qc::H);