Repository: PennyLaneAI/pennylane
Pull request #2015 (2021-12-11 22:11:15)

Fix two-qubit decomp to consider arbitrary number of unitaries
**Context:** Circuits with >3 two-qubit unitaries were yielding a `RecursionError` when put through the `unitary_to_rot` transform.

**Description of the Change:** Fixes the queuing in the `two_qubit_decomposition` method and adds a relevant unit test.

**Benefits:** Arbitrary number of two-qubit unitaries can now be decomposed.

**Possible Drawbacks:** None; although, I'm admittedly not sure why this fixed the problem.

**Related GitHub Issues:** #2014 


github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#2015](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (eff11db) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/b855176ebd5c84a49f51babce0a6d5af1ef29142?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (b855176) will **decrease** coverage by `1.94%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/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/2015?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)

```diff
@@            Coverage Diff             @@
##           master    #2015      +/-   ##
==========================================
- Coverage   99.12%   97.18%   -1.95%     
==========================================
  Files         221      221              
  Lines       16793    16792       -1     
==========================================
- Hits        16646    16319     -327     
- Misses        147      473     +326     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [...ane/transforms/decompositions/two\_qubit\_unitary.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3RyYW5zZm9ybXMvZGVjb21wb3NpdGlvbnMvdHdvX3F1Yml0X3VuaXRhcnkucHk=) | `100.00% <100.00%> (ø)` | |
| [pennylane/interfaces/batch/jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2ludGVyZmFjZXMvYmF0Y2gvamF4LnB5) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pennylane/interfaces/jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2ludGVyZmFjZXMvamF4LnB5) | `0.00% <0.00%> (-97.44%)` | :arrow_down: |
| [pennylane/devices/default\_qubit\_jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RldmljZXMvZGVmYXVsdF9xdWJpdF9qYXgucHk=) | `0.00% <0.00%> (-95.00%)` | :arrow_down: |
| [pennylane/qnn/cost.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3Fubi9jb3N0LnB5) | `42.85% <0.00%> (-57.15%)` | :arrow_down: |
| [pennylane/transforms/classical\_jacobian.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3RyYW5zZm9ybXMvY2xhc3NpY2FsX2phY29iaWFuLnB5) | `80.00% <0.00%> (-20.00%)` | :arrow_down: |
| [pennylane/math/utils.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvdXRpbHMucHk=) | `81.81% <0.00%> (-18.19%)` | :arrow_down: |
| [pennylane/math/multi\_dispatch.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvbXVsdGlfZGlzcGF0Y2gucHk=) | `86.84% <0.00%> (-13.16%)` | :arrow_down: |
| [pennylane/math/is\_independent.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvaXNfaW5kZXBlbmRlbnQucHk=) | `88.50% <0.00%> (-11.50%)` | :arrow_down: |
| [pennylane/collections/sum.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2NvbGxlY3Rpb25zL3N1bS5weQ==) | `89.47% <0.00%> (-10.53%)` | :arrow_down: |
| ... and [12 more](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015?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/2015?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Last update [b855176...eff11db](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2015?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).

glassnotes: > Thanks @glassnotes! Should we merge this into v0.20.0-rc0 instead? v0.20 is due to be released this Tuesday :)

Your call - it's not a critical bug that will affect a lot of things, so I think it'd be fine to wait until the next release, but I'm good either way!
josh146: >  so I think it'd be fine to wait until the next release,

Okay, lets leave it for 0.21! More time for it to be tested as well.

Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index c73686811..e1af8f97b 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -8,9 +8,17 @@
 
 <h3>Breaking changes</h3>
 
+<h3>Bug fixes</h3>
+
+* Fixes a bug in queueing of the `two_qubit_decomposition` method that
+  originally led to circuits with >3 two-qubit unitaries failing when passed
+  through the `unitary_to_rot` optimization transform.
+  [(#2015)](https://github.com/PennyLaneAI/pennylane/pull/2015)
+
 <h3>Documentation</h3>
 
 <h3>Contributors</h3>
 
 This release contains contributions from (in alphabetical order):
 
+Olivia Di Matteo
\ No newline at end of file
diff --git a/pennylane/transforms/decompositions/two_qubit_unitary.py b/pennylane/transforms/decompositions/two_qubit_unitary.py
index f0e5f3e5b..a7177268f 100644
--- a/pennylane/transforms/decompositions/two_qubit_unitary.py
+++ b/pennylane/transforms/decompositions/two_qubit_unitary.py
@@ -611,9 +611,8 @@ def two_qubit_decomposition(U, wires):
     # If there is an active tape, queue the decomposition so that expand works
     current_tape = qml.tape.get_active_tape()
 
-    if current_tape:
-        with current_tape:
-            for op in decomp:
-                qml.apply(op)
+    if current_tape is not None:
+        for op in decomp:
+            qml.apply(op, context=current_tape)
 
     return decomp


Test patch:
diff --git a/tests/transforms/test_unitary_to_rot.py b/tests/transforms/test_unitary_to_rot.py
index 579349df0..42601a25c 100644
--- a/tests/transforms/test_unitary_to_rot.py
+++ b/tests/transforms/test_unitary_to_rot.py
@@ -27,6 +27,8 @@ from pennylane.transforms import unitary_to_rot
 
 from gate_data import I, Z, S, T, H, X, CNOT
 
+from test_optimization.utils import check_matrix_equivalence
+
 single_qubit_decomps = [
     # First set of gates are diagonal and converted to RZ
     (I, qml.RZ, [0.0]),
@@ -439,6 +441,28 @@ test_two_qubit_unitaries = [
 ]
 
 
+@pytest.mark.parametrize("num_reps", [1, 2, 3, 4, 5])
+def test_unitary_to_rot_multiple_two_qubit(num_reps):
+    """Test that numerous two-qubit unitaries can be decomposed sequentially."""
+
+    dev = qml.device("default.qubit", wires=2)
+
+    U = np.array(test_two_qubit_unitaries[1], dtype=np.complex128)
+
+    def my_circuit():
+        for rep in range(num_reps):
+            qml.QubitUnitary(U, wires=[0, 1])
+        return qml.expval(qml.PauliZ(0))
+
+    original_qnode = qml.QNode(my_circuit, dev)
+    transformed_qnode = qml.QNode(unitary_to_rot(my_circuit), dev)
+
+    original_matrix = qml.transforms.get_unitary_matrix(original_qnode)()
+    transformed_matrix = qml.transforms.get_unitary_matrix(transformed_qnode)()
+
+    assert check_matrix_equivalence(original_matrix, transformed_matrix, atol=1e-7)
+
+
 class TestTwoQubitUnitaryDifferentiability:
     """Tests to ensure the transform is fully differentiable in all interfaces
     when the circuit contains two-qubit QubitUnitary operations.