Repository: PennyLaneAI/pennylane
Pull request #4983 (2024-01-03 18:08:55)

Stop queuing when applying transform on a qfunc
[sc-52886]

Found in discussions with @KetpuntoG . 

```
from functools import partial

@qml.qnode(qml.device('default.qubit'))
@partial(qml.devices.preprocess.decompose, stopping_condition = lambda obj: False, max_expansion=1)
def f():
    qml.IsingXX(1.2, wires=(0,1))
    return qml.state()

print(qml.draw(f)())
```
```
0: ─╭●──RX(1.20)─╭●─╭●──RX(1.20)─╭●─┤  State
1: ─╰X───────────╰X─╰X───────────╰X─┤  State
```

As you can see, when `decompose` is used as a qfunc transform, it ends up queuing everything twice.

This PR also updates the documentation for `transform` to clarify that no operators should be queued by the transform.

The other alternative is to add a `stop_recording` block in `TransformDispatcher._qfunc_transform`.

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://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4983?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> :exclamation: No coverage uploaded for pull request base (`v0.34.0-rc0@3c887a3`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#section-missing-base-commit).


<details><summary>Additional details and impacted files</summary>


```diff
@@              Coverage Diff               @@
##             v0.34.0-rc0    #4983   +/-   ##
==============================================
  Coverage               ?   99.67%           
==============================================
  Files                  ?      392           
  Lines                  ?    35291           
  Branches               ?        0           
==============================================
  Hits                   ?    35176           
  Misses                 ?      115           
  Partials               ?        0           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/4983?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).


Patch:
diff --git a/doc/releases/changelog-0.34.0.md b/doc/releases/changelog-0.34.0.md
index 43f1c813f..1803f1489 100644
--- a/doc/releases/changelog-0.34.0.md
+++ b/doc/releases/changelog-0.34.0.md
@@ -603,6 +603,10 @@
 
 <h3>Bug fixes 🐛</h3>
 
+* `TransformDispatcher` now stops queuing when performing the transform when applying it to a qfunc.
+  Only the output of the transform will be queued.
+  [(#4983)](https://github.com/PennyLaneAI/pennylane/pull/4983)
+
 * `qml.map_wires` now works properly with `qml.cond` and `qml.measure`.
   [(#4884)](https://github.com/PennyLaneAI/pennylane/pull/4884)
 
diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py
index 4cdf73bfa..c4640873e 100644
--- a/pennylane/devices/default_qubit.py
+++ b/pennylane/devices/default_qubit.py
@@ -138,9 +138,8 @@ def adjoint_state_measurements(tape: QuantumTape) -> (Tuple[QuantumTape], Callab
     params = tape.get_parameters()
     complex_data = [qml.math.cast(p, complex) for p in params]
     tape = tape.bind_new_parameters(complex_data, list(range(len(params))))
-    state_tape = qml.tape.QuantumScript(
-        tape.operations, [qml.measurements.StateMP(wires=tape.wires)]
-    )
+    new_mp = qml.measurements.StateMP(wires=tape.wires)
+    state_tape = qml.tape.QuantumScript(tape.operations, [new_mp])
     return (state_tape,), partial(
         all_state_postprocessing, measurements=tape.measurements, wire_order=tape.wires
     )
diff --git a/pennylane/transforms/core/transform_dispatcher.py b/pennylane/transforms/core/transform_dispatcher.py
index dba4f9578..3eea403e8 100644
--- a/pennylane/transforms/core/transform_dispatcher.py
+++ b/pennylane/transforms/core/transform_dispatcher.py
@@ -238,7 +238,8 @@ class TransformDispatcher:
                 qfunc_output = qfunc(*args, **kwargs)
 
             tape = qml.tape.QuantumScript.from_queue(q)
-            transformed_tapes, processing_fn = self._transform(tape, *targs, **tkwargs)
+            with qml.QueuingManager.stop_recording():
+                transformed_tapes, processing_fn = self._transform(tape, *targs, **tkwargs)
 
             if len(transformed_tapes) != 1:
                 raise TransformError(


Test patch:
diff --git a/tests/devices/test_preprocess.py b/tests/devices/test_preprocess.py
index 006db9f4a..4fd018a0e 100644
--- a/tests/devices/test_preprocess.py
+++ b/tests/devices/test_preprocess.py
@@ -298,12 +298,12 @@ class TestValidateMeasurements:
             validate_measurements(tape, lambda obj: True)
 
 
-class TestExpandFnTransformations:
-    """Tests for the behavior of the `expand_fn` helper."""
+class TestDecomposeTransformations:
+    """Tests for the behavior of the `decompose` helper."""
 
     @pytest.mark.parametrize("shots", [None, 100])
     def test_decompose_expand_unsupported_op(self, shots):
-        """Test that expand_fn expands the tape when unsupported operators are present"""
+        """Test that decompose expands the tape when unsupported operators are present"""
         ops = [qml.Hadamard(0), NoMatOp(1), qml.RZ(0.123, wires=1)]
         measurements = [qml.expval(qml.PauliZ(0)), qml.probs()]
         tape = QuantumScript(ops=ops, measurements=measurements, shots=shots)
diff --git a/tests/transforms/test_experimental/test_transform_dispatcher.py b/tests/transforms/test_experimental/test_transform_dispatcher.py
index ac5fa93b3..8e77553e0 100644
--- a/tests/transforms/test_experimental/test_transform_dispatcher.py
+++ b/tests/transforms/test_experimental/test_transform_dispatcher.py
@@ -100,6 +100,7 @@ def first_valid_transform(
     """A valid transform."""
     tape = tape.copy()
     tape._ops.pop(index)  # pylint:disable=protected-access
+    _ = (qml.PauliX(0), qml.S(0))
     return [tape], lambda x: x