Repository: PennyLaneAI/pennylane
Pull request #1559 (2021-08-18 20:07:36)

Update tape's to_openqasm method
The `tape.to_openqasm()` method now has a `measure_all` argument that specifies whether the serialized OpenQASM script includes computational basis measurements on all of the qubits or just those specified by the tape.

```python
import pennylane as qml
from scipy.stats import ortho_group

with qml.tape.QuantumTape() as tape:
    qml.RX(0.2, wires=0)
    qml.RY(0.6, wires=1)
    qml.CNOT(wires=[0, 1])
    qml.expval(qml.PauliZ(0))
```
With `measure_all=True` (current, and default in this PR):
```pycon
>>> print(tape.to_openqasm(measure_all=True))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
rx(0.2) q[0];
ry(0.6) q[1];
cx q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
```
New option:
```pycon
>>> print(tape.to_openqasm(measure_all=False))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
rx(0.2) q[0];
ry(0.6) q[1];
cx q[0],q[1];
measure q[0] -> c[0];
```

This addressed the comment [here](https://github.com/PennyLaneAI/pennylane/issues/1500#issuecomment-893763852).

codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1559?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#1559](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1559?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (ec62df4) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/742f2ff067d969a42e380968f36456c995dee2c9?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (742f2ff) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

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

```diff
@@           Coverage Diff           @@
##           master    #1559   +/-   ##
=======================================
  Coverage   99.14%   99.14%           
=======================================
  Files         188      188           
  Lines       13402    13407    +5     
=======================================
+ Hits        13288    13293    +5     
  Misses        114      114           
```


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

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1559?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/1559?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Last update [742f2ff...ec62df4](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1559?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 87ddf5019..71b3c48b1 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -84,6 +84,11 @@
 
 <h3>Improvements</h3>
 
+* The `tape.to_openqasm()` method now has a `measure_all` argument that specifies whether the
+  serialized OpenQASM script includes computational basis measurements on all of the qubits or
+  just those specified by the tape.
+  [(#1559)](https://github.com/PennyLaneAI/pennylane/pull/1559)
+
 * An error is raised when no arguments are passed to a `qml.operation.Observable` to inform the user about specifying wires.
   [(#1547)](https://github.com/PennyLaneAI/pennylane/pull/1547)
 
@@ -145,7 +150,7 @@ and requirements-ci.txt (unpinned). This latter would be used by the CI.
 
 This release contains contributions from (in alphabetical order):
 
-Josh Izaac, Prateek Jain, Johannes Jakob Meyer, Maria Schuld, Ingrid Strandberg.
+Thomas Bromley, Josh Izaac, Prateek Jain, Johannes Jakob Meyer, Maria Schuld, Ingrid Strandberg.
 
 # Release 0.17.0 (current release)
 
diff --git a/pennylane/tape/tape.py b/pennylane/tape/tape.py
index 48841218b..6004c117d 100644
--- a/pennylane/tape/tape.py
+++ b/pennylane/tape/tape.py
@@ -1098,11 +1098,13 @@ class QuantumTape(AnnotatedQueue):
             show_all_wires=show_all_wires,
         )
 
-    def to_openqasm(self, wires=None, rotations=True):
+    def to_openqasm(self, wires=None, rotations=True, measure_all=True):
         """Serialize the circuit as an OpenQASM 2.0 program.
 
-        Only operations are serialized; all measurements
-        are assumed to take place in the computational basis.
+        Measurements are assumed to be performed on all qubits in the computational basis. An
+        optional ``rotations`` argument can be provided so that output of the OpenQASM circuit is
+        diagonal in the eigenbasis of the tape's observables. The measurement outputs can be
+        restricted to only those specified in the tape by setting ``measure_all=False``.
 
         .. note::
 
@@ -1114,6 +1116,8 @@ class QuantumTape(AnnotatedQueue):
             rotations (bool): in addition to serializing user-specified
                 operations, also include the gates that diagonalize the
                 measured wires such that they are in the eigenbasis of the circuit observables.
+            measure_all (bool): whether to perform a computational basis measurement on all qubits
+                or just those specified in the tape
 
         Returns:
             str: OpenQASM serialization of the circuit
@@ -1174,9 +1178,16 @@ class QuantumTape(AnnotatedQueue):
         # NOTE: This is not strictly necessary, we could inspect self.observables,
         # and then only measure wires which are requested by the user. However,
         # some devices which consume QASM require all registers be measured, so
-        # measure all wires to be safe.
-        for wire in range(len(wires)):
-            qasm_str += "measure q[{wire}] -> c[{wire}];\n".format(wire=wire)
+        # measure all wires by default to be safe.
+        if measure_all:
+            for wire in range(len(wires)):
+                qasm_str += f"measure q[{wire}] -> c[{wire}];\n"
+        else:
+            measured_wires = qml.wires.Wires.all_wires([m.wires for m in self.measurements])
+
+            for w in measured_wires:
+                wire_indx = self.wires.index(w)
+                qasm_str += f"measure q[{wire_indx}] -> c[{wire_indx}];\n"
 
         return qasm_str
 


Test patch:
diff --git a/tests/circuit_graph/test_qasm.py b/tests/circuit_graph/test_qasm.py
index 03f9a34d5..b73505ad5 100644
--- a/tests/circuit_graph/test_qasm.py
+++ b/tests/circuit_graph/test_qasm.py
@@ -274,6 +274,42 @@ class TestToQasmUnitTests:
 
         assert res == qasm2
 
+    def test_only_tape_measurements(self):
+        """Test that no computational basis measurements are added other
+        than those already in the tape when ``measure_all=False``."""
+        with qml.tape.QuantumTape() as circuit:
+            qml.RX(0.43, wires="a")
+            qml.RY(0.35, wires="b")
+            qml.RZ(0.35, wires=2)
+            qml.CNOT(wires=["a", "b"])
+            qml.Hadamard(wires=2)
+            qml.CNOT(wires=[2, "a"])
+            qml.PauliX(wires="b")
+            qml.expval(qml.PauliZ("a"))
+            qml.expval(qml.PauliZ(2))
+
+        res = circuit.to_openqasm(measure_all=False)
+
+        expected = dedent(
+            """\
+            OPENQASM 2.0;
+            include "qelib1.inc";
+            qreg q[3];
+            creg c[3];
+            rx(0.43) q[0];
+            ry(0.35) q[1];
+            rz(0.35) q[2];
+            cx q[0],q[1];
+            h q[2];
+            cx q[2],q[0];
+            x q[1];
+            measure q[0] -> c[0];
+            measure q[2] -> c[2];
+            """
+        )
+
+        assert res == expected
+
 
 class TestQNodeQasmIntegrationTests:
     """Test that the QASM serialization works correctly