From 891e4c8a0ac5926bf0af8b915fce1670a888fb7b Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 14:05:56 -0500 Subject: [PATCH 01/22] initial commit --- pennylane/workflow/__init__.py | 1 + .../workflow/construct_execution_config.py | 70 +++++++++ .../test_construct_execution_config.py | 141 ++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 pennylane/workflow/construct_execution_config.py create mode 100644 tests/workflow/test_construct_execution_config.py diff --git a/pennylane/workflow/__init__.py b/pennylane/workflow/__init__.py index aa0ad2e8945..5aa52342c81 100644 --- a/pennylane/workflow/__init__.py +++ b/pennylane/workflow/__init__.py @@ -44,6 +44,7 @@ """ from .construct_batch import construct_batch, get_transform_program from .construct_tape import construct_tape +from .construct_execution_config import construct_execution_config from .execution import execute from .get_best_diff_method import get_best_diff_method from .qnode import QNode, qnode diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py new file mode 100644 index 00000000000..e840728faa2 --- /dev/null +++ b/pennylane/workflow/construct_execution_config.py @@ -0,0 +1,70 @@ +# Copyright 2018-2025 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License rif is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Contains a function to construct an execution configuration from a QNode instance.""" + +import pennylane as qml +from pennylane.math import Interface + + +def construct_execution_config(qnode, resolve=True): + """Constructs the execution configuration of a QNode instance. + + Args: + qnode (QNode): the qnode we want to get the tapes and post-processing for + resolve (bool): whether or not to resolve the execution configuration + + Returns: + config (qml.devices.ExecutionConfig): the execution configuration + + **Example** + + .. code-block:: python + + >>> + >>> + """ + + def wrapper(*args, **kwargs): + + mcm_config = qml.devices.MCMConfig( + postselect_mode=qnode.execute_kwargs["postselect_mode"], + mcm_method=qnode.execute_kwargs["mcm_method"], + ) + + grad_on_execution = qnode.execute_kwargs["grad_on_execution"] + if qnode.interface in {Interface.JAX.value, Interface.JAX_JIT.value}: + grad_on_execution = False + elif grad_on_execution == "best": + grad_on_execution = None + + config = qml.devices.ExecutionConfig( + interface=qnode.interface, + gradient_method=qnode.diff_method, + grad_on_execution=grad_on_execution, + use_device_jacobian_product=qnode.execute_kwargs["device_vjp"], + derivative_order=qnode.execute_kwargs["max_diff"], + gradient_keyword_arguments=qnode.gradient_kwargs, + mcm_config=mcm_config, + ) + + if resolve: + # pylint:disable=protected-access + tape = qml.workflow.construct_tape(qnode)(*args, **kwargs) + config = qml.workflow.resolution._resolve_execution_config( + config, qnode.device, (tape,), qnode._transform_program + ) + + return config + + return wrapper diff --git a/tests/workflow/test_construct_execution_config.py b/tests/workflow/test_construct_execution_config.py new file mode 100644 index 00000000000..9bc01d3f9b8 --- /dev/null +++ b/tests/workflow/test_construct_execution_config.py @@ -0,0 +1,141 @@ +# Copyright 2018-2025 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Contains tests for `construct_execution_config`.""" + +from dataclasses import replace + +import pytest + +import pennylane as qml +from pennylane.devices import ExecutionConfig, MCMConfig +from pennylane.math import get_canonical_interface_name +from pennylane.workflow import construct_execution_config + + +def dummycircuit(): + """Dummy function.""" + qml.X(0) + return qml.expval(qml.Z(0)) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("device_name", ["default.qubit", "lightning.qubit"]) +@pytest.mark.parametrize("interface", ["autograd", "tf", "torch", "jax", "jax-jit"]) +def test_unresolved_construction(device_name, interface): + """Test that an unresolved execution config is created correctly.""" + qn = qml.QNode(dummycircuit, qml.device(device_name, wires=1), interface=interface) + + config = construct_execution_config(qn, resolve=False)() + + mcm_config = MCMConfig(None, None) + expected_config = ExecutionConfig( + grad_on_execution=False if "jax" in interface else None, + use_device_gradient=None, + use_device_jacobian_product=False, + gradient_method="best", + gradient_keyword_arguments={}, + device_options={}, + interface=get_canonical_interface_name(interface), + derivative_order=1, + mcm_config=mcm_config, + convert_to_numpy=True, + ) + + assert config == expected_config + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("interface", ["autograd", "tf", "torch", "jax", "jax-jit"]) +def test_resolved_construction_lightning_qubit(interface): + """Test that an resolved execution config is created correctly.""" + qn = qml.QNode(dummycircuit, qml.device("lightning.qubit", wires=1), interface=interface) + + config = construct_execution_config(qn, resolve=True)() + + mcm_config = MCMConfig(None, None) + expected_config = ExecutionConfig( + grad_on_execution=True, + use_device_gradient=True, + use_device_jacobian_product=False, + gradient_method="adjoint", + gradient_keyword_arguments={}, + interface=get_canonical_interface_name(interface), + derivative_order=1, + mcm_config=mcm_config, + convert_to_numpy=True, + ) + + # ignore comparison of device_options, could change + assert replace(config, device_options={}) == replace(expected_config, device_options={}) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("interface", ["autograd", "tf", "torch", "jax", "jax-jit"]) +def test_resolved_construction_default_qubit(interface): + """Test that an resolved execution config is created correctly.""" + qn = qml.QNode(dummycircuit, qml.device("default.qubit", wires=1), interface=interface) + + config = construct_execution_config(qn, resolve=True)() + + mcm_config = MCMConfig(None, None) + expected_config = ExecutionConfig( + grad_on_execution=False, + use_device_gradient=True, + use_device_jacobian_product=False, + gradient_method="backprop", + gradient_keyword_arguments={}, + interface=get_canonical_interface_name(interface), + derivative_order=1, + mcm_config=mcm_config, + convert_to_numpy=True, + ) + + # ignore comparison of device_options, could change + assert replace(config, device_options={}) == replace(expected_config, device_options={}) + + +@pytest.mark.parametrize("mcm_method", [None, "one-shot"]) +@pytest.mark.parametrize("postselect_mode", [None, "hw-like"]) +@pytest.mark.parametrize("interface", ["jax", "jax-jit"]) +@pytest.mark.jax +def test_jax_interface(mcm_method, postselect_mode, interface): + """Test constructing config with JAX interface and different MCMConfig settings.""" + + @qml.qnode( + qml.device("default.qubit"), + interface=interface, + mcm_method=mcm_method, + postselect_mode=postselect_mode, + ) + def circuit(): + qml.X(0) + return qml.expval(qml.Z(0)) + + config = construct_execution_config(circuit)(shots=100) + + expected_mcm_config = MCMConfig(mcm_method, postselect_mode="pad-invalid-samples") + expected_config = ExecutionConfig( + grad_on_execution=False, + use_device_gradient=False, + use_device_jacobian_product=False, + gradient_method=qml.gradients.param_shift, + gradient_keyword_arguments={}, + interface=get_canonical_interface_name(interface), + derivative_order=1, + mcm_config=expected_mcm_config, + convert_to_numpy=True, + ) + + # ignore comparison of device_options, could change + assert replace(config, device_options={}) == replace(expected_config, device_options={}) From 385e6de90b3f7ecdb60d1800f2e503bd213a40f1 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 14:10:25 -0500 Subject: [PATCH 02/22] add example to docstring --- .../workflow/construct_execution_config.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index e840728faa2..512479809d6 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -30,9 +30,29 @@ def construct_execution_config(qnode, resolve=True): **Example** .. code-block:: python + import pennylane as qml + import pprint + + @qml.qnode(qml.device("default.qubit", wires=1)) + def circuit(x): + qml.RX(x, 0) + return qml.expval(qml.Z(0)) + + >>> config = qml.workflow.construct_execution_config(circuit)(1.0) + >>> pprint.pprint(config) + ExecutionConfig(grad_on_execution=False, + use_device_gradient=True, + use_device_jacobian_product=False, + gradient_method='backprop', + gradient_keyword_arguments={}, + device_options={'max_workers': None, + 'prng_key': None, + 'rng': Generator(PCG64) at 0x17D5BB220}, + interface=, + derivative_order=1, + mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), + convert_to_numpy=True) - >>> - >>> """ def wrapper(*args, **kwargs): From 7669ab6c76c057c853f356e54001d166faa38423 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 14:12:29 -0500 Subject: [PATCH 03/22] add type hinting --- pennylane/workflow/construct_execution_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 512479809d6..bd5232d9dd8 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -17,7 +17,7 @@ from pennylane.math import Interface -def construct_execution_config(qnode, resolve=True): +def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): """Constructs the execution configuration of a QNode instance. Args: From 2552bff8ed81821365642f162c4ed91bf4c4af75 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 14:15:34 -0500 Subject: [PATCH 04/22] doc: changelog --- doc/releases/changelog-dev.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 64eb1cb8607..3949bab8ff3 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -6,6 +6,33 @@

