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.

Pull request:
[unitaryHACK] Added SWAP gate decomposition and related tests
**Context:**
Added SWAP decomposition and wrote tests to it

**Description of the Change:**
added the the function 
 ``` 
  @staticmethod
    def decomposition(wires): 
```
to ` pennylane/ops/qubit.py `  and tests for it at ` tests/ops/test_qubit_ops.py `

**Possible Drawbacks:**
similar to #1313 
**Related GitHub Issues:**
resolves #1304


Patch:
diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index 8e0e26687..912f61439 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 61a9cfcf3..8ae55f07b 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 83d1181a1..57a967032 100644
--- a/tests/ops/test_qubit_ops.py
+++ b/tests/ops/test_qubit_ops.py
@@ -923,6 +923,22 @@ class TestOperations:
         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