Repository: PennyLaneAI/pennylane
Pull request #6822 (2025-01-14 18:13:50)

Deprecate `inner_transform_program` and `config` arguments to `qml.execute`
**Context:**

If users want this level of detail for execution they can use `qml.workflow.run`. This is done so we can have better signature parity with `QNode`.

Also, shuffled around the kwargs of `qml.execute` to match `QNode` better. Also added better typing.

[sc-81529]

github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.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://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6822?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.60%. Comparing base [(`807bc4c`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/807bc4c4d1df248951550fe7b7264c9fa83c2668?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) to head [(`b9beeff`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/b9beeff99fb1418ced0f61c02b67f36370a4353b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).
> Report is 2 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #6822   +/-   ##
=======================================
  Coverage   99.60%   99.60%           
=======================================
  Files         476      476           
  Lines       45237    45237           
=======================================
  Hits        45060    45060           
  Misses        177      177           
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/6822?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).


Patch:
diff --git a/doc/development/deprecations.rst b/doc/development/deprecations.rst
index f498fcf50..89c5f4d12 100644
--- a/doc/development/deprecations.rst
+++ b/doc/development/deprecations.rst
@@ -9,6 +9,12 @@ deprecations are listed below.
 Pending deprecations
 --------------------
 
+* The ``inner_transform_program`` and ``config`` keyword arguments in ``qml.execute`` have been deprecated.
+  If more detailed control over the execution is required, use ``qml.workflow.run`` with these arguments instead.
+
+  - Deprecated in v0.41
+  - Will be removed in v0.42
+
 * ``op.ops`` and ``op.coeffs`` for ``Sum`` and ``Prod`` will be removed in the future. Use
   :meth:`~.Operator.terms` instead.
 
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index b0acd30f9..e2b5cdb45 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -46,6 +46,9 @@
 
 <h3>Breaking changes 💔</h3>
 
