diff --git a/include/QuantumComputation.hpp b/include/QuantumComputation.hpp index 2d8ceb683..b1879c60e 100644 --- a/include/QuantumComputation.hpp +++ b/include/QuantumComputation.hpp @@ -479,6 +479,7 @@ class QuantumComputation { DEFINE_TWO_TARGET_OPERATION(dcx) DEFINE_TWO_TARGET_OPERATION(ecr) DEFINE_TWO_TARGET_OPERATION(iswap) + DEFINE_TWO_TARGET_OPERATION(iswapdg) DEFINE_TWO_TARGET_OPERATION(peres) DEFINE_TWO_TARGET_OPERATION(peresdg) diff --git a/include/dd/Operations.hpp b/include/dd/Operations.hpp index b7ba6f104..8c9676b37 100644 --- a/include/dd/Operations.hpp +++ b/include/dd/Operations.hpp @@ -121,6 +121,9 @@ qc::MatrixDD getStandardOperationDD(const qc::StandardOperation* op, case qc::iSWAP: gm = inverse ? ISWAPDG_MAT : ISWAP_MAT; break; + case qc::iSWAPdg: + gm = inverse ? ISWAP_MAT : ISWAPDG_MAT; + break; case qc::DCX: gm = DCX_MAT; break; @@ -165,6 +168,11 @@ qc::MatrixDD getStandardOperationDD(const qc::StandardOperation* op, startQubit); } return dd->makeiSWAPDD(nqubits, controls, target0, target1, startQubit); + case qc::iSWAPdg: + if (inverse) { + return dd->makeiSWAPDD(nqubits, controls, target0, target1, startQubit); + } + return dd->makeiSWAPinvDD(nqubits, controls, target0, target1, startQubit); case qc::Peres: if (inverse) { return dd->makePeresdagDD(nqubits, controls, target0, target1, diff --git a/include/operations/OpType.hpp b/include/operations/OpType.hpp index 8037858e2..a18f8fbc4 100644 --- a/include/operations/OpType.hpp +++ b/include/operations/OpType.hpp @@ -33,7 +33,8 @@ enum OpType : std::uint8_t { RY, RZ, SWAP, - iSWAP, // NOLINT (readability-identifier-naming) + iSWAP, // NOLINT (readability-identifier-naming) + iSWAPdg, // NOLINT (readability-identifier-naming) Peres, Peresdg, DCX, @@ -109,6 +110,8 @@ inline std::string toString(const OpType& opType) { return "swap"; case iSWAP: return "iswap"; + case iSWAPdg: + return "iswapdg"; case Peres: return "peres"; case Peresdg: @@ -163,6 +166,8 @@ inline std::string shortName(const OpType& opType) { return "sw"; case iSWAP: return "isw"; + case iSWAPdg: + return "isd"; case Peres: return "pr"; case Peresdg: @@ -188,6 +193,7 @@ inline bool isTwoQubitGate(const OpType& opType) { switch (opType) { case SWAP: case iSWAP: + case iSWAPdg: case Peres: case Peresdg: case DCX: @@ -262,6 +268,7 @@ const inline static std::unordered_map {"swap", OpType::SWAP}, {"cswap", OpType::SWAP}, {"iswap", OpType::iSWAP}, + {"iswapdg", OpType::iSWAPdg}, {"peres", OpType::Peres}, {"peresdg", OpType::Peresdg}, {"dcx", OpType::DCX}, diff --git a/include/parsers/qasm_parser/Parser.hpp b/include/parsers/qasm_parser/Parser.hpp index c3809dad2..f7d7a9297 100644 --- a/include/parsers/qasm_parser/Parser.hpp +++ b/include/parsers/qasm_parser/Parser.hpp @@ -151,6 +151,7 @@ class Parser { {"teleport", {0, 3, 0, qc::Teleportation}}, {"swap", {0, 2, 0, qc::SWAP}}, {"iswap", {0, 2, 0, qc::iSWAP}}, + {"iswapdg", {0, 2, 0, qc::iSWAPdg}}, {"cnot", {1, 1, 0, qc::X}}, {"CX", {1, 1, 0, qc::X}}, {"cx", {1, 1, 0, qc::X}}, diff --git a/src/mqt/core/_core/__init__.pyi b/src/mqt/core/_core/__init__.pyi index 4218cb471..91bb455d0 100644 --- a/src/mqt/core/_core/__init__.pyi +++ b/src/mqt/core/_core/__init__.pyi @@ -217,6 +217,9 @@ class QuantumComputation(MutableSequence[Operation]): def iswap(self: Self, target1: int, target2: int) -> None: ... def ciswap(self: Self, control: Control | int, target1: int, target2: int) -> None: ... def mciswap(self: Self, controls: set[Control | int], target1: int, target2: int) -> None: ... + def iswapdg(self: Self, target1: int, target2: int) -> None: ... + def ciswapdg(self: Self, control: Control | int, target1: int, target2: int) -> None: ... + def mciswapdg(self: Self, controls: set[Control | int], target1: int, target2: int) -> None: ... def peres(self: Self, target1: int, target2: int) -> None: ... def cperes(self: Self, control: Control | int, target1: int, target2: int) -> None: ... def mcperes(self: Self, controls: set[Control | int], target1: int, target2: int) -> None: ... diff --git a/src/mqt/core/_core/operations.pyi b/src/mqt/core/_core/operations.pyi index 1b1a47043..ae2140b53 100644 --- a/src/mqt/core/_core/operations.pyi +++ b/src/mqt/core/_core/operations.pyi @@ -35,27 +35,28 @@ class Control: class OpType: __members__: ClassVar[dict[OpType, str]] # readonly barrier: ClassVar[OpType] # value = - classic_controlled: ClassVar[OpType] # value = - compound: ClassVar[OpType] # value = - dcx: ClassVar[OpType] # value = - ecr: ClassVar[OpType] # value = + classic_controlled: ClassVar[OpType] # value = + compound: ClassVar[OpType] # value = + dcx: ClassVar[OpType] # value = + ecr: ClassVar[OpType] # value = gphase: ClassVar[OpType] # value = h: ClassVar[OpType] # value = i: ClassVar[OpType] # value = iswap: ClassVar[OpType] # value = - measure: ClassVar[OpType] # value = + iswapdg: ClassVar[OpType] # value = + measure: ClassVar[OpType] # value = none: ClassVar[OpType] # value = - peres: ClassVar[OpType] # value = - peresdg: ClassVar[OpType] # value = + peres: ClassVar[OpType] # value = + peresdg: ClassVar[OpType] # value = p: ClassVar[OpType] # value = - reset: ClassVar[OpType] # value = + reset: ClassVar[OpType] # value = rx: ClassVar[OpType] # value = - rxx: ClassVar[OpType] # value = + rxx: ClassVar[OpType] # value = ry: ClassVar[OpType] # value = - ryy: ClassVar[OpType] # value = + ryy: ClassVar[OpType] # value = rz: ClassVar[OpType] # value = - rzx: ClassVar[OpType] # value = - rzz: ClassVar[OpType] # value = + rzx: ClassVar[OpType] # value = + rzz: ClassVar[OpType] # value = s: ClassVar[OpType] # value = sdg: ClassVar[OpType] # value = swap: ClassVar[OpType] # value = @@ -63,14 +64,14 @@ class OpType: sxdg: ClassVar[OpType] # value = t: ClassVar[OpType] # value = tdg: ClassVar[OpType] # value = - teleportation: ClassVar[OpType] # value = + teleportation: ClassVar[OpType] # value = u2: ClassVar[OpType] # value = u: ClassVar[OpType] # value = v: ClassVar[OpType] # value = vdg: ClassVar[OpType] # value = x: ClassVar[OpType] # value = - xx_minus_yy: ClassVar[OpType] # value = - xx_plus_yy: ClassVar[OpType] # value = + xx_minus_yy: ClassVar[OpType] # value = + xx_plus_yy: ClassVar[OpType] # value = y: ClassVar[OpType] # value = z: ClassVar[OpType] # value = @property diff --git a/src/operations/StandardOperation.cpp b/src/operations/StandardOperation.cpp index 340c568f0..17b5841e7 100644 --- a/src/operations/StandardOperation.cpp +++ b/src/operations/StandardOperation.cpp @@ -368,6 +368,9 @@ void StandardOperation::dumpOpenQASM( case iSWAP: op << "iswap"; break; + case iSWAPdg: + op << "iswapdg"; + break; case Peres: of << op.str() << "cx"; for (const auto& c : controls) { @@ -541,8 +544,12 @@ void StandardOperation::invert() { case Peresdg: type = Peres; break; - // Tracking issue for iSwap: https://github.com/cda-tum/mqt-core/issues/423 case iSWAP: + type = iSWAPdg; + break; + case iSWAPdg: + type = iSWAP; + break; case None: case Compound: case Measure: diff --git a/src/python/operations/register_optype.cpp b/src/python/operations/register_optype.cpp index bb1799b0b..c36c18ad7 100644 --- a/src/python/operations/register_optype.cpp +++ b/src/python/operations/register_optype.cpp @@ -30,6 +30,7 @@ void registerOptype(py::module& m) { .value("rz", qc::OpType::RZ) .value("swap", qc::OpType::SWAP) .value("iswap", qc::OpType::iSWAP) + .value("iswapdg", qc::OpType::iSWAPdg) .value("peres", qc::OpType::Peres) .value("peresdg", qc::OpType::Peresdg) .value("dcx", qc::OpType::DCX) diff --git a/test/dd/test_dd_functionality.cpp b/test/dd/test_dd_functionality.cpp index ef2af2def..243cb5a18 100644 --- a/test/dd/test_dd_functionality.cpp +++ b/test/dd/test_dd_functionality.cpp @@ -57,8 +57,9 @@ INSTANTIATE_TEST_SUITE_P( testing::Values(qc::GPhase, qc::I, qc::H, qc::X, qc::Y, qc::Z, qc::S, qc::Sdg, qc::T, qc::Tdg, qc::SX, qc::SXdg, qc::V, qc::Vdg, qc::U, qc::U2, qc::P, qc::RX, qc::RY, qc::RZ, qc::Peres, - qc::Peresdg, qc::SWAP, qc::iSWAP, qc::DCX, qc::ECR, qc::RXX, - qc::RYY, qc::RZZ, qc::RZX, qc::XXminusYY, qc::XXplusYY), + qc::Peresdg, qc::SWAP, qc::iSWAP, qc::iSWAPdg, qc::DCX, + qc::ECR, qc::RXX, qc::RYY, qc::RZZ, qc::RZX, qc::XXminusYY, + qc::XXplusYY), [](const testing::TestParamInfo& inf) { const auto gate = inf.param; return toString(gate); @@ -91,6 +92,7 @@ TEST_P(DDFunctionality, standardOpBuildInverseBuild) { case qc::SWAP: case qc::iSWAP: + case qc::iSWAPdg: case qc::DCX: case qc::ECR: op = qc::StandardOperation(nqubits, Controls{}, 0, 1, gate); @@ -126,6 +128,11 @@ TEST_F(DDFunctionality, buildCircuit) { qc.x(0); qc.swap(0, 1); + qc.cswap(2, 0, 1); + qc.mcswap({2, 3}, 0, 1); + qc.iswap(0, 1); + qc.ciswap(2, 0, 1); + qc.mciswap({2, 3}, 0, 1); qc.h(0); qc.s(3); qc.sdg(2); @@ -178,6 +185,11 @@ TEST_F(DDFunctionality, buildCircuit) { qc.s(2); qc.sdg(3); qc.h(0); + qc.mciswapdg({2, 3}, 0, 1); + qc.ciswapdg(2, 0, 1); + qc.iswapdg(0, 1); + qc.mcswap({2, 3}, 0, 1); + qc.cswap(2, 0, 1); qc.swap(0, 1); qc.x(0); diff --git a/test/unittests/test_io.cpp b/test/unittests/test_io.cpp index 9f7ce9acb..c2b611a0d 100644 --- a/test/unittests/test_io.cpp +++ b/test/unittests/test_io.cpp @@ -380,6 +380,16 @@ TEST_F(IO, iSWAPDumpIsValid) { std::cout << *qc << "\n"; } +TEST_F(IO, iSWAPdagDumpIsValid) { + qc->addQubitRegister(2); + qc->iswapdg(0, 1); + std::cout << *qc << "\n"; + std::stringstream ss{}; + qc->dumpOpenQASM(ss); + EXPECT_NO_THROW(qc->import(ss, qc::Format::OpenQASM);); + std::cout << *qc << "\n"; +} + TEST_F(IO, PeresDumpIsValid) { qc->addQubitRegister(2); qc->peres(0, 1); diff --git a/test/unittests/test_qfr_functionality.cpp b/test/unittests/test_qfr_functionality.cpp index b285a0919..347b2ba42 100644 --- a/test/unittests/test_qfr_functionality.cpp +++ b/test/unittests/test_qfr_functionality.cpp @@ -772,6 +772,9 @@ TEST_F(QFRFunctionality, gateShortCutsAndCloning) { qc.iswap(0, 1); qc.ciswap(2, 0, 1); qc.mciswap({2, 3_nc}, 0, 1); + qc.iswapdg(0, 1); + qc.ciswapdg(2, 0, 1); + qc.mciswapdg({2, 3_nc}, 0, 1); qc.peres(0, 1); qc.cperes(2, 0, 1); qc.mcperes({2, 3_nc}, 0, 1); @@ -2161,7 +2164,7 @@ TEST_F(QFRFunctionality, invertStandardOpInvertClone) { TEST_F(QFRFunctionality, invertStandardOpSpecial) { const auto opTypes = { std::pair{S, Sdg}, std::pair{T, Tdg}, std::pair{V, Vdg}, - std::pair{SX, SXdg}, std::pair{Peres, Peresdg}, + std::pair{SX, SXdg}, std::pair{Peres, Peresdg}, std::pair{iSWAP, iSWAPdg}, }; for (const auto& [opType, opTypeInv] : opTypes) {