diff --git a/doc/development/deprecations.rst b/doc/development/deprecations.rst
index 34c6e03b9b1..23f2c0749e9 100644
--- a/doc/development/deprecations.rst
+++ b/doc/development/deprecations.rst
@@ -21,6 +21,14 @@ Pending deprecations
- Deprecated in v0.37
- Will be removed in v0.38
+* ``qml.from_qasm`` will no longer remove measurements from the QASM code. Calling ``qml.from_qasm``
+ without specifying ``measurements`` will raise a deprecation warning in v0.37, and in v0.38,
+ the default behaviour will be changed to keeping measurements. Use ``measurements=[]`` to remove
+ measurements from the original circuit.
+
+ - Deprecated in v0.37
+ - Default behaviour will be changed in v0.38
+
New operator arithmetic deprecations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 80597b8fcb0..a6b39d4c984 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -405,6 +405,9 @@
* `qml.transforms.map_batch_transform` is deprecated, since a transform can be applied directly to a batch of tapes.
[(#5676)](https://github.com/PennyLaneAI/pennylane/pull/5676)
+* The default behaviour of `qml.from_qasm()` to remove measurements in the QASM code is deprecated. Use `measurements=[]` to keep this behaviour or `measurements=None` to keep the measurements from the QASM code.
+ [(#5882)](https://github.com/PennyLaneAI/pennylane/pull/5882)
+
Documentation 📝
* Move information about mid-circuit measurements from the measurements quickstart page to its own
diff --git a/pennylane/io.py b/pennylane/io.py
index 3fcb4c36dce..44465521250 100644
--- a/pennylane/io.py
+++ b/pennylane/io.py
@@ -15,10 +15,13 @@
This module contains functions to load circuits from other frameworks as
PennyLane templates.
"""
+import warnings
from collections import defaultdict
from importlib import metadata
from sys import version_info
+import pennylane as qml
+
# Error message to show when the PennyLane-Qiskit plugin is required but missing.
_MISSING_QISKIT_PLUGIN_MESSAGE = (
"Conversion from Qiskit requires the PennyLane-Qiskit plugin. "
@@ -407,7 +410,7 @@ def from_qiskit_op(qiskit_op, params=None, wires=None):
raise RuntimeError(_MISSING_QISKIT_PLUGIN_MESSAGE) from e
-def from_qasm(quantum_circuit: str, measurements=None):
+def from_qasm(quantum_circuit: str, measurements=False):
"""Loads quantum circuits from a QASM string using the converter in the
PennyLane-Qiskit plugin.
@@ -436,8 +439,16 @@ def from_qasm(quantum_circuit: str, measurements=None):
that will **override** any terminal measurements present in the QASM code,
so that they are not performed before the operations specified in ``measurements``.
- If the existing QASM code already contains measurements, ``from_qasm``
- will return those measurements, provided that they are not overriden as shown above.
+ By default, ``from_qasm`` will remove any measurements that are present in the QASM code.
+ If the QASM code contains measurements, set ``measurements=None`` to keep them in the
+ output of ``from_qasm``.
+
+ .. warning::
+
+ The current default behaviour of removing measurements in the QASM code is deprecated
+ and will be changed in a future release. Starting in version ``0.38``, ``from_qasm``
+ will keep the measurements from the QASM code by default. To remove all measurements,
+ set ``measurements=[]`` which overrides the existing measurements with an empty list.
Mid-circuit measurements inside the QASM code can also be interpreted.
@@ -485,12 +496,23 @@ def circuit():
quantum_circuit (str): a QASM string containing a valid quantum circuit
measurements (None | MeasurementProcess | list[MeasurementProcess]): an optional PennyLane
measurement or list of PennyLane measurements that overrides any terminal measurements
- that may be present in the input circuit
+ that may be present in the input circuit. If set to ``None``, existing measurements
+ in the input circuit will be used.
Returns:
function: the PennyLane template created based on the QASM string
+
"""
plugin_converter = plugin_converters["qasm"].load()
+ if measurements is False:
+ warnings.warn(
+ "The current default behaviour of removing measurements in the QASM code is "
+ "deprecated. Set measurements=None to keep the existing measurements in the QASM "
+ "code or set measurements=[] to remove them from the returned circuit. Starting "
+ "in version 0.38, measurements=None will be the new default.",
+ qml.PennyLaneDeprecationWarning,
+ )
+ measurements = []
return plugin_converter(quantum_circuit, measurements=measurements)
diff --git a/tests/test_io.py b/tests/test_io.py
index 489a5509fa9..d59b22ba892 100644
--- a/tests/test_io.py
+++ b/tests/test_io.py
@@ -114,7 +114,6 @@ def test_qiskit_converter_load_fails(self, monkeypatch, method, entry_point_name
[
(qml.from_qiskit, "qiskit"),
(qml.from_qiskit_op, "qiskit_op"),
- (qml.from_qasm, "qasm"),
(qml.from_pyquil, "pyquil_program"),
(qml.from_quil, "quil"),
(qml.from_quil_file, "quil_file"),
@@ -135,11 +134,38 @@ def test_convenience_functions(self, method, entry_point_name, mock_plugin_conve
if mock_plugin_converters[plugin_converter].called:
raise RuntimeError(f"The other plugin converter {plugin_converter} was called.")
+ def test_from_qasm(self, mock_plugin_converters):
+ """Tests that the correct entry point is called for from_qasm."""
+
+ qml.from_qasm("Test", measurements=None)
+ assert mock_plugin_converters["qasm"].called
+ assert mock_plugin_converters["qasm"].last_args == ("Test",)
+
+ for plugin_converter in mock_plugin_converters:
+ if mock_plugin_converters[plugin_converter].called and plugin_converter != "qasm":
+ raise RuntimeError(f"The other plugin converter {plugin_converter} was called.")
+
+ def test_from_qasm_deprecated(self, mock_plugin_converters):
+ """Tests that the current default behaviour of from_qasm is deprecated."""
+
+ with pytest.warns(qml.PennyLaneDeprecationWarning, match="The current default behaviour"):
+ qml.from_qasm("Test")
+
+ called_args, called_kwargs = mock_plugin_converters["qasm"].call_args
+ assert called_args == ("Test",)
+ assert called_kwargs == {"measurements": []}
+
@pytest.mark.parametrize(
"method, entry_point_name, args, kwargs",
[
(qml.from_qiskit, "qiskit", ("Circuit",), {"measurements": []}),
(qml.from_qiskit_op, "qiskit_op", ("Op",), {"params": [1, 2], "wires": [3, 4]}),
+ (
+ qml.from_qasm,
+ "qasm",
+ ("Circuit",),
+ {"measurements": []},
+ ),
],
)
def test_convenience_function_arguments(