Repository: PennyLaneAI/pennylane
Pull request #1321 (2021-05-15 19:40:47)

[unitaryHACK] Add reset error to noise channels
**Context:** Add Reset Error to noise channels

**Description of the Change:**  Add Single-qubit Reset error channel to pennylane.

**Benefits:** Add a new noise model that simulates the reset of qubits to 0 or 1 given a probability.

**Possible Drawbacks:**

**Related GitHub Issues:** #971 


josh146: Hi @nahumsa! Thanks for this PR -- this is a great issue to tackle. Just a bit of housekeeping before we can provide a review:

- The formatting check is failing. All that is required is that the PennyLane source code and tests folder is 'blacked' using the Black formatting tool:

  ```python
  pip install black
  black -l 100 pennylane
  black -l 100 tests
  ```

- The documentation check is also failing, due to a missing space after the backtick in the docstring:
  ```
  :math:`p_1 \in [0, 1]`is
  ```

  You can click on the 'details' link beside the `docs/readthedocs.org:pennylane` CI check to view what the rendered documentation for your PR looks like, to make sure it looks okay when built :)

  ![image](https://user-images.githubusercontent.com/2959003/118443694-cc55a980-b71e-11eb-84e9-4e09d3558b4c.png)

- Finally, it looks like there is an issue with the new tests, causing the test CI to fail.

Let us know when these have been addressed, and the PR is ready for review! Alternatively, feel free to ask any questions.
nahumsa: Thanks for the response, @josh146 ! I will fix those issues and let you know when it's ready for a review.
nahumsa: I think that this is ready for review.
josh146: Oh, and don't forget to add your name to the Contributors section of the changelog!
nahumsa: > Oh, and don't forget to add your name to the Contributors section of the changelog!

Sure! :)
codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#1321](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (77ab397) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/012704f3da025004115b28d706b61a2901d1f31e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (012704f) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321/graphs/tree.svg?width=650&height=150&src=pr&token=9S3YzlUgGk&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)

