Repository: PennyLaneAI/pennylane
Pull request #1434 (2021-06-25 14:44:27)

Fix return of single measurement in qfunc transform.
**Context:** After applying a quantum function transform and constructing a QNode, the resultant QNode would return a 1-d array of measurement results even when there was only a single measurement.

**Description of the Change:** The qfunc transform decorator now checks the length of the list of measurements, and returns a list of results only when there are multiple measurements.

**Benefits:** Transformed QNodes that return a 0-d tensor now still return a 0-d tensor.

**Possible Drawbacks:** None

**Related GitHub Issues:** None


github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [.github/CHANGELOG.md](/PennyLaneAI/pennylane/blob/master/.github/CHANGELOG.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/1434?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#1434](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1434?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (dccdba7) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/a6a82ee0cb636533f36ed058065bc71e63a76206?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (a6a82ee) will **decrease** coverage by `0.00%`.
> The diff coverage is `50.00%`.

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

```diff
@@            Coverage Diff             @@
##           master    #1434      +/-   ##
==========================================
- Coverage   98.23%   98.22%   -0.01%     
==========================================
  Files         160      160              
  Lines       11964    11966       +2     
==========================================
+ Hits        11753    11754       +1     
- Misses        211      212       +1     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1434?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/transforms/qfunc\_transforms.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1434/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3RyYW5zZm9ybXMvcWZ1bmNfdHJhbnNmb3Jtcy5weQ==) | `98.38% <50.00%> (-1.62%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1434?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/1434?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Last update [a6a82ee...dccdba7](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1434?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 30b4da827..8bbec02dd 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -11,13 +11,17 @@
 
 <h3>Bug fixes</h3>
 
+* Quantum function transforms now preserve the format of the measurement
+  results, so that a single measurement returns a single value rather than
+  an array with a single element. [(#1434)](https://github.com/PennyLaneAI/pennylane/pull/1434/files)
+
 <h3>Documentation</h3>
 
 <h3>Contributors</h3>
 
 This release contains contributions from (in alphabetical order):
 
-Ashish Panigrahi
+Olivia Di Matteo, Ashish Panigrahi
 
 
 # Release 0.16.0 (current release)
diff --git a/pennylane/transforms/qfunc_transforms.py b/pennylane/transforms/qfunc_transforms.py
index 9581bae67..13263af30 100644
--- a/pennylane/transforms/qfunc_transforms.py
+++ b/pennylane/transforms/qfunc_transforms.py
@@ -182,6 +182,10 @@ def _create_qfunc_internal_wrapper(fn, tape_transform, transform_args, transform
     def internal_wrapper(*args, **kwargs):
         tape = make_tape(fn)(*args, **kwargs)
         tape = tape_transform(tape, *transform_args, **transform_kwargs)
+
+        if len(tape.measurements) == 1:
+            return tape.measurements[0]
+
         return tape.measurements
 
     return internal_wrapper


Test patch:
diff --git a/tests/transforms/test_qfunc_transform.py b/tests/transforms/test_qfunc_transform.py
index f7d157de5..066a24f38 100644
--- a/tests/transforms/test_qfunc_transform.py
+++ b/tests/transforms/test_qfunc_transform.py
@@ -271,6 +271,37 @@ class TestQFuncTransforms:
         assert ops[0].parameters == [x]
         assert ops[1].name == "CZ"
 
+    def test_transform_single_measurement(self):
+        """Test that transformed functions return a scalar value when there is only
+        a single measurement."""
+
+        @qml.qfunc_transform
+        def expand_hadamards(tape):
+            for op in tape.operations + tape.measurements:
+                if op.name == "Hadamard":
+                    qml.RZ(np.pi, wires=op.wires)
+                    qml.RY(np.pi / 2, wires=op.wires)
+                else:
+                    op.queue()
+
+        def ansatz():
+            qml.Hadamard(wires=0)
+            qml.CNOT(wires=[0, 1])
+            return qml.expval(qml.PauliX(wires=1))
+
+        dev = qml.device("default.qubit", wires=2)
+
+        normal_qnode = qml.QNode(ansatz, dev)
+
+        transformed_ansatz = expand_hadamards(ansatz)
+        transformed_qnode = qml.QNode(transformed_ansatz, dev)
+
+        normal_result = normal_qnode()
+        transformed_result = transformed_qnode()
+
+        assert np.allclose(normal_result, transformed_result)
+        assert normal_result.shape == transformed_result.shape
+
 
 ############################################
 # Test transform, ansatz, and qfunc function