Skip to content

Commit

Permalink
Add deprecation warning to from_qasm (#5882)
Browse files Browse the repository at this point in the history
**Context:**
Previously, the QASM circuit converted to PL had no measurements (even
if the circuit ended with measurements, the assumption was we remove
those and add PL measurements once the circuit is converted).

In the UnitaryHack, a contributor added the option to specify
measurements when converting a circuit `from_qasm`, like the
`from_qiskit` function. In doing so, the `from_qasm` circuit took on the
current `from_qiskit` convention. Calling `from_qasm(qasm_str)`
previously returned only the operators, and now returns operators +
measurements. This is a breaking change with no deprecation cycle.

PennyLaneAI/pennylane-qiskit#469

**Description of the Change:**
Adds a deprecation warning to `from_qasm`

[sc-66318]

---------

Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>
Co-authored-by: Christina Lee <christina@xanadu.ai>
Co-authored-by: David Wierichs <david.wierichs@xanadu.ai>
  • Loading branch information
4 people committed Jun 20, 2024
1 parent 70ee43c commit 50e009a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 5 deletions.
8 changes: 8 additions & 0 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
3 changes: 3 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<h3>Documentation 📝</h3>

* Move information about mid-circuit measurements from the measurements quickstart page to its own
Expand Down
30 changes: 26 additions & 4 deletions pennylane/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -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. "
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)


Expand Down
28 changes: 27 additions & 1 deletion tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -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(
Expand Down

0 comments on commit 50e009a

Please sign in to comment.