+* `qml.execute` now has a collection of keyword-only arguments.
+  [(#6598)](https://github.com/PennyLaneAI/pennylane/pull/6598)
+
 * The ``decomp_depth`` argument in :func:`~pennylane.transforms.set_decomposition` has been removed. 
   [(#6824)](https://github.com/PennyLaneAI/pennylane/pull/6824)
 
@@ -71,6 +74,10 @@
 
 <h3>Deprecations 👋</h3>
 
+* The ``inner_transform_program`` and ``config`` keyword arguments in ``qml.execute`` have been deprecated.
+  If more detailed control over the execution is required, use ``qml.workflow.run`` with these arguments instead.
+  [(#6822)](https://github.com/PennyLaneAI/pennylane/pull/6822)
+
 <h3>Documentation 📝</h3>
 
 * Updated documentation for vibrational Hamiltonians
diff --git a/pennylane/workflow/execution.py b/pennylane/workflow/execution.py
index 5a3b1d57c..cfe93f322 100644
--- a/pennylane/workflow/execution.py
+++ b/pennylane/workflow/execution.py
@@ -18,16 +18,19 @@ differentiation support.
 
 import inspect
 import logging
-from collections.abc import Callable
 from dataclasses import replace
-from typing import Optional, Union
+from typing import Callable, Literal, Optional, Union
+from warnings import warn
 
 from cachetools import Cache
 
 import pennylane as qml
 from pennylane.math import Interface
+from pennylane.math.interface_utils import InterfaceLike
 from pennylane.tape import QuantumScriptBatch
+from pennylane.transforms.core import TransformDispatcher, TransformProgram
 from pennylane.typing import ResultBatch
+from pennylane.workflow.resolution import SupportedDiffMethods
 
 from ._setup_transform_program import _setup_transform_program
 from .resolution import _resolve_execution_config, _resolve_interface
@@ -41,19 +44,19 @@ logger.addHandler(logging.NullHandler())
 def execute(
     tapes: QuantumScriptBatch,
     device: Union["qml.devices.LegacyDevice", "qml.devices.Device"],
-    diff_method: Optional[Union[Callable, str, qml.transforms.core.TransformDispatcher]] = None,
-    interface: Optional[Union[str, Interface]] = Interface.AUTO,
+    diff_method: Optional[Union[Callable, SupportedDiffMethods, TransformDispatcher]] = None,
+    interface: Optional[InterfaceLike] = Interface.AUTO,
     *,
-    transform_program=None,
-    inner_transform=None,
-    config=None,
-    grad_on_execution="best",
-    gradient_kwargs=None,
+    grad_on_execution: Literal[bool, "best"] = "best",
     cache: Union[None, bool, dict, Cache] = True,
-    cachesize=10000,
-    max_diff=1,
-    device_vjp=False,
-    mcm_config=None,
+    cachesize: int = 10000,
+    max_diff: int = 1,
+    device_vjp: Union[bool, None] = False,
+    gradient_kwargs: dict = None,
+    transform_program: TransformProgram = None,
+    mcm_config: "qml.devices.MCMConfig" = None,
+    config="unset",
+    inner_transform="unset",
 ) -> ResultBatch:
     """A function for executing a batch of tapes on a device with compatibility for auto-differentiation.
 
@@ -69,17 +72,11 @@ def execute(
             This affects the types of parameters that can exist on the input tapes.
             Available options include ``autograd``, ``torch``, ``tf``, ``jax``, and ``auto``.
         transform_program(.TransformProgram): A transform program to be applied to the initial tape.
-        inner_transform (.TransformProgram): A transform program to be applied to the tapes in
-            inner execution, inside the ml interface.
-        config (qml.devices.ExecutionConfig): A data structure describing the parameters
-            needed to fully describe the execution.
         grad_on_execution (bool, str): Whether the gradients should be computed
             on the execution or not. It 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.
-        gradient_kwargs (dict): dictionary of keyword arguments to pass when
-            determining the gradients of tapes.
         cache (None, bool, dict, Cache): Whether to cache evaluations. This can result in
             a significant reduction in quantum evaluations during gradient computations.
         cachesize (int): the size of the cache.
@@ -91,6 +88,12 @@ def execute(
             product if it is available.
         mcm_config (dict): Dictionary containing configuration options for handling
             mid-circuit measurements.
+        gradient_kwargs (dict): dictionary of keyword arguments to pass when
+            determining the gradients of tapes.
+        config="unset": **DEPRECATED**. This keyword argument has been deprecated and
+            will be removed in v0.42.
+        inner_transform="unset": **DEPRECATED**. This keyword argument has been deprecated
+            and will be removed in v0.42.
 
     Returns:
         list[tensor_like[float]]: A nested list of tape results. Each element in
@@ -154,6 +157,22 @@ def execute(
     if not isinstance(device, qml.devices.Device):
         device = qml.devices.LegacyDeviceFacade(device)
 
+    if config != "unset":
+        warn(
+            "The config argument has been deprecated and will be removed in v0.42. "
+            "The provided config argument will be ignored. "
+            "If more detailed control over the execution is required, use ``qml.workflow.run`` with these arguments instead.",
+            qml.PennyLaneDeprecationWarning,
+        )
+
+    if inner_transform != "unset":
+        warn(
+            "The inner_transform argument has been deprecated and will be removed in v0.42. "
+            "The provided inner_transform argument will be ignored. "
+            "If more detailed control over the execution is required, use ``qml.workflow.run`` with these arguments instead.",
+            qml.PennyLaneDeprecationWarning,
+        )
+
     if logger.isEnabledFor(logging.DEBUG):
         logger.debug(
             (
@@ -185,21 +204,16 @@ def execute(
     interface = _resolve_interface(interface, tapes)
     # Only need to calculate derivatives with jax when we know it will be executed later.
 
-    gradient_kwargs = gradient_kwargs or {}
-    mcm_config = mcm_config or {}
-    if not config:
-        config = qml.devices.ExecutionConfig(
-            interface=interface,
-            gradient_method=diff_method,
-            grad_on_execution=None if grad_on_execution == "best" else grad_on_execution,
-            use_device_jacobian_product=device_vjp,
-            mcm_config=mcm_config,
-            gradient_keyword_arguments=gradient_kwargs,
-            derivative_order=max_diff,
-        )
-        config = _resolve_execution_config(
-            config, device, tapes, transform_program=transform_program
-        )
+    config = qml.devices.ExecutionConfig(
+        interface=interface,
+        gradient_method=diff_method,
+        grad_on_execution=None if grad_on_execution == "best" else grad_on_execution,
+        use_device_jacobian_product=device_vjp,
+        mcm_config=mcm_config or {},
+        gradient_keyword_arguments=gradient_kwargs or {},
+        derivative_order=max_diff,
+    )
+    config = _resolve_execution_config(config, device, tapes, transform_program=transform_program)
 
     config = replace(
         config,
@@ -207,11 +221,10 @@ def execute(
         derivative_order=max_diff,
     )
 
-    if transform_program is None or inner_transform is None:
-        transform_program = transform_program or qml.transforms.core.TransformProgram()
-        transform_program, inner_transform = _setup_transform_program(
-            transform_program, device, config, cache, cachesize
-        )
+    transform_program = transform_program or qml.transforms.core.TransformProgram()
+    transform_program, inner_transform = _setup_transform_program(
+        transform_program, device, config, cache, cachesize
+    )
 
     #### Executing the configured setup #####
     tapes, post_processing = transform_program(tapes)


Test patch:
diff --git a/tests/workflow/interfaces/execute/test_execute.py b/tests/workflow/interfaces/execute/test_execute.py
index 668f05858..8bea335ff 100644
--- a/tests/workflow/interfaces/execute/test_execute.py
+++ b/tests/workflow/interfaces/execute/test_execute.py
@@ -57,6 +57,28 @@ def test_execute_legacy_device():
     assert qml.math.allclose(res[0], np.cos(0.1))
 
 
+def test_config_deprecation():
+    """Test that the config argument has been deprecated."""
+
+    tape = qml.tape.QuantumScript([qml.RX(qml.numpy.array(1.0), 0)], [qml.expval(qml.Z(0))])
+    dev = qml.device("default.qubit")
+    with pytest.warns(
+        qml.PennyLaneDeprecationWarning, match="The config argument has been deprecated"
+    ):
+        qml.execute((tape,), dev, config=qml.devices.DefaultExecutionConfig)
+
+
+def test_inner_transform_program_deprecation():
+    """Test that the inner_transform argument has been deprecated."""
+
+    tape = qml.tape.QuantumScript([qml.RX(qml.numpy.array(1.0), 0)], [qml.expval(qml.Z(0))])
+    dev = qml.device("default.qubit")
+    with pytest.warns(
+        qml.PennyLaneDeprecationWarning, match="The inner_transform argument has been deprecated"
+    ):
+        qml.execute((tape,), dev, inner_transform=qml.transforms.core.TransformProgram())
+
+
 def test_execution_with_empty_batch():
     """Test that qml.execute can be used with an empty batch."""