Improvements 🛠

+* Added the `qml.workflow.construct_execution_config(qnode)(*args,**kwargs)` helper function. + Users can now construct the execution configuration from a particular `QNode` instance. + [(#6901)](https://github.com/PennyLaneAI/pennylane/pull/6901) + + ```python + @qml.qnode(qml.device("default.qubit", wires=1)) + def circuit(x): + qml.RX(x, 0) + return qml.expval(qml.Z(0)) + ``` + ```pycon + >>> config = qml.workflow.construct_execution_config(circuit)(1) + >>> pprint.pprint(config) + ExecutionConfig(grad_on_execution=False, + use_device_gradient=True, + use_device_jacobian_product=False, + gradient_method='backprop', + gradient_keyword_arguments={}, + device_options={'max_workers': None, + 'prng_key': None, + 'rng': Generator(PCG64) at 0x17D5BB220}, + interface=, + derivative_order=1, + mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), + convert_to_numpy=True) + ``` + * The higher order primitives in program capture can now accept inputs with abstract shapes. [(#6786)](https://github.com/PennyLaneAI/pennylane/pull/6786) From 21daa92cb41653408ff5b854e3d61c5081352ff9 Mon Sep 17 00:00:00 2001 From: Andrija Paurevic <46359773+andrijapau@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:59:19 -0500 Subject: [PATCH 05/22] Update pennylane/workflow/construct_execution_config.py Co-authored-by: Christina Lee --- pennylane/workflow/construct_execution_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index bd5232d9dd8..aaeeb2425df 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -22,7 +22,7 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): Args: qnode (QNode): the qnode we want to get the tapes and post-processing for - resolve (bool): whether or not to resolve the execution configuration + resolve (bool): whether or not to validate and fill in undetermined values like `"best"` Returns: config (qml.devices.ExecutionConfig): the execution configuration From 11416b13c4f8079314b72b0787ce97754682cb55 Mon Sep 17 00:00:00 2001 From: Andrija Paurevic <46359773+andrijapau@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:59:26 -0500 Subject: [PATCH 06/22] Update pennylane/workflow/construct_execution_config.py --- pennylane/workflow/construct_execution_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index aaeeb2425df..468eb310af7 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -21,7 +21,7 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): """Constructs the execution configuration of a QNode instance. Args: - qnode (QNode): the qnode we want to get the tapes and post-processing for + qnode (QNode): the qnode we want to get execution configuration for resolve (bool): whether or not to validate and fill in undetermined values like `"best"` Returns: From 45b863067b09adff70a09658664e7d413dd0158c Mon Sep 17 00:00:00 2001 From: Andrija Paurevic <46359773+andrijapau@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:59:44 -0500 Subject: [PATCH 07/22] Update pennylane/workflow/construct_execution_config.py Co-authored-by: Christina Lee --- pennylane/workflow/construct_execution_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 468eb310af7..95b23e1a0a3 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -55,6 +55,7 @@ def circuit(x): """ + @functools.wraps(qnode) def wrapper(*args, **kwargs): mcm_config = qml.devices.MCMConfig( From fed1b2ba6d544bdbc32eca87428a45b46d915e43 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 15:05:47 -0500 Subject: [PATCH 08/22] address Christina's review --- .../workflow/construct_execution_config.py | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index bd5232d9dd8..01f3538f6de 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -15,6 +15,8 @@ import pennylane as qml from pennylane.math import Interface +from pennylane.workflow import construct_tape +from pennylane.workflow.resolution import _resolve_execution_config def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): @@ -38,19 +40,37 @@ def circuit(x): qml.RX(x, 0) return qml.expval(qml.Z(0)) - >>> config = qml.workflow.construct_execution_config(circuit)(1.0) + If we wish to construct an unresolved execution configuration, we can specify + ``resolve=False``. This will leave properties like ``gradient_method`` and ``interface`` + in their unrefined state (e.g. ``"best"`` or ``"auto"`` respectively). + >>> config = qml.workflow.construct_execution_config(circuit, resolve=False)(1) >>> pprint.pprint(config) + ExecutionConfig(grad_on_execution=None, + use_device_gradient=None, + use_device_jacobian_product=False, + gradient_method='best', + gradient_keyword_arguments={}, + device_options={}, + interface=, + derivative_order=1, + mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), + convert_to_numpy=True) + + Specifying ``resolve=True`` will then resolve these properties appropriately for the + given ``QNode`` configuration that was provided, + >>> resolved_config = qml.workflow.construct_execution_config(circuit, resolve=True)(1) + >>> pprint.pprint(resolved_config) ExecutionConfig(grad_on_execution=False, - use_device_gradient=True, - use_device_jacobian_product=False, - gradient_method='backprop', - gradient_keyword_arguments={}, - device_options={'max_workers': None, - 'prng_key': None, - 'rng': Generator(PCG64) at 0x17D5BB220}, - interface=, - derivative_order=1, - mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), + use_device_gradient=True, + use_device_jacobian_product=False, + gradient_method='backprop', + gradient_keyword_arguments={}, + device_options={'max_workers': None, + 'prng_key': None, + 'rng': Generator(PCG64) at 0x17CFBBA00}, + interface=, + derivative_order=1, + mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), convert_to_numpy=True) """ @@ -79,9 +99,9 @@ def wrapper(*args, **kwargs): ) if resolve: + tape = construct_tape(qnode)(*args, **kwargs) # pylint:disable=protected-access - tape = qml.workflow.construct_tape(qnode)(*args, **kwargs) - config = qml.workflow.resolution._resolve_execution_config( + config = _resolve_execution_config( config, qnode.device, (tape,), qnode._transform_program ) From 618b39646b51bfb87294cd592fec19ec660c2ba1 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 15:08:41 -0500 Subject: [PATCH 09/22] refactor --- pennylane/workflow/construct_execution_config.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 7b17c5c05a2..c5b7247b777 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -12,8 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. """Contains a function to construct an execution configuration from a QNode instance.""" +import functools import pennylane as qml +from pennylane.devices import ExecutionConfig, MCMConfig from pennylane.math import Interface from pennylane.workflow import construct_tape from pennylane.workflow.resolution import _resolve_execution_config @@ -78,7 +80,7 @@ def circuit(x): @functools.wraps(qnode) def wrapper(*args, **kwargs): - mcm_config = qml.devices.MCMConfig( + mcm_config = MCMConfig( postselect_mode=qnode.execute_kwargs["postselect_mode"], mcm_method=qnode.execute_kwargs["mcm_method"], ) @@ -89,7 +91,7 @@ def wrapper(*args, **kwargs): elif grad_on_execution == "best": grad_on_execution = None - config = qml.devices.ExecutionConfig( + config = ExecutionConfig( interface=qnode.interface, gradient_method=qnode.diff_method, grad_on_execution=grad_on_execution, From 1c8290dacb3468be2afc3485d8a1b762040a2e86 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 15:12:07 -0500 Subject: [PATCH 10/22] revert bc of circular imports --- pennylane/workflow/construct_execution_config.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index c5b7247b777..86b10fb4758 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -15,7 +15,6 @@ import functools import pennylane as qml -from pennylane.devices import ExecutionConfig, MCMConfig from pennylane.math import Interface from pennylane.workflow import construct_tape from pennylane.workflow.resolution import _resolve_execution_config @@ -80,7 +79,7 @@ def circuit(x): @functools.wraps(qnode) def wrapper(*args, **kwargs): - mcm_config = MCMConfig( + mcm_config = qml.devices.MCMConfig( postselect_mode=qnode.execute_kwargs["postselect_mode"], mcm_method=qnode.execute_kwargs["mcm_method"], ) @@ -91,7 +90,7 @@ def wrapper(*args, **kwargs): elif grad_on_execution == "best": grad_on_execution = None - config = ExecutionConfig( + config = qml.devices.ExecutionConfig( interface=qnode.interface, gradient_method=qnode.diff_method, grad_on_execution=grad_on_execution, From db9a05fdc7124efdfaf8a9631489724945112d13 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 15:27:20 -0500 Subject: [PATCH 11/22] doc: Update __init__.py for workflow --- pennylane/workflow/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane/workflow/__init__.py b/pennylane/workflow/__init__.py index 5aa52342c81..5cf782595db 100644 --- a/pennylane/workflow/__init__.py +++ b/pennylane/workflow/__init__.py @@ -25,6 +25,7 @@ ~execute ~workflow.construct_tape ~workflow.construct_batch + ~workflow.construct_execution_config ~workflow.get_transform_program ~workflow.get_best_diff_method From 683027e6c435a809b1405b1a017c135445081524 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 15:51:47 -0500 Subject: [PATCH 12/22] doc: Fix docstring for sphinx --- pennylane/workflow/construct_execution_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 86b10fb4758..40248add7ce 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -44,6 +44,7 @@ def circuit(x): If we wish to construct an unresolved execution configuration, we can specify ``resolve=False``. This will leave properties like ``gradient_method`` and ``interface`` in their unrefined state (e.g. ``"best"`` or ``"auto"`` respectively). + >>> config = qml.workflow.construct_execution_config(circuit, resolve=False)(1) >>> pprint.pprint(config) ExecutionConfig(grad_on_execution=None, @@ -59,6 +60,7 @@ def circuit(x): Specifying ``resolve=True`` will then resolve these properties appropriately for the given ``QNode`` configuration that was provided, + >>> resolved_config = qml.workflow.construct_execution_config(circuit, resolve=True)(1) >>> pprint.pprint(resolved_config) ExecutionConfig(grad_on_execution=False, @@ -73,7 +75,6 @@ def circuit(x): derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), convert_to_numpy=True) - """ @functools.wraps(qnode) From 152d484bc9da31d228a2a2216000b3b2bfc18548 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:14:04 -0500 Subject: [PATCH 13/22] remove pprint from code block --- pennylane/workflow/construct_execution_config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 40248add7ce..682ff02d4d0 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -34,7 +34,6 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): .. code-block:: python import pennylane as qml - import pprint @qml.qnode(qml.device("default.qubit", wires=1)) def circuit(x): From 63b1bdcfedfbc65d140a1098934e8416b93268d7 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:21:03 -0500 Subject: [PATCH 14/22] fix: Update execution.py typing hinting --- pennylane/workflow/execution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/workflow/execution.py b/pennylane/workflow/execution.py index a118dbcd48a..e6a98cf9fca 100644 --- a/pennylane/workflow/execution.py +++ b/pennylane/workflow/execution.py @@ -46,7 +46,7 @@ def execute( interface: Optional[InterfaceLike] = Interface.AUTO, *, transform_program: TransformProgram = None, - grad_on_execution: Literal[bool, "best"] = "best", + grad_on_execution: Literal[True, False, "best"] = "best", cache: Union[None, bool, dict, Cache] = True, cachesize: int = 10000, max_diff: int = 1, From 2e570f7f5918584a0010538dded96768d3bd348d Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:22:38 -0500 Subject: [PATCH 15/22] fix: Update execution.py typing hinting --- pennylane/workflow/execution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane/workflow/execution.py b/pennylane/workflow/execution.py index e6a98cf9fca..ad0beadeedf 100644 --- a/pennylane/workflow/execution.py +++ b/pennylane/workflow/execution.py @@ -51,8 +51,8 @@ def execute( cachesize: int = 10000, max_diff: int = 1, device_vjp: Union[bool, None] = False, - postselect_mode=None, - mcm_method=None, + postselect_mode: Literal[None, "hw-like", "fill-shots"] = None, + mcm_method: Literal[None, "deferred", "one-shot", "tree-traversal"] = None, gradient_kwargs: dict = None, mcm_config="unset", config="unset", From 3204aa65c880a77aa60989b3eb36c787132844ca Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:26:10 -0500 Subject: [PATCH 16/22] fix: Update docstring --- pennylane/workflow/construct_execution_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 682ff02d4d0..53ab9540031 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -33,6 +33,7 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): **Example** .. code-block:: python + import pennylane as qml @qml.qnode(qml.device("default.qubit", wires=1)) From 0aa70ae6ff31ef87e910dbaff22bca3742a65846 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:28:12 -0500 Subject: [PATCH 17/22] fix: Update docstring --- pennylane/workflow/construct_execution_config.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 53ab9540031..4694acef70d 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -34,19 +34,21 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): .. code-block:: python - import pennylane as qml - @qml.qnode(qml.device("default.qubit", wires=1)) def circuit(x): qml.RX(x, 0) return qml.expval(qml.Z(0)) + First, let's import ``pprint`` to make it easier to read the execution configuration objects. + + >>> from pprint import pprint + If we wish to construct an unresolved execution configuration, we can specify ``resolve=False``. This will leave properties like ``gradient_method`` and ``interface`` in their unrefined state (e.g. ``"best"`` or ``"auto"`` respectively). >>> config = qml.workflow.construct_execution_config(circuit, resolve=False)(1) - >>> pprint.pprint(config) + >>> pprint(config) ExecutionConfig(grad_on_execution=None, use_device_gradient=None, use_device_jacobian_product=False, @@ -62,7 +64,7 @@ def circuit(x): given ``QNode`` configuration that was provided, >>> resolved_config = qml.workflow.construct_execution_config(circuit, resolve=True)(1) - >>> pprint.pprint(resolved_config) + >>> pprint(resolved_config) ExecutionConfig(grad_on_execution=False, use_device_gradient=True, use_device_jacobian_product=False, From c36afb40fcceae672188eaf11c7e1c861bdbebd2 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:30:47 -0500 Subject: [PATCH 18/22] Trigger CI From f547bc8954efe136e6ed41ea8097a497e0cb7f72 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 16:48:35 -0500 Subject: [PATCH 19/22] fix: Update docstring --- pennylane/workflow/construct_execution_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 4694acef70d..9182d733f15 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -25,7 +25,7 @@ def construct_execution_config(qnode: "qml.QNode", resolve: bool = True): Args: qnode (QNode): the qnode we want to get execution configuration for - resolve (bool): whether or not to validate and fill in undetermined values like `"best"` + resolve (bool): Whether or not to validate and fill in undetermined values like `"best"`. Defaults to ``True``. Returns: config (qml.devices.ExecutionConfig): the execution configuration From 368eb16aaca095ab1d87a6d58be12cefef0411d7 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 17:04:25 -0500 Subject: [PATCH 20/22] update interface as well in resolve_execution_config --- pennylane/devices/execution_config.py | 4 ++++ pennylane/workflow/construct_execution_config.py | 6 +++--- pennylane/workflow/resolution.py | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pennylane/devices/execution_config.py b/pennylane/devices/execution_config.py index 17c9363b76f..c0cdce89204 100644 --- a/pennylane/devices/execution_config.py +++ b/pennylane/devices/execution_config.py @@ -15,6 +15,7 @@ Contains the :class:`ExecutionConfig` data class. """ from dataclasses import dataclass, field +from pprint import pformat from typing import Optional, Union from pennylane.math import Interface, get_canonical_interface_name @@ -136,5 +137,8 @@ def __post_init__(self): elif not isinstance(self.mcm_config, MCMConfig): raise ValueError(f"Got invalid type {type(self.mcm_config)} for 'mcm_config'") + def __str__(self): + return pformat(self) + DefaultExecutionConfig = ExecutionConfig() diff --git a/pennylane/workflow/construct_execution_config.py b/pennylane/workflow/construct_execution_config.py index 9182d733f15..0b13700d552 100644 --- a/pennylane/workflow/construct_execution_config.py +++ b/pennylane/workflow/construct_execution_config.py @@ -72,11 +72,11 @@ def circuit(x): gradient_keyword_arguments={}, device_options={'max_workers': None, 'prng_key': None, - 'rng': Generator(PCG64) at 0x17CFBBA00}, - interface=, + 'rng': Generator(PCG64) at 0x15F6BB680}, + interface=, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), - convert_to_numpy=True) + convert_to_numpy=True) """ @functools.wraps(qnode) diff --git a/pennylane/workflow/resolution.py b/pennylane/workflow/resolution.py index d89a03c6e2d..1ec5f656fc0 100644 --- a/pennylane/workflow/resolution.py +++ b/pennylane/workflow/resolution.py @@ -251,6 +251,7 @@ def _resolve_execution_config( ) mcm_config = _resolve_mcm_config(execution_config.mcm_config, mcm_interface, finite_shots) + updated_values["interface"] = interface updated_values["mcm_config"] = mcm_config execution_config = replace(execution_config, **updated_values) From 88459b429715527ee337c0d4738a1ce53f947753 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 29 Jan 2025 17:05:14 -0500 Subject: [PATCH 21/22] update changelog as well --- doc/releases/changelog-dev.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 3949bab8ff3..3f4d80a795c 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -26,8 +26,8 @@ gradient_keyword_arguments={}, device_options={'max_workers': None, 'prng_key': None, - 'rng': Generator(PCG64) at 0x17D5BB220}, - interface=, + 'rng': Generator(PCG64) at 0x15F6BB680}, + interface=, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), convert_to_numpy=True) From 07f3ca13fc09183e74fa47476c7f3305709cbbc9 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 30 Jan 2025 10:10:42 -0500 Subject: [PATCH 22/22] remove __str__ --- pennylane/devices/execution_config.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pennylane/devices/execution_config.py b/pennylane/devices/execution_config.py index c0cdce89204..17c9363b76f 100644 --- a/pennylane/devices/execution_config.py +++ b/pennylane/devices/execution_config.py @@ -15,7 +15,6 @@ Contains the :class:`ExecutionConfig` data class. """ from dataclasses import dataclass, field -from pprint import pformat from typing import Optional, Union from pennylane.math import Interface, get_canonical_interface_name @@ -137,8 +136,5 @@ def __post_init__(self): elif not isinstance(self.mcm_config, MCMConfig): raise ValueError(f"Got invalid type {type(self.mcm_config)} for 'mcm_config'") - def __str__(self): - return pformat(self) - DefaultExecutionConfig = ExecutionConfig()