Skip to content

Commit

Permalink
✨ added inverse gate for iSWAP (#460)
Browse files Browse the repository at this point in the history
## Description

The DD Package was missing the ```iSWAPDag``` (iSWAP dagger) gate.
However, the DD Package already had in some place a ```ISWAPDG_MAT```
which implemented the desired gate in a matrix form.

## Status
Currently, the `iSWAPdagDumpIsValid` test produces the following error:
```
gate type iswapdg could not be converted to OpenQASM

i:   0   1
1:iswdiswd
o:   0   1

~/mqt-core/test/unittests/test_io.cpp:389: Failure
Expected: qc->import(ss, qc::Format::OpenQASM); doesn't throw an exception.
  Actual: it throws std::runtime_error with description "[qasm parser] l:6 c:2 msg: Unknown gate q".


i:   0   1
o:   0   1
```

After reading through
[https://qiskit.org/documentation/apidoc/circuit_library.html](url), my
assumption is that OpenQASM does not support at the moment the iSWAP
dagger gate natively, so, therefore, it doesn't have implementation for
it.

(I know that the previous assumption might not be the reason why, but I
tried to point out a tiny direction why this might not work. Anyway, I
will try to look further into this issue in the near future)

Fixes #423 <!--- Replace (issue) with the issue number that is fixed by
this pull request. -->

## Checklist:

<!---
This checklist serves as a reminder of a couple of things that ensure
your pull request will be merged swiftly.
-->

- [x] The pull request only contains commits that are related to it.
- [ ] I have added appropriate tests and documentation.
- [ ] I have made sure that all CI jobs on GitHub pass.
- [ ] The pull request introduces no new warnings and follows the
project's style guidelines.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
BertiFlorea and pre-commit-ci[bot] authored Nov 18, 2023
1 parent 95541a6 commit 1ee8f70
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 20 deletions.
1 change: 1 addition & 0 deletions include/QuantumComputation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
8 changes: 8 additions & 0 deletions include/dd/Operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion include/operations/OpType.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -188,6 +193,7 @@ inline bool isTwoQubitGate(const OpType& opType) {
switch (opType) {
case SWAP:
case iSWAP:
case iSWAPdg:
case Peres:
case Peresdg:
case DCX:
Expand Down Expand Up @@ -262,6 +268,7 @@ const inline static std::unordered_map<std::string, qc::OpType>
{"swap", OpType::SWAP},
{"cswap", OpType::SWAP},
{"iswap", OpType::iSWAP},
{"iswapdg", OpType::iSWAPdg},
{"peres", OpType::Peres},
{"peresdg", OpType::Peresdg},
{"dcx", OpType::DCX},
Expand Down
1 change: 1 addition & 0 deletions include/parsers/qasm_parser/Parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}},
Expand Down
3 changes: 3 additions & 0 deletions src/mqt/core/_core/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
31 changes: 16 additions & 15 deletions src/mqt/core/_core/operations.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -35,42 +35,43 @@ class Control:
class OpType:
__members__: ClassVar[dict[OpType, str]] # readonly
barrier: ClassVar[OpType] # value = <OpType.barrier: 3>
classic_controlled: ClassVar[OpType] # value = <OpType.classic_controlled: 38>
compound: ClassVar[OpType] # value = <OpType.compound: 34>
dcx: ClassVar[OpType] # value = <OpType.dcx: 26>
ecr: ClassVar[OpType] # value = <OpType.ecr: 27>
classic_controlled: ClassVar[OpType] # value = <OpType.classic_controlled: 39>
compound: ClassVar[OpType] # value = <OpType.compound: 35>
dcx: ClassVar[OpType] # value = <OpType.dcx: 27>
ecr: ClassVar[OpType] # value = <OpType.ecr: 28>
gphase: ClassVar[OpType] # value = <OpType.gphase: 1>
h: ClassVar[OpType] # value = <OpType.h: 4>
i: ClassVar[OpType] # value = <OpType.i: 2>
iswap: ClassVar[OpType] # value = <OpType.iswap: 23>
measure: ClassVar[OpType] # value = <OpType.measure: 35>
iswapdg: ClassVar[OpType] # value = <OpType.iswapdg: 24>
measure: ClassVar[OpType] # value = <OpType.measure: 36>
none: ClassVar[OpType] # value = <OpType.none: 0>
peres: ClassVar[OpType] # value = <OpType.peres: 24>
peresdg: ClassVar[OpType] # value = <OpType.peresdg: 25>
peres: ClassVar[OpType] # value = <OpType.peres: 25>
peresdg: ClassVar[OpType] # value = <OpType.peresdg: 26>
p: ClassVar[OpType] # value = <OpType.p: 16>
reset: ClassVar[OpType] # value = <OpType.reset: 36>
reset: ClassVar[OpType] # value = <OpType.reset: 37>
rx: ClassVar[OpType] # value = <OpType.rx: 19>
rxx: ClassVar[OpType] # value = <OpType.rxx: 28>
rxx: ClassVar[OpType] # value = <OpType.rxx: 29>
ry: ClassVar[OpType] # value = <OpType.ry: 20>
ryy: ClassVar[OpType] # value = <OpType.ryy: 29>
ryy: ClassVar[OpType] # value = <OpType.ryy: 30>
rz: ClassVar[OpType] # value = <OpType.rz: 21>
rzx: ClassVar[OpType] # value = <OpType.rzx: 31>
rzz: ClassVar[OpType] # value = <OpType.rzz: 30>
rzx: ClassVar[OpType] # value = <OpType.rzx: 32>
rzz: ClassVar[OpType] # value = <OpType.rzz: 31>
s: ClassVar[OpType] # value = <OpType.s: 8>
sdg: ClassVar[OpType] # value = <OpType.sdg: 9>
swap: ClassVar[OpType] # value = <OpType.swap: 22>
sx: ClassVar[OpType] # value = <OpType.sx: 17>
sxdg: ClassVar[OpType] # value = <OpType.sxdg: 18>
t: ClassVar[OpType] # value = <OpType.t: 10>
tdg: ClassVar[OpType] # value = <OpType.tdg: 11>
teleportation: ClassVar[OpType] # value = <OpType.teleportation: 37>
teleportation: ClassVar[OpType] # value = <OpType.teleportation: 38>
u2: ClassVar[OpType] # value = <OpType.u2: 15>
u: ClassVar[OpType] # value = <OpType.u: 14>
v: ClassVar[OpType] # value = <OpType.v: 12>
vdg: ClassVar[OpType] # value = <OpType.vdg: 13>
x: ClassVar[OpType] # value = <OpType.x: 5>
xx_minus_yy: ClassVar[OpType] # value = <OpType.xx_minus_yy: 32>
xx_plus_yy: ClassVar[OpType] # value = <OpType.xx_plus_yy: 33>
xx_minus_yy: ClassVar[OpType] # value = <OpType.xx_minus_yy: 33>
xx_plus_yy: ClassVar[OpType] # value = <OpType.xx_plus_yy: 34>
y: ClassVar[OpType] # value = <OpType.y: 6>
z: ClassVar[OpType] # value = <OpType.z: 7>
@property
Expand Down
9 changes: 8 additions & 1 deletion src/operations/StandardOperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions src/python/operations/register_optype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 14 additions & 2 deletions test/dd/test_dd_functionality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DDFunctionality::ParamType>& inf) {
const auto gate = inf.param;
return toString(gate);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
10 changes: 10 additions & 0 deletions test/unittests/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion test/unittests/test_qfr_functionality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 1ee8f70

Please sign in to comment.