```diff
@@           Coverage Diff           @@
##           master    #1321   +/-   ##
=======================================
  Coverage   98.15%   98.16%           
=======================================
  Files         145      145           
  Lines       11079    11093   +14     
=======================================
+ Hits        10875    10889   +14     
  Misses        204      204           
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/ops/channel.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9jaGFubmVsLnB5) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Last update [012704f...77ab397](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1321?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).


Patch:
diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index eeb6e538d..64120bf97 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -7,6 +7,9 @@
 * The `qml.Toffoli` operation now has a decomposition over elementary gates. 
   [(#1320)](https://github.com/PennyLaneAI/pennylane/pull/1320)
 
+* Added a new noise channel, `qml.ResetError`.
+  [(#1321)](https://github.com/PennyLaneAI/pennylane/pull/1321).
+
 * 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
diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py
index a88ae9dce..630c5910b 100644
--- a/pennylane/ops/channel.py
+++ b/pennylane/ops/channel.py
@@ -267,6 +267,71 @@ class BitFlip(Channel):
         return [K0, K1]
 
 
+class ResetError(Channel):
+    r"""ResetError(p_0, p_1, wires)
+    Single-qubit Reset error channel.
+
+    This channel is modelled by the following Kraus matrices:
+
+    .. math::
+        K_0 = \sqrt{1-p_0-p_1} \begin{bmatrix}
+                1 & 0 \\
+                0 & 1
+                \end{bmatrix}
+
+    .. math::
+        K_1 = \sqrt{p_0}\begin{bmatrix}
+                1 & 0  \\
+                0 & 0
+                \end{bmatrix}
+
+    .. math::
+        K_2 = \sqrt{p_0}\begin{bmatrix}
+                0 & 1  \\
+                0 & 0
+                \end{bmatrix}
+
+    .. math::
+        K_3 = \sqrt{p_1}\begin{bmatrix}
+                0 & 0  \\
+                1 & 0
+                \end{bmatrix}
+
+    .. math::
+        K_4 = \sqrt{p_1}\begin{bmatrix}
+                0 & 0  \\
+                0 & 1
+                \end{bmatrix}
+
+    where :math:`p_0 \in [0, 1]` is the probability of a reset to 0,
+    and :math:`p_1 \in [0, 1]` is the probability of a reset to 1 error.
+
+    **Details:**
+
+    * Number of wires: 1
+    * Number of parameters: 2
+
+    Args:
+        p_0 (float): The probability that a reset to 0 error occurs.
+        p_1 (float): The probability that a reset to 1 error occurs.
+        wires (Sequence[int] or int): the wire the channel acts on
+    """
+    num_params = 2
+    num_wires = 1
+    par_domain = "R"
+    grad_method = "F"
+
+    @classmethod
+    def _kraus_matrices(cls, *params):
+        p_0, p_1 = params[0], params[1]
+        K0 = np.sqrt(1 - p_0 - p_1) * np.eye(2)
+        K1 = np.sqrt(p_0) * np.array([[1, 0], [0, 0]])
+        K2 = np.sqrt(p_0) * np.array([[0, 1], [0, 0]])
+        K3 = np.sqrt(p_1) * np.array([[0, 0], [1, 0]])
+        K4 = np.sqrt(p_1) * np.array([[0, 0], [0, 1]])
+        return [K0, K1, K2, K3, K4]
+
+
 class PhaseFlip(Channel):
     r"""PhaseFlip(p, wires)
     Single-qubit bit flip (Pauli :math:`Z`) error channel.
@@ -371,6 +436,7 @@ __qubit_channels__ = {
     "DepolarizingChannel",
     "BitFlip",
     "PhaseFlip",
+    "ResetError",
     "QubitChannel",
 }
 


Test patch:
diff --git a/tests/ops/test_channel_ops.py b/tests/ops/test_channel_ops.py
index 83af67732..d4b85e321 100644
--- a/tests/ops/test_channel_ops.py
+++ b/tests/ops/test_channel_ops.py
@@ -32,6 +32,7 @@ ch_list = [
     channel.BitFlip,
     channel.PhaseFlip,
     channel.DepolarizingChannel,
+    channel.ResetError,
 ]
 
 
@@ -44,6 +45,8 @@ class TestChannels:
         """Test channels are trace-preserving"""
         if ops.__name__ == "GeneralizedAmplitudeDamping":
             op = ops(p, p, wires=0)
+        elif ops.__name__ == "ResetError":
+            op = ops(p / 2, p / 3, wires=0)
         else:
             op = ops(p, wires=0)
         K_list = op.kraus_matrices
@@ -213,6 +216,30 @@ class TestDepolarizingChannel:
         assert np.allclose(gradient, -(4 / 3) * np.cos(angle))
 
 
+class TestResetError:
+    """Tests for the quantum channel ResetError"""
+
+    @pytest.mark.parametrize("p_0,p_1", list(zip([0.5, 0.1, 0.0, 0.0], [0, 0.1, 0.5, 0.0])))
+    def test_p0_p1_arbitrary(self, p_0, p_1, tol):
+        """Test that various values of p_0 and p_1 give correct Kraus matrices"""
+        op = channel.ResetError
+
+        expected_K0 = np.sqrt(1 - p_0 - p_1) * np.eye(2)
+        assert np.allclose(op(p_0, p_1, wires=0).kraus_matrices[0], expected_K0, atol=tol, rtol=0)
+
+        expected_K1 = np.sqrt(p_0) * np.array([[1, 0], [0, 0]])
+        assert np.allclose(op(p_0, p_1, wires=0).kraus_matrices[1], expected_K1, atol=tol, rtol=0)
+
+        expected_K2 = np.sqrt(p_0) * np.array([[0, 1], [0, 0]])
+        assert np.allclose(op(p_0, p_1, wires=0).kraus_matrices[2], expected_K2, atol=tol, rtol=0)
+
+        expected_K3 = np.sqrt(p_1) * np.array([[0, 0], [1, 0]])
+        assert np.allclose(op(p_0, p_1, wires=0).kraus_matrices[3], expected_K3, atol=tol, rtol=0)
+
+        expected_K4 = np.sqrt(p_1) * np.array([[0, 0], [0, 1]])
+        assert np.allclose(op(p_0, p_1, wires=0).kraus_matrices[4], expected_K4, atol=tol, rtol=0)
+
+
 class TestQubitChannel:
     """Tests for the quantum channel QubitChannel"""