From f4537a9bf3e8e6dd81e92cd2d3f5eec43fbe4195 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 10 Jul 2023 15:04:46 -0400 Subject: [PATCH] Deprecations for 0.32 from me! (#4316) * deprecate the old return system * deprecate the mode kwarg for QNode * changelog * PR feedback * update notice to avoid wrongly suggesting action needed * update docstrings, docs and warnings * add link to qnode returns doc * change the mode warning depending on return system active * also add disclaimer to docstring --- doc/development/deprecations.rst | 12 ++++++++++ doc/introduction/interfaces/jax.rst | 2 -- doc/releases/changelog-dev.md | 9 ++++++++ pennylane/devices/experimental/device_api.py | 2 +- pennylane/gradients/hadamard_gradient.py | 2 -- pennylane/gradients/jvp.py | 3 --- pennylane/gradients/parameter_shift.py | 8 +++---- pennylane/qnode.py | 22 +++++++++++++++--- pennylane/return_types.py | 18 +++++++++++++++ pennylane/tape/qscript.py | 2 -- tests/test_qnode.py | 21 +++++++++++++++++ tests/test_return_types.py | 24 ++++++++++++++++++++ 12 files changed, 107 insertions(+), 18 deletions(-) diff --git a/doc/development/deprecations.rst b/doc/development/deprecations.rst index c7870a13559..3763b42bec8 100644 --- a/doc/development/deprecations.rst +++ b/doc/development/deprecations.rst @@ -6,6 +6,18 @@ Deprecations Pending deprecations -------------------- +* ``qml.enable_return`` and ``qml.disable_return`` are deprecated. Please avoid calling + ``disable_return``, as the old return system is deprecated along with these switch functions. + + - Deprecated in v0.32 + - Will be removed in v0.33 + +* The ``mode`` keyword argument in ``QNode`` is deprecated, as it was only used in the old return + system (which is also deprecated). Please use ``grad_on_execution`` instead. + + - Deprecated in v0.32 + - Will be removed in v0.33 + * The ``observables`` argument in ``QubitDevice.statistics`` is deprecated. Please use ``circuit`` instead. Using a list of observables in ``QubitDevice.statistics`` is deprecated. Please use a ``QuantumTape`` instead. diff --git a/doc/introduction/interfaces/jax.rst b/doc/introduction/interfaces/jax.rst index aa03117a0c3..e7084383845 100644 --- a/doc/introduction/interfaces/jax.rst +++ b/doc/introduction/interfaces/jax.rst @@ -21,8 +21,6 @@ PennyLane in combination with JAX, we have to generate JAX-compatible quantum no types in QNodes; * Multiple probability measurements need to have the same number of wires specified; - * Computing the jacobian of vector-valued QNodes is not supported - in ``mode="forward"``. However, when using ``diff_method="backprop"``, all QNode measurement statistics are supported. diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index db0f90fce25..24c3bdb1032 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -55,6 +55,15 @@ * The CV observables ``qml.X`` and ``qml.P`` have been deprecated. Use ``qml.QuadX`` and ``qml.QuadP`` instead. + [(#4330)](https://github.com/PennyLaneAI/pennylane/pull/4330) + +* `qml.enable_return` and `qml.disable_return` are deprecated. Please avoid calling + `disable_return`, as the old return system is deprecated along with these switch functions. + [(#4316)](https://github.com/PennyLaneAI/pennylane/pull/4316) + +* The `mode` keyword argument in `QNode` is deprecated, as it was only used in the + old return system (which is also deprecated). Please use `grad_on_execution` instead. + [(#4316)](https://github.com/PennyLaneAI/pennylane/pull/4316)

Documentation 📝

diff --git a/pennylane/devices/experimental/device_api.py b/pennylane/devices/experimental/device_api.py index 4676eea248f..cbcfbcbe882 100644 --- a/pennylane/devices/experimental/device_api.py +++ b/pennylane/devices/experimental/device_api.py @@ -42,7 +42,7 @@ class Device(abc.ABC): This interface is **experimental** and not yet integrated with the rest of PennyLane. Device drivers should be configured to run under :func:`~.enable_return`, the newer - return shape specification. + return shape specification, as the old return shape specification is deprecated. Only the ``execute`` method must be defined to construct a device driver. diff --git a/pennylane/gradients/hadamard_gradient.py b/pennylane/gradients/hadamard_gradient.py index fb59c3c9c42..bad143fbfc1 100644 --- a/pennylane/gradients/hadamard_gradient.py +++ b/pennylane/gradients/hadamard_gradient.py @@ -92,7 +92,6 @@ def _hadamard_grad( This gradient transform can be applied directly to :class:`QNode ` objects: - >>> qml.enable_return() >>> dev = qml.device("default.qubit", wires=2) >>> @qml.qnode(dev) ... def circuit(params): @@ -146,7 +145,6 @@ def _hadamard_grad( If you use custom wires on your device, you need to pass an auxiliary wire. - >>> qml.enable_return() >>> dev_wires = ("a", "c") >>> dev = qml.device("default.qubit", wires=dev_wires) >>> @qml.qnode(dev, interface="jax", diff_method="hadamard", aux_wire="c", device_wires=dev_wires) diff --git a/pennylane/gradients/jvp.py b/pennylane/gradients/jvp.py index e15ea5584a4..35811b40ef2 100644 --- a/pennylane/gradients/jvp.py +++ b/pennylane/gradients/jvp.py @@ -263,8 +263,6 @@ def jvp(tape, tangent, gradient_fn, shots=None, gradient_kwargs=None): import jax - qml.enable_return() - x = jax.numpy.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]) @@ -368,7 +366,6 @@ def batch_jvp(tapes, tangents, gradient_fn, shots=None, reduction="append", grad .. code-block:: python import jax - qml.enable_return() x = jax.numpy.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]) diff --git a/pennylane/gradients/parameter_shift.py b/pennylane/gradients/parameter_shift.py index 05eee293ec3..17cfa09166f 100644 --- a/pennylane/gradients/parameter_shift.py +++ b/pennylane/gradients/parameter_shift.py @@ -1487,11 +1487,9 @@ def proc_with_validation(results): res = fn(results) except (ValueError, TypeError) as e: raise e.__class__( - "The processing function of the gradient transform ran into errors " - "while the new return type system was turned on. Make sure to " - "pass the device shots to the param_shift gradient transform " - "using the shots argument or disable the new return type " - "system by calling the qml.disable_return function." + "The processing function of the gradient transform ran into errors. " + "Make sure to pass the device shots to the param_shift gradient transform " + "using the shots argument." ) from e return res diff --git a/pennylane/qnode.py b/pennylane/qnode.py index a9623a7005c..d5bc695ae56 100644 --- a/pennylane/qnode.py +++ b/pennylane/qnode.py @@ -151,11 +151,12 @@ class QNode: Only applies if the device is queried for the gradient; gradient transform functions available in ``qml.gradients`` are only supported on the backward pass. The 'best' option chooses automatically between the two options and is default. - mode (str): Whether the gradients should be computed on the forward + mode (str): Deprecated kwarg indicating whether the gradients should be computed on the forward pass (``forward``) or the backward pass (``backward``). Only applies if the device is queried for the gradient; gradient transform functions available in ``qml.gradients`` are only supported on the backward - pass. + pass. This argument does nothing with the new return system, and users should + instead set ``grad_on_execution`` to indicate their desired behaviour. cache (bool or dict or Cache): Whether to cache evaluations. This can result in a significant reduction in quantum evaluations during gradient computations. If ``True``, a cache with corresponding ``cachesize`` is created for each batch @@ -386,7 +387,7 @@ def __init__( expansion_strategy="gradient", max_expansion=10, grad_on_execution="best", - mode="best", + mode=None, cache=True, cachesize=10000, max_diff=1, @@ -427,6 +428,21 @@ def __init__( f"gradient kwargs." ) + if mode is None: + mode = "best" + elif qml.active_return(): + warnings.warn( + "The `mode` keyword argument is deprecated and does nothing with the new return system. " + "Please use `grad_on_execution` instead.", + UserWarning, + ) + else: + warnings.warn( + "The `mode` keyword argument is deprecated, along with the old return system. In " + "the new return system, you should set the `grad_on_execution` boolean instead.", + UserWarning, + ) + # input arguments self.func = func self.device = device diff --git a/pennylane/return_types.py b/pennylane/return_types.py index 9a6d5f79a7d..0998a5e0695 100644 --- a/pennylane/return_types.py +++ b/pennylane/return_types.py @@ -15,6 +15,8 @@ Class and functions for activating, deactivating and checking the new return types system """ # pylint: disable=global-statement +import warnings + __activated = True @@ -615,6 +617,13 @@ def circuit_stack(a, b): (tensor([ 0.0000, 0.0050, -0.0050, 0.0050, -0.0050]), tensor([ 0.0000, -0.4888, 0.4888, 0.0012, -0.0012]))) """ + warnings.warn( + "The old return system is deprecated, and will be removed along with " + "`qml.enable_return()` in v0.33. Please consult the QNode returns page for guidance on " + "switching to the new return system: https://docs.pennylane.ai/en/stable/introduction/returns.html", + UserWarning, + ) + global __activated __activated = True @@ -646,6 +655,14 @@ def circuit(x): tensor([0.5 , 0.5 , 0.08014815, 0.96939564, 0.03060436, 0.93879128], requires_grad=True) """ + + warnings.warn( + "The old return system is deprecated, and will be removed along with " + "`qml.disable_return()` in v0.33. Please consult the QNode returns page for guidance on " + "switching to the new return system: https://docs.pennylane.ai/en/stable/introduction/returns.html", + UserWarning, + ) + global __activated __activated = False # pragma: no cover @@ -678,4 +695,5 @@ def active_return(): >>> active_return() False """ + return __activated diff --git a/pennylane/tape/qscript.py b/pennylane/tape/qscript.py index 6c943f51411..5bdea78390c 100644 --- a/pennylane/tape/qscript.py +++ b/pennylane/tape/qscript.py @@ -921,7 +921,6 @@ def shape(self, device): .. code-block:: pycon - >>> qml.enable_return() >>> dev = qml.device('default.qubit', wires=2) >>> qs = QuantumScript(measurements=[qml.state()]) >>> qs.shape(dev) @@ -1004,7 +1003,6 @@ def numeric_type(self): .. code-block:: pycon - >>> qml.enable_return() >>> dev = qml.device('default.qubit', wires=2) >>> qs = QuantumScript(measurements=[qml.state()]) >>> qs.numeric_type diff --git a/tests/test_qnode.py b/tests/test_qnode.py index 66b6c6250f4..9ab072e246b 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -636,6 +636,27 @@ def circuit(params): assert len(record) == 0 + def test_not_giving_mode_kwarg_does_not_raise_warning(self): + """Test that not providing a value for mode does not raise a warning.""" + with warnings.catch_warnings(record=True) as record: + _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1)) + + assert len(record) == 0 + + def test_giving_mode_kwarg_raises_warning(self): + """Test that providing a value for mode raises a warning.""" + with pytest.warns(UserWarning, match="The `mode` keyword argument is deprecated"): + _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1), mode="best") + + def test_giving_mode_kwarg_raises_warning_old_return(self): + """Test that providing a value for mode raises a custom warning with disable_return.""" + qml.disable_return() + with pytest.warns( + UserWarning, match="In the new return system, you should set the `grad_on_execution`" + ): + _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1), mode="best") + qml.enable_return() + class TestTapeConstruction: """Tests for the tape construction""" diff --git a/tests/test_return_types.py b/tests/test_return_types.py index 733ff8e6119..14897361519 100644 --- a/tests/test_return_types.py +++ b/tests/test_return_types.py @@ -14,6 +14,8 @@ """ Unit tests for the new return types. """ +import warnings + import numpy as np import pytest @@ -1274,3 +1276,25 @@ def test_custom_wire_labels_error(self): msg = "Returning the mutual information is not supported when using custom wire labels" with pytest.raises(qml.QuantumFunctionError, match=msg): qml.execute(tapes=[tape], device=dev, gradient_fn=None) + + +class TestDeprecationWarnings: + """Tests that all return-system functions raise deprecation warnings.""" + + def test_enable_return_raises_warning(self): + """Test that enable_return() raises a warning.""" + with pytest.warns(UserWarning, match="The old return system is deprecated"): + qml.enable_return() + + def test_disable_return_raises_warning(self): + """Test that disable_return() raises a warning.""" + with pytest.warns(UserWarning, match="The old return system is deprecated"): + qml.disable_return() + qml.enable_return() + + def test_active_return_does_not_raise_warning(self): + """Test that active_return() does not raise a warning.""" + with warnings.catch_warnings(record=True) as record: + qml.active_return() + + assert len(record) == 0