Repository: PennyLaneAI/pennylane (Python)

Issue:
[unitaryhack] Define decomposition for `qml.SWAP`
*This issue has been tagged for contributions during [unitaryHACK](https://unitaryfund.github.io/unitaryhack/participating-projects.html)*

Each PennyLane operation defines a decomposition. The decomposition of an operation is an ordered list of other operations. Applying this list of operations evolves quantum states the same way as applying the operation itself does. In most cases, this list includes elementary gates that are often supported by most quantum devices.

We would like to add the decomposition of the `qml.SWAP` operation by:
1. Defining the decomposition method for [the `qml.SWAP` operation](https://github.com/PennyLaneAI/pennylane/blob/1930230dde60112ad90af0951fa9295d374e1adf/pennylane/ops/qubit.py#L528) that has the following signature:
```python
    @staticmethod
    def decomposition(wires):
```
Other operations in the `pennylane/ops/qubit.py` file can serve as an example for defining this method (e.g., [see `qml.Hadamard`](https://github.com/PennyLaneAI/pennylane/blob/1930230dde60112ad90af0951fa9295d374e1adf/pennylane/ops/qubit.py#L87)).
2. Including a test case for the decomposition of `qml.SWAP` in the `tests/ops/test_qubit_ops.py` file to verify its correctness.


Discussion:

Patch:
diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index 8e0e2668718..912f614397e 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 <h3>New features since last release</h3>
 
+* The `qml.SWAP`  operation now has a decomposition over elementary gates. [(#1329)](https://github.com/PennyLaneAI/pennylane/pull/1329)
+
 * Added functionality for constructing and manipulating the Pauli group
   [(#1181)](https://github.com/PennyLaneAI/pennylane/pull/1181).
   The function `pennylane.grouping.pauli_group` provides a generator to
@@ -250,7 +252,7 @@ random_mat2 = rng.standard_normal(3, requires_grad=False)
 
 This release contains contributions from (in alphabetical order):
 
-Thomas Bromley, Olivia Di Matteo, Diego Guala, Anthony Hayes, Josh Izaac, Brian Shi, Antal Száva, Pavan Jayasinha
+Vishnu Ajith, Thomas Bromley, Olivia Di Matteo, Diego Guala, Anthony Hayes, Josh Izaac, Brian Shi, Antal Száva, Pavan Jayasinha
 
 # Release 0.15.1 (current release)
 
diff --git a/pennylane/ops/qubit.py b/pennylane/ops/qubit.py
index 61a9cfcf3f0..8ae55f07bc5 100644
--- a/pennylane/ops/qubit.py
+++ b/pennylane/ops/qubit.py
@@ -526,6 +526,15 @@ class SWAP(Operation):
     def _matrix(cls, *params):
         return cls.matrix
 
+    @staticmethod
+    def decomposition(wires):
+        decomp_ops = [
+            qml.CNOT(wires=[wires[0], wires[1]]),
+            qml.CNOT(wires=[wires[1], wires[0]]),
+            qml.CNOT(wires=[wires[0], wires[1]]),
+        ]
+        return decomp_ops
+
     def adjoint(self):
         return SWAP(wires=self.wires)
 


Test patch:
diff --git a/tests/ops/test_qubit_ops.py b/tests/ops/test_qubit_ops.py
index 83d1181a1ad..57a9670325c 100644
--- a/tests/ops/test_qubit_ops.py
+++ b/tests/ops/test_qubit_ops.py
@@ -923,6 +923,22 @@ def test_iswap_eigenval(self):
         res = op.eigvals
         assert np.allclose(res, exp)
 
+    def test_swap_decomposition(self):
+        """Tests the swap operator produces the correct output"""
+        opr = qml.SWAP(wires=[0, 1])
+        decomp = opr.decomposition([0, 1])
+
+        mat = []
+        for op in reversed(decomp):
+            if isinstance(op, qml.CNOT) and op.wires.tolist() == [0, 1]:
+                mat.append(CNOT)
+            elif isinstance(op, qml.CNOT) and op.wires.tolist() == [1, 0]:
+                mat.append(np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]]))
+
+        decomposed_matrix = np.linalg.multi_dot(mat)
+
+        assert np.allclose(decomposed_matrix, opr.matrix)
+
     @pytest.mark.parametrize("phi", [-0.1, 0.2, 0.5])
     def test_controlled_phase_shift_matrix_and_eigvals(self, phi):
         """Tests that the ControlledPhaseShift operation calculates the correct matrix and