From 6a6f0b59576cc222b1ae35597fd5faf680862289 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 15:37:13 -0500 Subject: [PATCH 01/46] fix: Update PauliX operator --- pennylane/ops/qubit/non_parametric_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/ops/qubit/non_parametric_ops.py b/pennylane/ops/qubit/non_parametric_ops.py index 77f7967e23a..af289148dfd 100644 --- a/pennylane/ops/qubit/non_parametric_ops.py +++ b/pennylane/ops/qubit/non_parametric_ops.py @@ -249,7 +249,7 @@ def pauli_rep(self): ) return self._pauli_rep - def __init__(self, wires: Optional[WiresLike] = None, id: Optional[str] = None): + def __init__(self, wires: WiresLike, id: Optional[str] = None): super().__init__(wires=wires, id=id) def label( From 1c572acb996e59b634cfd70845f27b2858f10911 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 15:46:09 -0500 Subject: [PATCH 02/46] fix: PauliError channel --- pennylane/ops/channel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py index f28166c039c..447aca2b54e 100644 --- a/pennylane/ops/channel.py +++ b/pennylane/ops/channel.py @@ -20,6 +20,7 @@ from pennylane import math as np from pennylane.operation import AnyWires, Channel +from pennylane.wires import WiresLike class AmplitudeDamping(Channel): @@ -563,7 +564,7 @@ class PauliError(Channel): num_params = 2 """int: Number of trainable parameters that the operator depends on.""" - def __init__(self, operators, p, wires=None, id=None): + def __init__(self, operators, p, wires: WiresLike, id=None): super().__init__(operators, p, wires=wires, id=id) # check if the specified operators are legal From 0276a0f7baa294f5422381e5a93e1ed30825e876 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 15:54:05 -0500 Subject: [PATCH 03/46] Revert "fix: PauliError channel" This reverts commit 1c572acb996e59b634cfd70845f27b2858f10911. --- pennylane/ops/channel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py index 447aca2b54e..f28166c039c 100644 --- a/pennylane/ops/channel.py +++ b/pennylane/ops/channel.py @@ -20,7 +20,6 @@ from pennylane import math as np from pennylane.operation import AnyWires, Channel -from pennylane.wires import WiresLike class AmplitudeDamping(Channel): @@ -564,7 +563,7 @@ class PauliError(Channel): num_params = 2 """int: Number of trainable parameters that the operator depends on.""" - def __init__(self, operators, p, wires: WiresLike, id=None): + def __init__(self, operators, p, wires=None, id=None): super().__init__(operators, p, wires=wires, id=id) # check if the specified operators are legal From 018ec06d032325ff6c8ac84dc419aa053b133275 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 15:56:17 -0500 Subject: [PATCH 04/46] fix: Remove wires=None from channel.py --- pennylane/ops/channel.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py index f28166c039c..271759671fc 100644 --- a/pennylane/ops/channel.py +++ b/pennylane/ops/channel.py @@ -20,6 +20,7 @@ from pennylane import math as np from pennylane.operation import AnyWires, Channel +from pennylane.wires import WiresLike class AmplitudeDamping(Channel): @@ -563,7 +564,7 @@ class PauliError(Channel): num_params = 2 """int: Number of trainable parameters that the operator depends on.""" - def __init__(self, operators, p, wires=None, id=None): + def __init__(self, operators, p, *, wires: WiresLike, id=None): super().__init__(operators, p, wires=wires, id=id) # check if the specified operators are legal @@ -713,7 +714,7 @@ class QubitChannel(Channel): num_wires = AnyWires grad_method = None - def __init__(self, K_list, wires=None, id=None): + def __init__(self, K_list, *, wires: WiresLike, id=None): super().__init__(*K_list, wires=wires, id=id) # check all Kraus matrices are square matrices @@ -744,7 +745,7 @@ def _flatten(self): # pylint: disable=arguments-differ, unused-argument @classmethod - def _primitive_bind_call(cls, K_list, wires=None, id=None): + def _primitive_bind_call(cls, K_list, *, wires: WiresLike, id=None): return super()._primitive_bind_call(*K_list, wires=wires) @staticmethod From 0cd69579abeb81747e707c92ef10a7e0f5360a05 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:04:18 -0500 Subject: [PATCH 05/46] fix: Update test_default_mixed_autograd.py for new PauliError signature --- tests/devices/test_default_mixed_autograd.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_autograd.py b/tests/devices/test_default_mixed_autograd.py index 0d76e5b1375..fae732d9a6c 100644 --- a/tests/devices/test_default_mixed_autograd.py +++ b/tests/devices/test_default_mixed_autograd.py @@ -225,9 +225,13 @@ def test_partial_subsystem(self, mocker): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", np.array(0.5), 0), "_apply_channel", 2), - (qml.PauliError("XXX", np.array(0.5), [0, 1, 2]), "_apply_channel_tensordot", 4), - (qml.PauliError("X" * 8, np.array(0.5), list(range(8))), "_apply_channel_tensordot", 8), + (qml.PauliError("X", np.array(0.5), wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", np.array(0.5), wires=[0, 1, 2]), "_apply_channel_tensordot", 4), + ( + qml.PauliError("X" * 8, np.array(0.5), wires=list(range(8))), + "_apply_channel_tensordot", + 8, + ), ], ) def test_method_choice(mocker, op, exp_method, dev_wires): From 0576be0a59db0df72b09cc07449e088d88f1ed5f Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:05:29 -0500 Subject: [PATCH 06/46] fix: Update test_default_mixed_jax.py for new PauliError signature --- tests/devices/test_default_mixed_jax.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_jax.py b/tests/devices/test_default_mixed_jax.py index adcb5b77b51..26cd1762332 100644 --- a/tests/devices/test_default_mixed_jax.py +++ b/tests/devices/test_default_mixed_jax.py @@ -329,10 +329,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", jnp.array(0.5), 0), "_apply_channel", 2), - (qml.PauliError("XXX", jnp.array(0.5), [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", jnp.array(0.5), wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", jnp.array(0.5), wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, jnp.array(0.5), list(range(8))), + qml.PauliError("X" * 8, jnp.array(0.5), wires=list(range(8))), "_apply_channel_tensordot", 8, ), From 34ec71942b3612909fb7a28c3dc77ef8f1ee2132 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:05:50 -0500 Subject: [PATCH 07/46] fix: Update test_default_mixed_tf.py for new PauliError signature --- tests/devices/test_default_mixed_tf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_tf.py b/tests/devices/test_default_mixed_tf.py index 48749d24ea9..a072be21b46 100644 --- a/tests/devices/test_default_mixed_tf.py +++ b/tests/devices/test_default_mixed_tf.py @@ -209,10 +209,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", tf.constant(0.5), 0), "_apply_channel", 2), - (qml.PauliError("XXX", tf.constant(0.5), [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", tf.constant(0.5), wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", tf.constant(0.5), wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, tf.constant(0.5), list(range(8))), + qml.PauliError("X" * 8, tf.constant(0.5), wires=list(range(8))), "_apply_channel_tensordot", 8, ), From e6c2b1622026e27e585c6e51094860f3a3f8a332 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:06:18 -0500 Subject: [PATCH 08/46] fix: Update test_default_mixed_torch.py for new PauliError signature --- tests/devices/test_default_mixed_torch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_torch.py b/tests/devices/test_default_mixed_torch.py index 5622f5010d6..c3d835b4c7c 100644 --- a/tests/devices/test_default_mixed_torch.py +++ b/tests/devices/test_default_mixed_torch.py @@ -212,10 +212,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", 0.5, 0), "_apply_channel", 2), - (qml.PauliError("XXX", 0.5, [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", 0.5, wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", 0.5, wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, 0.5, list(range(8))), + qml.PauliError("X" * 8, 0.5, wires=list(range(8))), "_apply_channel_tensordot", 8, ), From ada9b984d3f984fdc309a5684c18cda8d014acff Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:15:32 -0500 Subject: [PATCH 09/46] fix: Update test_default_clifford.py for new PauliError signature --- tests/devices/test_default_clifford.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/devices/test_default_clifford.py b/tests/devices/test_default_clifford.py index ad420ee8120..e0cdd1be606 100644 --- a/tests/devices/test_default_clifford.py +++ b/tests/devices/test_default_clifford.py @@ -412,7 +412,10 @@ def circuit_fn(): (qml.GlobalPhase(1.0), (None, [])), (qml.Snapshot(), (None, [])), (qml.DepolarizingChannel(0.2, [2]), ("DEPOLARIZE1(0.2)", [2])), - (qml.PauliError("XYZ", 0.2, [0, 1, 2]), ("CORRELATED_ERROR(0.2)", ["X0", "Y1", "Z2"])), + ( + qml.PauliError("XYZ", 0.2, wires=[0, 1, 2]), + ("CORRELATED_ERROR(0.2)", ["X0", "Y1", "Z2"]), + ), ], ) def test_pl_to_stim(pl_op, stim_op): From cba441c298d54bfb964d667e9f94e495a254ff94 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:16:42 -0500 Subject: [PATCH 10/46] fix: Update test_default_mixed_jax.py for new PauliError signature --- tests/devices/test_default_mixed_jax.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_jax.py b/tests/devices/test_default_mixed_jax.py index 26cd1762332..8b97e9203b5 100644 --- a/tests/devices/test_default_mixed_jax.py +++ b/tests/devices/test_default_mixed_jax.py @@ -365,10 +365,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", jnp.array(0.5), 0), "_apply_channel", 2), - (qml.PauliError("XXX", jnp.array(0.5), [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", jnp.array(0.5), wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", jnp.array(0.5), wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, jnp.array(0.5), list(range(8))), + qml.PauliError("X" * 8, jnp.array(0.5), wires=list(range(8))), "_apply_channel_tensordot", 8, ), From 0c5a37ebcb06602565b7a7975fae91c1c232eea0 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:17:14 -0500 Subject: [PATCH 11/46] fix: Update test_default_mixed_tf.py for new PauliError signature --- tests/devices/test_default_mixed_tf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_tf.py b/tests/devices/test_default_mixed_tf.py index a072be21b46..d2a8964625a 100644 --- a/tests/devices/test_default_mixed_tf.py +++ b/tests/devices/test_default_mixed_tf.py @@ -245,10 +245,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", tf.constant(0.5), 0), "_apply_channel", 2), - (qml.PauliError("XXX", tf.constant(0.5), [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", tf.constant(0.5), wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", tf.constant(0.5), wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, tf.constant(0.5), list(range(8))), + qml.PauliError("X" * 8, tf.constant(0.5), wires=list(range(8))), "_apply_channel_tensordot", 8, ), From 9769340827710195cb481b68b19ed0f9d79208e5 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:17:42 -0500 Subject: [PATCH 12/46] fix: Update test_default_mixed_torch.py for new PauliError signature --- tests/devices/test_default_mixed_torch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/devices/test_default_mixed_torch.py b/tests/devices/test_default_mixed_torch.py index c3d835b4c7c..c54fa83e443 100644 --- a/tests/devices/test_default_mixed_torch.py +++ b/tests/devices/test_default_mixed_torch.py @@ -251,10 +251,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", 0.5, 0), "_apply_channel", 2), - (qml.PauliError("XXX", 0.5, [0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", 0.5, wires=0), "_apply_channel", 2), + (qml.PauliError("XXX", 0.5, wires=[0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, 0.5, list(range(8))), + qml.PauliError("X" * 8, 0.5, wires=list(range(8))), "_apply_channel_tensordot", 8, ), From cf5a69c8a8dea41a07d39152a5091112fbfb7e79 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 16:48:48 -0500 Subject: [PATCH 13/46] fix: Update PCPhase operator to disallow wires=None and adjust test_qsvt.py to follow --- pennylane/ops/qubit/parametric_ops_multi_qubit.py | 4 ++-- tests/templates/test_subroutines/test_qsvt.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pennylane/ops/qubit/parametric_ops_multi_qubit.py b/pennylane/ops/qubit/parametric_ops_multi_qubit.py index 1064315965c..235dca8b818 100644 --- a/pennylane/ops/qubit/parametric_ops_multi_qubit.py +++ b/pennylane/ops/qubit/parametric_ops_multi_qubit.py @@ -598,7 +598,7 @@ def _flatten(self) -> FlatPytree: hyperparameter = (("dim", self.hyperparameters["dimension"][0]),) return tuple(self.data), (self.wires, hyperparameter) - def __init__(self, phi: TensorLike, dim: int, wires: WiresLike, id: Optional[str] = None): + def __init__(self, phi: TensorLike, dim: int, *, wires: WiresLike, id: Optional[str] = None): wires = wires if isinstance(wires, Wires) else Wires(wires) if not (isinstance(dim, int) and (dim <= 2 ** len(wires))): @@ -661,7 +661,7 @@ def compute_eigvals(*params: TensorLike, **hyperparams) -> TensorLike: @staticmethod def compute_decomposition( - *params: TensorLike, wires: Optional[WiresLike] = None, **hyperparams + *params: TensorLike, wires: WiresLike, **hyperparams ) -> list["qml.operation.Operator"]: r"""Representation of the operator as a product of other operators (static method). diff --git a/tests/templates/test_subroutines/test_qsvt.py b/tests/templates/test_subroutines/test_qsvt.py index ffddc951288..380c058b4b5 100644 --- a/tests/templates/test_subroutines/test_qsvt.py +++ b/tests/templates/test_subroutines/test_qsvt.py @@ -235,7 +235,7 @@ def test_ltorch(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires) for phi in angles], + [qml.PCPhase(phi, 2, wires=wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) @@ -260,7 +260,7 @@ def test_QSVT_jax(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires) for phi in angles], + [qml.PCPhase(phi, 2, wires=wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) @@ -318,7 +318,7 @@ def test_QSVT_tensorflow(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires) for phi in angles], + [qml.PCPhase(phi, 2, wires=wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) From b43e1a9b57266ec7d4e7822ae673b673da6b4155 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 17:04:09 -0500 Subject: [PATCH 14/46] fix: Remove ', *,' from signatures I changed :) --- pennylane/ops/channel.py | 6 +++--- pennylane/ops/qubit/parametric_ops_multi_qubit.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py index 271759671fc..b500a635df1 100644 --- a/pennylane/ops/channel.py +++ b/pennylane/ops/channel.py @@ -564,7 +564,7 @@ class PauliError(Channel): num_params = 2 """int: Number of trainable parameters that the operator depends on.""" - def __init__(self, operators, p, *, wires: WiresLike, id=None): + def __init__(self, operators, p, wires: WiresLike, id=None): super().__init__(operators, p, wires=wires, id=id) # check if the specified operators are legal @@ -714,7 +714,7 @@ class QubitChannel(Channel): num_wires = AnyWires grad_method = None - def __init__(self, K_list, *, wires: WiresLike, id=None): + def __init__(self, K_list, wires: WiresLike, id=None): super().__init__(*K_list, wires=wires, id=id) # check all Kraus matrices are square matrices @@ -745,7 +745,7 @@ def _flatten(self): # pylint: disable=arguments-differ, unused-argument @classmethod - def _primitive_bind_call(cls, K_list, *, wires: WiresLike, id=None): + def _primitive_bind_call(cls, K_list, wires: WiresLike, id=None): return super()._primitive_bind_call(*K_list, wires=wires) @staticmethod diff --git a/pennylane/ops/qubit/parametric_ops_multi_qubit.py b/pennylane/ops/qubit/parametric_ops_multi_qubit.py index 235dca8b818..e49bb9d3542 100644 --- a/pennylane/ops/qubit/parametric_ops_multi_qubit.py +++ b/pennylane/ops/qubit/parametric_ops_multi_qubit.py @@ -598,7 +598,7 @@ def _flatten(self) -> FlatPytree: hyperparameter = (("dim", self.hyperparameters["dimension"][0]),) return tuple(self.data), (self.wires, hyperparameter) - def __init__(self, phi: TensorLike, dim: int, *, wires: WiresLike, id: Optional[str] = None): + def __init__(self, phi: TensorLike, dim: int, wires: WiresLike, id: Optional[str] = None): wires = wires if isinstance(wires, Wires) else Wires(wires) if not (isinstance(dim, int) and (dim <= 2 ** len(wires))): From 654873e6eb91de0bc4fc4f25a157f0404eb68d10 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 17:10:15 -0500 Subject: [PATCH 15/46] fix: Disallow wires=None in ClassicalShadowMP in classical_shadow.py --- pennylane/measurements/classical_shadow.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pennylane/measurements/classical_shadow.py b/pennylane/measurements/classical_shadow.py index 7af5b7f523f..412b19ae021 100644 --- a/pennylane/measurements/classical_shadow.py +++ b/pennylane/measurements/classical_shadow.py @@ -23,7 +23,7 @@ import pennylane as qml from pennylane.operation import Operator -from pennylane.wires import Wires +from pennylane.wires import Wires, WiresLike from .measurements import MeasurementShapeError, MeasurementTransform, Shadow, ShadowExpval @@ -226,9 +226,7 @@ class ClassicalShadowMP(MeasurementTransform): where the instance has to be identified """ - def __init__( - self, wires: Optional[Wires] = None, seed: Optional[int] = None, id: Optional[str] = None - ): + def __init__(self, wires: WiresLike, seed: Optional[int] = None, id: Optional[str] = None): self.seed = seed super().__init__(wires=wires, id=id) From 2aa2907efb892f4fc12c6c263d06e254c82d84f7 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 17:47:09 -0500 Subject: [PATCH 16/46] fix: Disallow wires=None from Identity and GlobalPhase --- pennylane/ops/identity.py | 23 ++++++++++++++--------- pennylane/pauli/pauli_arithmetic.py | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/pennylane/ops/identity.py b/pennylane/ops/identity.py index dc6a401af25..5667e849aab 100644 --- a/pennylane/ops/identity.py +++ b/pennylane/ops/identity.py @@ -27,6 +27,7 @@ Operation, SparseMatrixUndefinedError, ) +from pennylane.wires import WiresLike class Identity(CVObservable, Operation): @@ -61,15 +62,16 @@ class Identity(CVObservable, Operation): ev_order = 1 @classmethod - def _primitive_bind_call(cls, wires=None, **kwargs): # pylint: disable=arguments-differ - wires = [] if wires is None else wires + def _primitive_bind_call( + cls, wires: WiresLike = (), **kwargs + ): # pylint: disable=arguments-differ return super()._primitive_bind_call(wires=wires, **kwargs) def _flatten(self): return tuple(), (self.wires, tuple()) - def __init__(self, wires=None, id=None): - super().__init__(wires=[] if wires is None else wires, id=id) + def __init__(self, wires: WiresLike = (), id=None): + super().__init__(wires=wires, id=id) self._hyperparameters = {"n_wires": len(self.wires)} self._pauli_rep = qml.pauli.PauliSentence({qml.pauli.PauliWord({}): 1.0}) @@ -308,12 +310,13 @@ def circuit(): grad_method = None @classmethod - def _primitive_bind_call(cls, phi, wires=None, **kwargs): # pylint: disable=arguments-differ - wires = [] if wires is None else wires + def _primitive_bind_call( + cls, phi, wires: WiresLike = (), **kwargs + ): # pylint: disable=arguments-differ return super()._primitive_bind_call(phi, wires=wires, **kwargs) - def __init__(self, phi, wires=None, id=None): - super().__init__(phi, wires=[] if wires is None else wires, id=id) + def __init__(self, phi, wires: WiresLike = (), id=None): + super().__init__(phi, wires=wires, id=id) @staticmethod def compute_eigvals(phi, n_wires=1): # pylint: disable=arguments-differ @@ -412,7 +415,9 @@ def compute_diagonalizing_gates( return [] @staticmethod - def compute_decomposition(phi, wires=None): # pylint:disable=arguments-differ,unused-argument + def compute_decomposition( + phi, wires: WiresLike = () + ): # pylint:disable=arguments-differ,unused-argument r"""Representation of the operator as a product of other operators (static method). .. note:: diff --git a/pennylane/pauli/pauli_arithmetic.py b/pennylane/pauli/pauli_arithmetic.py index b453582397e..d101f5d442d 100644 --- a/pennylane/pauli/pauli_arithmetic.py +++ b/pennylane/pauli/pauli_arithmetic.py @@ -23,7 +23,7 @@ from pennylane import math from pennylane.ops import Identity, PauliX, PauliY, PauliZ, Prod, SProd, Sum from pennylane.typing import TensorLike -from pennylane.wires import Wires +from pennylane.wires import Wires, WiresLike I = "I" X = "X" @@ -504,7 +504,7 @@ def _get_csr_indices(self, wire_order): current_size *= 2 return indices - def operation(self, wire_order=None): + def operation(self, wire_order: WiresLike = ()): """Returns a native PennyLane :class:`~pennylane.operation.Operation` representing the PauliWord.""" if len(self) == 0: return Identity(wires=wire_order) From c5d5c8137b57e01463bbd9226745de54f83c2073 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 17:49:55 -0500 Subject: [PATCH 17/46] fix: Revert changes to tests/devices/ --- tests/devices/test_default_clifford.py | 5 +---- tests/devices/test_default_mixed_autograd.py | 10 +++------- tests/devices/test_default_mixed_jax.py | 12 ++++++------ tests/devices/test_default_mixed_tf.py | 12 ++++++------ tests/devices/test_default_mixed_torch.py | 12 ++++++------ 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/tests/devices/test_default_clifford.py b/tests/devices/test_default_clifford.py index e0cdd1be606..ad420ee8120 100644 --- a/tests/devices/test_default_clifford.py +++ b/tests/devices/test_default_clifford.py @@ -412,10 +412,7 @@ def circuit_fn(): (qml.GlobalPhase(1.0), (None, [])), (qml.Snapshot(), (None, [])), (qml.DepolarizingChannel(0.2, [2]), ("DEPOLARIZE1(0.2)", [2])), - ( - qml.PauliError("XYZ", 0.2, wires=[0, 1, 2]), - ("CORRELATED_ERROR(0.2)", ["X0", "Y1", "Z2"]), - ), + (qml.PauliError("XYZ", 0.2, [0, 1, 2]), ("CORRELATED_ERROR(0.2)", ["X0", "Y1", "Z2"])), ], ) def test_pl_to_stim(pl_op, stim_op): diff --git a/tests/devices/test_default_mixed_autograd.py b/tests/devices/test_default_mixed_autograd.py index fae732d9a6c..0d76e5b1375 100644 --- a/tests/devices/test_default_mixed_autograd.py +++ b/tests/devices/test_default_mixed_autograd.py @@ -225,13 +225,9 @@ def test_partial_subsystem(self, mocker): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", np.array(0.5), wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", np.array(0.5), wires=[0, 1, 2]), "_apply_channel_tensordot", 4), - ( - qml.PauliError("X" * 8, np.array(0.5), wires=list(range(8))), - "_apply_channel_tensordot", - 8, - ), + (qml.PauliError("X", np.array(0.5), 0), "_apply_channel", 2), + (qml.PauliError("XXX", np.array(0.5), [0, 1, 2]), "_apply_channel_tensordot", 4), + (qml.PauliError("X" * 8, np.array(0.5), list(range(8))), "_apply_channel_tensordot", 8), ], ) def test_method_choice(mocker, op, exp_method, dev_wires): diff --git a/tests/devices/test_default_mixed_jax.py b/tests/devices/test_default_mixed_jax.py index 8b97e9203b5..adcb5b77b51 100644 --- a/tests/devices/test_default_mixed_jax.py +++ b/tests/devices/test_default_mixed_jax.py @@ -329,10 +329,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", jnp.array(0.5), wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", jnp.array(0.5), wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", jnp.array(0.5), 0), "_apply_channel", 2), + (qml.PauliError("XXX", jnp.array(0.5), [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, jnp.array(0.5), wires=list(range(8))), + qml.PauliError("X" * 8, jnp.array(0.5), list(range(8))), "_apply_channel_tensordot", 8, ), @@ -365,10 +365,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", jnp.array(0.5), wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", jnp.array(0.5), wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", jnp.array(0.5), 0), "_apply_channel", 2), + (qml.PauliError("XXX", jnp.array(0.5), [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, jnp.array(0.5), wires=list(range(8))), + qml.PauliError("X" * 8, jnp.array(0.5), list(range(8))), "_apply_channel_tensordot", 8, ), diff --git a/tests/devices/test_default_mixed_tf.py b/tests/devices/test_default_mixed_tf.py index d2a8964625a..48749d24ea9 100644 --- a/tests/devices/test_default_mixed_tf.py +++ b/tests/devices/test_default_mixed_tf.py @@ -209,10 +209,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", tf.constant(0.5), wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", tf.constant(0.5), wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", tf.constant(0.5), 0), "_apply_channel", 2), + (qml.PauliError("XXX", tf.constant(0.5), [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, tf.constant(0.5), wires=list(range(8))), + qml.PauliError("X" * 8, tf.constant(0.5), list(range(8))), "_apply_channel_tensordot", 8, ), @@ -245,10 +245,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", tf.constant(0.5), wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", tf.constant(0.5), wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", tf.constant(0.5), 0), "_apply_channel", 2), + (qml.PauliError("XXX", tf.constant(0.5), [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, tf.constant(0.5), wires=list(range(8))), + qml.PauliError("X" * 8, tf.constant(0.5), list(range(8))), "_apply_channel_tensordot", 8, ), diff --git a/tests/devices/test_default_mixed_torch.py b/tests/devices/test_default_mixed_torch.py index c54fa83e443..5622f5010d6 100644 --- a/tests/devices/test_default_mixed_torch.py +++ b/tests/devices/test_default_mixed_torch.py @@ -212,10 +212,10 @@ class TestApplyChannelMethodChoice: (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel_tensordot", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", 0.5, wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", 0.5, wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", 0.5, 0), "_apply_channel", 2), + (qml.PauliError("XXX", 0.5, [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, 0.5, wires=list(range(8))), + qml.PauliError("X" * 8, 0.5, list(range(8))), "_apply_channel_tensordot", 8, ), @@ -251,10 +251,10 @@ def test_with_numpy_state(self, mocker, op, exp_method, dev_wires): (qml.MultiControlledX(wires=list(range(2))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(3))), "_apply_channel", 3), (qml.MultiControlledX(wires=list(range(8))), "_apply_channel_tensordot", 8), - (qml.PauliError("X", 0.5, wires=0), "_apply_channel", 2), - (qml.PauliError("XXX", 0.5, wires=[0, 1, 2]), "_apply_channel", 4), + (qml.PauliError("X", 0.5, 0), "_apply_channel", 2), + (qml.PauliError("XXX", 0.5, [0, 1, 2]), "_apply_channel", 4), ( - qml.PauliError("X" * 8, 0.5, wires=list(range(8))), + qml.PauliError("X" * 8, 0.5, list(range(8))), "_apply_channel_tensordot", 8, ), From 8af5e075df6377f99e3755f57a1f7607cdf203df Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 17:50:49 -0500 Subject: [PATCH 18/46] fix: Revert changes to test_qsvt.py --- tests/templates/test_subroutines/test_qsvt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/templates/test_subroutines/test_qsvt.py b/tests/templates/test_subroutines/test_qsvt.py index 380c058b4b5..ffddc951288 100644 --- a/tests/templates/test_subroutines/test_qsvt.py +++ b/tests/templates/test_subroutines/test_qsvt.py @@ -235,7 +235,7 @@ def test_ltorch(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires=wires) for phi in angles], + [qml.PCPhase(phi, 2, wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) @@ -260,7 +260,7 @@ def test_QSVT_jax(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires=wires) for phi in angles], + [qml.PCPhase(phi, 2, wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) @@ -318,7 +318,7 @@ def test_QSVT_tensorflow(self, input_matrix, poly, wires): op = qml.QSVT( qml.BlockEncode(input_matrix, wires), - [qml.PCPhase(phi, 2, wires=wires) for phi in angles], + [qml.PCPhase(phi, 2, wires) for phi in angles], ) assert np.allclose(qml.matrix(op), default_matrix) From 610643add344a12c2a0158e2ccaacd0e72c55296 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 9 Dec 2024 18:13:00 -0500 Subject: [PATCH 19/46] fix: Update pauli_arithmetic.py to disallow wire_order=None --- pennylane/pauli/pauli_arithmetic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/pauli/pauli_arithmetic.py b/pennylane/pauli/pauli_arithmetic.py index d101f5d442d..2e409e6118c 100644 --- a/pennylane/pauli/pauli_arithmetic.py +++ b/pennylane/pauli/pauli_arithmetic.py @@ -999,7 +999,7 @@ def _sum_different_structure_pws(indices, data): matrix.eliminate_zeros() return matrix - def operation(self, wire_order=None): + def operation(self, wire_order: WiresLike = ()): """Returns a native PennyLane :class:`~pennylane.operation.Operation` representing the PauliSentence.""" if len(self) == 0: return qml.s_prod(0, Identity(wires=wire_order)) From e42d29f679814692c7f3e1712b1969500a006c31 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 10 Dec 2024 09:35:34 -0500 Subject: [PATCH 20/46] feat: Add type hinting to MultiControlledX --- pennylane/ops/op_math/controlled_ops.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index 93370bcb37d..db6dbfaaa55 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -25,6 +25,7 @@ import pennylane as qml from pennylane.operation import AnyWires, Wires from pennylane.ops.qubit.parametric_ops_single_qubit import stack_last +from pennylane.wires import WiresLike from .controlled import ControlledOp from .controlled_decompositions import decompose_mcx @@ -1115,7 +1116,13 @@ def _primitive_bind_call(cls, wires, control_values=None, work_wires=None, id=No ) # pylint: disable=too-many-arguments - def __init__(self, control_wires=None, wires=None, control_values=None, work_wires=None): + def __init__( + self, + control_wires: WiresLike = None, + wires: WiresLike = None, + control_values=None, + work_wires: WiresLike = None, + ): # First raise deprecation warnings regardless of the validity of other arguments if isinstance(control_values, str): From bb05f87e544a953cbbf49e13a24ac1e382688548 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 10 Dec 2024 09:35:56 -0500 Subject: [PATCH 21/46] feat: Add type hinting to WireCut --- pennylane/ops/meta.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 6d63d820609..a85aafaf66d 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -23,7 +23,7 @@ import pennylane as qml from pennylane.operation import AnyWires, Operation -from pennylane.wires import Wires # pylint: disable=unused-import +from pennylane.wires import Wires, WiresLike # pylint: disable=unused-import class Barrier(Operation): @@ -119,7 +119,7 @@ class WireCut(Operation): num_wires = AnyWires grad_method = None - def __init__(self, *params, wires=None, id=None): + def __init__(self, *params, wires: WiresLike = None, id=None): if wires == []: raise ValueError( f"{self.__class__.__name__}: wrong number of wires. " @@ -128,7 +128,7 @@ def __init__(self, *params, wires=None, id=None): super().__init__(*params, wires=wires, id=id) @staticmethod - def compute_decomposition(wires): # pylint: disable=unused-argument + def compute_decomposition(wires: WiresLike): # pylint: disable=unused-argument r"""Representation of the operator as a product of other operators (static method). Since this operator is a placeholder inside a circuit, it decomposes into an empty list. From 061a98812acdfc80438239c479b710a8740674f6 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 16 Dec 2024 11:29:36 -0500 Subject: [PATCH 22/46] fix: More updates --- pennylane/measurements/classical_shadow.py | 3 ++- pennylane/ops/channel.py | 8 ++++++-- pennylane/ops/meta.py | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pennylane/measurements/classical_shadow.py b/pennylane/measurements/classical_shadow.py index 412b19ae021..d768840bb0d 100644 --- a/pennylane/measurements/classical_shadow.py +++ b/pennylane/measurements/classical_shadow.py @@ -89,7 +89,7 @@ def circuit(x, obs): return ShadowExpvalMP(H=H, seed=seed, k=k) -def classical_shadow(wires, seed=None): +def classical_shadow(wires: WiresLike, seed=None): """ The classical shadow measurement protocol. @@ -228,6 +228,7 @@ class ClassicalShadowMP(MeasurementTransform): def __init__(self, wires: WiresLike, seed: Optional[int] = None, id: Optional[str] = None): self.seed = seed + wires = Wires(wires) super().__init__(wires=wires, id=id) def _flatten(self): diff --git a/pennylane/ops/channel.py b/pennylane/ops/channel.py index b500a635df1..837ee72a83a 100644 --- a/pennylane/ops/channel.py +++ b/pennylane/ops/channel.py @@ -20,7 +20,7 @@ from pennylane import math as np from pennylane.operation import AnyWires, Channel -from pennylane.wires import WiresLike +from pennylane.wires import Wires, WiresLike class AmplitudeDamping(Channel): @@ -59,7 +59,8 @@ class AmplitudeDamping(Channel): num_wires = 1 grad_method = "F" - def __init__(self, gamma, wires, id=None): + def __init__(self, gamma, wires: WiresLike, id=None): + wires = Wires(wires) super().__init__(gamma, wires=wires, id=id) @staticmethod @@ -565,6 +566,7 @@ class PauliError(Channel): """int: Number of trainable parameters that the operator depends on.""" def __init__(self, operators, p, wires: WiresLike, id=None): + wires = Wires(wires) super().__init__(operators, p, wires=wires, id=id) # check if the specified operators are legal @@ -715,6 +717,7 @@ class QubitChannel(Channel): grad_method = None def __init__(self, K_list, wires: WiresLike, id=None): + wires = Wires(wires) super().__init__(*K_list, wires=wires, id=id) # check all Kraus matrices are square matrices @@ -746,6 +749,7 @@ def _flatten(self): # pylint: disable=arguments-differ, unused-argument @classmethod def _primitive_bind_call(cls, K_list, wires: WiresLike, id=None): + wires = Wires(wires) return super()._primitive_bind_call(*K_list, wires=wires) @staticmethod diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index a85aafaf66d..4884e900da5 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -46,7 +46,8 @@ class Barrier(Operation): num_wires = AnyWires par_domain = None - def __init__(self, wires=Wires([]), only_visual=False, id=None): + def __init__(self, wires: WiresLike = (), only_visual=False, id=None): + wires = Wires(wires) self.only_visual = only_visual self.hyperparameters["only_visual"] = only_visual super().__init__(wires=wires, id=id) @@ -120,7 +121,8 @@ class WireCut(Operation): grad_method = None def __init__(self, *params, wires: WiresLike = None, id=None): - if wires == []: + wires = Wires([]) if wires is None else Wires(wires) + if len(wires) == 0: raise ValueError( f"{self.__class__.__name__}: wrong number of wires. " f"At least one wire has to be given." From 73499831d105e1e6504eb1c6378b01d89dc1afca Mon Sep 17 00:00:00 2001 From: andrijapau Date: Mon, 16 Dec 2024 12:29:04 -0500 Subject: [PATCH 23/46] fix: Update tests --- pennylane/measurements/classical_shadow.py | 1 - pennylane/ops/meta.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pennylane/measurements/classical_shadow.py b/pennylane/measurements/classical_shadow.py index d768840bb0d..fab46c0ad51 100644 --- a/pennylane/measurements/classical_shadow.py +++ b/pennylane/measurements/classical_shadow.py @@ -228,7 +228,6 @@ class ClassicalShadowMP(MeasurementTransform): def __init__(self, wires: WiresLike, seed: Optional[int] = None, id: Optional[str] = None): self.seed = seed - wires = Wires(wires) super().__init__(wires=wires, id=id) def _flatten(self): diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 4884e900da5..221a0073f1a 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -121,8 +121,7 @@ class WireCut(Operation): grad_method = None def __init__(self, *params, wires: WiresLike = None, id=None): - wires = Wires([]) if wires is None else Wires(wires) - if len(wires) == 0: + if wires == []: raise ValueError( f"{self.__class__.__name__}: wrong number of wires. " f"At least one wire has to be given." From 99ef3f167242140afce2364a668ea4befa1a4dad Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 17 Dec 2024 09:30:15 -0500 Subject: [PATCH 24/46] fix: Update classical_shadow.py --- pennylane/measurements/classical_shadow.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pennylane/measurements/classical_shadow.py b/pennylane/measurements/classical_shadow.py index fab46c0ad51..7e9dc5285c8 100644 --- a/pennylane/measurements/classical_shadow.py +++ b/pennylane/measurements/classical_shadow.py @@ -226,7 +226,12 @@ class ClassicalShadowMP(MeasurementTransform): where the instance has to be identified """ - def __init__(self, wires: WiresLike, seed: Optional[int] = None, id: Optional[str] = None): + def __init__( + self, + wires: Optional[WiresLike] = None, + seed: Optional[int] = None, + id: Optional[str] = None, + ): self.seed = seed super().__init__(wires=wires, id=id) From aac11f24675a4350c8d5209bd1056a35c2ac0928 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 17 Dec 2024 09:54:11 -0500 Subject: [PATCH 25/46] fix: Update MultiControlledX in controlled_ops.py --- pennylane/ops/op_math/controlled_ops.py | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index db6dbfaaa55..528efabd04d 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -1118,11 +1118,14 @@ def _primitive_bind_call(cls, wires, control_values=None, work_wires=None, id=No # pylint: disable=too-many-arguments def __init__( self, - control_wires: WiresLike = None, - wires: WiresLike = None, + control_wires: WiresLike = (), + wires: WiresLike = (), control_values=None, - work_wires: WiresLike = None, + work_wires: WiresLike = (), ): + control_wires = Wires(() if control_wires is None else control_wires) + wires = Wires(() if wires is None else wires) + work_wires = Wires(() if work_wires is None else work_wires) # First raise deprecation warnings regardless of the validity of other arguments if isinstance(control_values, str): @@ -1131,22 +1134,19 @@ def __init__( "supported in future releases, Use a list of booleans or integers instead.", qml.PennyLaneDeprecationWarning, ) - if control_wires is not None: + if len(control_wires) > 0: warnings.warn( "The control_wires keyword for MultiControlledX is deprecated, and will " "be removed soon. Use wires = (*control_wires, target_wire) instead.", UserWarning, ) - if wires is None: + if len(wires) == 0: raise ValueError("Must specify the wires where the operation acts on") - wires = wires if isinstance(wires, Wires) else Wires(wires) - - if control_wires is not None: + if len(control_wires) > 0: if len(wires) != 1: raise ValueError("MultiControlledX accepts a single target wire.") - control_wires = Wires(control_wires) else: if len(wires) < 2: raise ValueError( @@ -1179,7 +1179,7 @@ def wires(self): # pylint: disable=unused-argument, arguments-differ @staticmethod - def compute_matrix(control_wires, control_values=None, **kwargs): + def compute_matrix(control_wires: WiresLike, control_values=None, **kwargs): r"""Representation of the operator as a canonical matrix in the computational basis (static method). The canonical matrix is the textbook matrix representation that does not consider wires. @@ -1222,7 +1222,9 @@ def matrix(self, wire_order=None): # pylint: disable=unused-argument, arguments-differ @staticmethod - def compute_decomposition(wires=None, work_wires=None, control_values=None, **kwargs): + def compute_decomposition( + wires: WiresLike = None, work_wires: WiresLike = None, control_values=None, **kwargs + ): r"""Representation of the operator as a product of other operators (static method). .. math:: O = O_1 O_2 \dots O_n. @@ -1249,6 +1251,7 @@ def compute_decomposition(wires=None, work_wires=None, control_values=None, **kw Toffoli(wires=[0, 1, 'aux'])] """ + wires = Wires(() if wires is None else wires) if len(wires) < 2: raise ValueError(f"Wrong number of wires. {len(wires)} given. Need at least 2.") @@ -1324,7 +1327,7 @@ class CRX(ControlledOp): name = "CRX" parameter_frequencies = [(0.5, 1.0)] - def __init__(self, phi, wires, id=None): + def __init__(self, phi, wires: WiresLike, id=None): # We use type.__call__ instead of calling the class directly so that we don't bind the # operator primitive when new program capture is enabled base = type.__call__(qml.RX, phi, wires=wires[1:]) @@ -1341,7 +1344,7 @@ def _unflatten(cls, data, metadata): return cls(*data, wires=metadata[0]) @classmethod - def _primitive_bind_call(cls, phi, wires, id=None): + def _primitive_bind_call(cls, phi, wires: WiresLike, id=None): return cls._primitive.bind(phi, *wires, n_wires=len(wires)) @staticmethod @@ -1392,7 +1395,7 @@ def compute_matrix(theta): # pylint: disable=arguments-differ return qml.math.stack([stack_last(row) for row in matrix], axis=-2) @staticmethod - def compute_decomposition(phi, wires): # pylint: disable=arguments-differ + def compute_decomposition(phi, wires: WiresLike): # pylint: disable=arguments-differ r"""Representation of the operator as a product of other operators (static method). : .. math:: O = O_1 O_2 \dots O_n. From 893a9f7ddc28d70d04ffa6d68b04dc41a9a45638 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 17 Dec 2024 11:10:59 -0500 Subject: [PATCH 26/46] fix: Update qft.py --- pennylane/templates/subroutines/qft.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pennylane/templates/subroutines/qft.py b/pennylane/templates/subroutines/qft.py index 4cb0bd758df..0c9730a29e5 100644 --- a/pennylane/templates/subroutines/qft.py +++ b/pennylane/templates/subroutines/qft.py @@ -22,6 +22,7 @@ import pennylane as qml from pennylane.operation import AnyWires, Operation +from pennylane.wires import Wires, WiresLike class QFT(Operation): @@ -131,8 +132,8 @@ def scFT_add(m, k, n_wires): num_wires = AnyWires grad_method = None - def __init__(self, wires=None, id=None): - wires = qml.wires.Wires(wires) + def __init__(self, wires: WiresLike, id=None): + wires = Wires(wires) self.hyperparameters["n_wires"] = len(wires) super().__init__(wires=wires, id=id) @@ -149,7 +150,9 @@ def compute_matrix(n_wires): # pylint: disable=arguments-differ return np.fft.ifft(np.eye(2**n_wires), norm="ortho") @staticmethod - def compute_decomposition(wires, n_wires): # pylint: disable=arguments-differ,unused-argument + def compute_decomposition( + wires: WiresLike, n_wires=None + ): # pylint: disable=arguments-differ,unused-argument r"""Representation of the operator as a product of other operators (static method). .. math:: O = O_1 O_2 \dots O_n. @@ -173,10 +176,16 @@ def compute_decomposition(wires, n_wires): # pylint: disable=arguments-differ,u H(1), ControlledPhaseShift(1.5707963267948966, wires=Wires([2, 1])), H(2), - H(4), - SWAP(wires=[0, 4])] + SWAP(wires=[0, 2])] """ + wires = Wires(wires) + if n_wires is None: + n_wires = len(wires) + else: + if len(wires) != n_wires: + raise ValueError("`n_wires` does not match length of `wires`.") + shifts = [2 * np.pi * 2**-i for i in range(2, n_wires + 1)] shift_len = len(shifts) From 37816914350ecd8ef6c082aacb8805c361e110aa Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 17 Dec 2024 11:16:00 -0500 Subject: [PATCH 27/46] fix: Update grover.py --- pennylane/templates/subroutines/grover.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pennylane/templates/subroutines/grover.py b/pennylane/templates/subroutines/grover.py index 11924dc828c..c3e5e292858 100644 --- a/pennylane/templates/subroutines/grover.py +++ b/pennylane/templates/subroutines/grover.py @@ -18,7 +18,7 @@ from pennylane.operation import AnyWires, Operation from pennylane.ops import GlobalPhase, Hadamard, MultiControlledX, PauliZ -from pennylane.wires import Wires +from pennylane.wires import Wires, WiresLike class GroverOperator(Operation): @@ -109,13 +109,16 @@ def _flatten(self): hyperparameters = (("work_wires", self.hyperparameters["work_wires"]),) return tuple(), (self.wires, hyperparameters) - def __init__(self, wires=None, work_wires=None, id=None): - if (not hasattr(wires, "__len__")) or (len(wires) < 2): + def __init__(self, wires: WiresLike = None, work_wires: WiresLike = None, id=None): + work_wires = Wires(() if work_wires is None else work_wires) + wires = Wires(() if wires is None else wires) + + if len(wires) < 2: raise ValueError("GroverOperator must have at least two wires provided.") self._hyperparameters = { "n_wires": len(wires), - "work_wires": Wires(work_wires) if work_wires is not None else Wires([]), + "work_wires": work_wires, } super().__init__(wires=wires, id=id) @@ -126,7 +129,7 @@ def num_params(self): @staticmethod def compute_decomposition( - wires, work_wires, **kwargs + wires: WiresLike, work_wires: WiresLike, **kwargs ): # pylint: disable=arguments-differ,unused-argument r"""Representation of the operator as a product of other operators. From 5e0e85bd787a5b6588cf9c34c83b3c3e587448e9 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Tue, 17 Dec 2024 12:08:15 -0500 Subject: [PATCH 28/46] fix: Improve coverage on qft.py --- tests/templates/test_subroutines/test_qft.py | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/templates/test_subroutines/test_qft.py b/tests/templates/test_subroutines/test_qft.py index a3554b1d079..37fe473e3b6 100644 --- a/tests/templates/test_subroutines/test_qft.py +++ b/tests/templates/test_subroutines/test_qft.py @@ -37,6 +37,29 @@ def test_QFT(self): exp = QFT assert np.allclose(res, exp) + def test_QFT_compute_decomposition_error(self): + """Test that an error is raised for incorrect n_wires""" + with pytest.raises(ValueError, match="`n_wires` does not match length of `wires`."): + qml.QFT.compute_decomposition(wires=[0, 1], n_wires=1) + + @pytest.mark.parametrize("n_qubits", range(2, 6)) + def test_QFT_compute_decomposition(self, n_qubits): + """Test if the QFT operation is correctly decomposed""" + decomp = qml.QFT.compute_decomposition(wires=range(n_qubits)) + + dev = qml.device("default.qubit", wires=n_qubits) + + out_states = [] + for state in np.eye(2**n_qubits): + ops = [qml.StatePrep(state, wires=range(n_qubits))] + decomp + qs = qml.tape.QuantumScript(ops, [qml.state()]) + out_states.append(dev.execute(qs)) + + reconstructed_unitary = np.array(out_states).T + expected_unitary = qml.QFT(wires=range(n_qubits)).matrix() + + assert np.allclose(reconstructed_unitary, expected_unitary) + @pytest.mark.parametrize("n_qubits", range(2, 6)) def test_QFT_decomposition(self, n_qubits): """Test if the QFT operation is correctly decomposed""" From 6d696bbdb4558f12172a63991888b673850a7183 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Wed, 18 Dec 2024 11:05:00 -0500 Subject: [PATCH 29/46] fix: Update controlled.py --- pennylane/ops/op_math/controlled.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index 06279a04a39..d49209660c6 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -31,7 +31,7 @@ from pennylane.capture.capture_diff import create_non_interpreted_prim from pennylane.compiler import compiler from pennylane.operation import Operator -from pennylane.wires import Wires +from pennylane.wires import Wires, WiresLike from .controlled_decompositions import ctrl_decomp_bisect, ctrl_decomp_zyz from .symbolicop import SymbolicOp @@ -175,7 +175,7 @@ def create_controlled_op(op, control, control_values=None, work_wires=None): # Flatten nested controlled operations to a multi-controlled operation for better # decomposition algorithms. This includes special cases like CRX, CRot, etc. if isinstance(op, Controlled): - work_wires = work_wires or [] + work_wires = () if work_wires is None else work_wires return ctrl( op.base, control=control + op.control_wires, @@ -489,9 +489,16 @@ def _primitive_bind_call( ) # pylint: disable=too-many-function-args - def __init__(self, base, control_wires, control_values=None, work_wires=None, id=None): + def __init__( + self, + base, + control_wires: WiresLike, + control_values=None, + work_wires: WiresLike = None, + id=None, + ): control_wires = Wires(control_wires) - work_wires = Wires([]) if work_wires is None else Wires(work_wires) + work_wires = Wires(() if work_wires is None else work_wires) if control_values is None: control_values = [True] * len(control_wires) From 69b2eb947f6078c9f727ff8c561f1aa5438686e5 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 14:36:46 -0500 Subject: [PATCH 30/46] fix: Update meta.py to remove unnecessary pylint disable --- pennylane/ops/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 221a0073f1a..3de2d2e5dbb 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -23,7 +23,7 @@ import pennylane as qml from pennylane.operation import AnyWires, Operation -from pennylane.wires import Wires, WiresLike # pylint: disable=unused-import +from pennylane.wires import Wires, WiresLike class Barrier(Operation): From 885421cce976a549f2e5dafd24fef3e854d5220e Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 14:51:41 -0500 Subject: [PATCH 31/46] fix: Update grover.py --- pennylane/templates/subroutines/grover.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pennylane/templates/subroutines/grover.py b/pennylane/templates/subroutines/grover.py index c3e5e292858..15c275a7e65 100644 --- a/pennylane/templates/subroutines/grover.py +++ b/pennylane/templates/subroutines/grover.py @@ -109,9 +109,9 @@ def _flatten(self): hyperparameters = (("work_wires", self.hyperparameters["work_wires"]),) return tuple(), (self.wires, hyperparameters) - def __init__(self, wires: WiresLike = None, work_wires: WiresLike = None, id=None): - work_wires = Wires(() if work_wires is None else work_wires) - wires = Wires(() if wires is None else wires) + def __init__(self, wires: WiresLike, work_wires: WiresLike = (), id=None): + wires = Wires(wires) + work_wires = Wires(work_wires) if len(wires) < 2: raise ValueError("GroverOperator must have at least two wires provided.") From 55864972a6666df959c48fd74aa0d0c7679295cd Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 15:03:38 -0500 Subject: [PATCH 32/46] fix: Update grover.py --- pennylane/templates/subroutines/grover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/templates/subroutines/grover.py b/pennylane/templates/subroutines/grover.py index 15c275a7e65..1d051fd3fe5 100644 --- a/pennylane/templates/subroutines/grover.py +++ b/pennylane/templates/subroutines/grover.py @@ -111,7 +111,7 @@ def _flatten(self): def __init__(self, wires: WiresLike, work_wires: WiresLike = (), id=None): wires = Wires(wires) - work_wires = Wires(work_wires) + work_wires = Wires(() if work_wires is None else work_wires) if len(wires) < 2: raise ValueError("GroverOperator must have at least two wires provided.") From 0e39ee9142d13d665369021e029c73dc112cd3b0 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 15:44:06 -0500 Subject: [PATCH 33/46] fix: clean up controlled_*.py --- pennylane/ops/op_math/controlled.py | 17 +++++++++++------ pennylane/ops/op_math/controlled_ops.py | 7 +++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index d49209660c6..9997d86f1b1 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -148,10 +148,12 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control, control_values=None, work_wires=None): +def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" - control = qml.wires.Wires(control) + control = Wires(control) + work_wires = Wires(() if work_wires is None else work_wires) + if isinstance(control_values, (int, bool)): control_values = [control_values] elif control_values is None: @@ -269,7 +271,7 @@ def _capture_ctrl_transform(qfunc: Callable, control, control_values, work_wires @wraps(qfunc) def new_qfunc(*args, **kwargs): jaxpr = jax.make_jaxpr(functools.partial(qfunc, **kwargs))(*args) - control_wires = qml.wires.Wires(control) # make sure is iterable + control_wires = Wires(control) # make sure is iterable ctrl_prim.bind( *jaxpr.consts, *args, @@ -318,7 +320,9 @@ def _get_pauli_x_based_ops(): return qml.X, qml.CNOT, qml.Toffoli, qml.MultiControlledX -def _try_wrap_in_custom_ctrl_op(op, control, control_values=None, work_wires=None): +def _try_wrap_in_custom_ctrl_op( + op, control: WiresLike, control_values=None, work_wires: WiresLike = () +): """Wraps a controlled operation in custom ControlledOp, returns None if not applicable.""" ops_with_custom_ctrl_ops = _get_special_ops() @@ -336,7 +340,9 @@ def _try_wrap_in_custom_ctrl_op(op, control, control_values=None, work_wires=Non return None -def _handle_pauli_x_based_controlled_ops(op, control, control_values, work_wires): +def _handle_pauli_x_based_controlled_ops( + op, control: WiresLike, control_values, work_wires: WiresLike = None +): """Handles PauliX-based controlled operations.""" op_map = { @@ -355,7 +361,6 @@ def _handle_pauli_x_based_controlled_ops(op, control, control_values, work_wires wires=control + op.wires, control_values=control_values, work_wires=work_wires ) - work_wires = work_wires or [] return qml.MultiControlledX( wires=control + op.wires, control_values=control_values + op.control_values, diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index 5a4ecdaf8b1..a454f9fa170 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -1262,7 +1262,7 @@ def matrix(self, wire_order=None): # pylint: disable=unused-argument, arguments-differ @staticmethod def compute_decomposition( - wires: WiresLike = None, work_wires: WiresLike = None, control_values=None, **kwargs + wires: WiresLike, work_wires: WiresLike, control_values=None, **kwargs ): r"""Representation of the operator as a product of other operators (static method). @@ -1283,7 +1283,7 @@ def compute_decomposition( **Example:** >>> print(qml.MultiControlledX.compute_decomposition( - ... wires=[0,1,2,3], control_values=[1,1,1], work_wires=qml.wires.Wires("aux"))) + ... wires=[0,1,2,3], control_values=[1,1,1], work_wires="aux")) [Toffoli(wires=[2, 'aux', 3]), Toffoli(wires=[0, 1, 'aux']), Toffoli(wires=[2, 'aux', 3]), @@ -1291,6 +1291,7 @@ def compute_decomposition( """ wires = Wires(() if wires is None else wires) + work_wires = Wires(() if work_wires is None else work_wires) if len(wires) < 2: raise ValueError(f"Wrong number of wires. {len(wires)} given. Need at least 2.") @@ -1301,8 +1302,6 @@ def compute_decomposition( if control_values is None: control_values = [True] * len(control_wires) - work_wires = work_wires or [] - flips1 = [qml.X(w) for w, val in zip(control_wires, control_values) if not val] decomp = decompose_mcx(control_wires, target_wire, work_wires) From 5fe2e8400c3c9a08887ea93769c908d41d11430a Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 15:48:32 -0500 Subject: [PATCH 34/46] fix: clean up phase_adder.py --- pennylane/templates/subroutines/phase_adder.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pennylane/templates/subroutines/phase_adder.py b/pennylane/templates/subroutines/phase_adder.py index 722dfad9787..9460f0e3feb 100644 --- a/pennylane/templates/subroutines/phase_adder.py +++ b/pennylane/templates/subroutines/phase_adder.py @@ -19,7 +19,7 @@ import pennylane as qml from pennylane.operation import Operation -from pennylane.wires import WiresLike +from pennylane.wires import Wires, WiresLike def _add_k_fourier(k, wires: WiresLike): @@ -127,8 +127,8 @@ def __init__( self, k, x_wires: WiresLike, mod=None, work_wire: WiresLike = (), id=None ): # pylint: disable=too-many-arguments - work_wire = qml.wires.Wires(() if work_wire is None else work_wire) - x_wires = qml.wires.Wires(x_wires) + work_wire = Wires(() if work_wire is None else work_wire) + x_wires = Wires(x_wires) num_work_wires = len(work_wire) @@ -152,15 +152,11 @@ def __init__( "None of the wires in work_wire should be included in x_wires." ) - all_wires = ( - qml.wires.Wires(x_wires) + qml.wires.Wires(work_wire) - if work_wire - else qml.wires.Wires(x_wires) - ) + all_wires = x_wires + work_wire self.hyperparameters["k"] = k % mod self.hyperparameters["mod"] = mod - self.hyperparameters["work_wire"] = qml.wires.Wires(work_wire) + self.hyperparameters["work_wire"] = work_wire self.hyperparameters["x_wires"] = x_wires super().__init__(wires=all_wires, id=id) From b6e306a74cbf091e486d2bdc8bd60f4c05222c97 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 15:59:18 -0500 Subject: [PATCH 35/46] fix: further clean-up in controlled.py --- pennylane/ops/op_math/controlled.py | 46 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index 9997d86f1b1..a88f0eba301 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -42,16 +42,20 @@ def ctrl( op: Operator, control: Any, control_values: Optional[Sequence[bool]] = None, - work_wires: Optional[Any] = None, + work_wires: Optional[Any] = (), ) -> Operator: ... + + @overload def ctrl( op: Callable, control: Any, control_values: Optional[Sequence[bool]] = None, - work_wires: Optional[Any] = None, + work_wires: Optional[Any] = (), ) -> Callable: ... -def ctrl(op, control: Any, control_values=None, work_wires=None): + + +def ctrl(op, control: WiresLike, control_values=None, work_wires: WiresLike = ()): """Create a method that applies a controlled version of the provided op. :func:`~.qjit` compatible. @@ -148,7 +152,7 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): +def create_controlled_op(op, control: WiresLike, control_values=None, work_wires: WiresLike = ()): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" control = Wires(control) @@ -201,7 +205,7 @@ def create_controlled_op(op, control, control_values=None, work_wires: WiresLike return _ctrl_transform(op, control, control_values, work_wires) -def _ctrl_transform(op, control, control_values, work_wires): +def _ctrl_transform(op, control: WiresLike, control_values, work_wires: WiresLike): @wraps(op) def wrapper(*args, **kwargs): qscript = qml.tape.make_qscript(op)(*args, **kwargs) @@ -261,7 +265,9 @@ def _(*_, **__): return ctrl_prim -def _capture_ctrl_transform(qfunc: Callable, control, control_values, work_wires) -> Callable: +def _capture_ctrl_transform( + qfunc: Callable, control: WiresLike, control_values, work_wires: WiresLike +) -> Callable: """Capture compatible way of performing an ctrl transform.""" # note that this logic is tested in `tests/capture/test_nested_plxpr.py` import jax # pylint: disable=import-outside-toplevel @@ -341,7 +347,7 @@ def _try_wrap_in_custom_ctrl_op( def _handle_pauli_x_based_controlled_ops( - op, control: WiresLike, control_values, work_wires: WiresLike = None + op, control: WiresLike, control_values, work_wires: WiresLike = () ): """Handles PauliX-based controlled operations.""" @@ -486,7 +492,12 @@ def __new__(cls, base, *_, **__): # pylint: disable=arguments-differ @classmethod def _primitive_bind_call( - cls, base, control_wires, control_values=None, work_wires=None, id=None + cls, + base, + control_wires: WiresLike, + control_values=None, + work_wires: WiresLike = (), + id=None, ): control_wires = Wires(control_wires) return cls._primitive.bind( @@ -499,7 +510,7 @@ def __init__( base, control_wires: WiresLike, control_values=None, - work_wires: WiresLike = None, + work_wires: WiresLike = (), id=None, ): control_wires = Wires(control_wires) @@ -663,17 +674,17 @@ def _compute_matrix_from_base(self): return qmlmath.block_diag([left_pad, base_matrix, right_pad]) - def matrix(self, wire_order=None): + def matrix(self, wire_order: WiresLike = None): if self.compute_matrix is not Operator.compute_matrix: canonical_matrix = self.compute_matrix(*self.data) else: canonical_matrix = self._compute_matrix_from_base() - wire_order = wire_order or self.wires + wire_order = self.wires if wire_order is None else wire_order return qml.math.expand_matrix(canonical_matrix, wires=self.wires, wire_order=wire_order) # pylint: disable=arguments-differ - def sparse_matrix(self, wire_order=None, format="csr"): + def sparse_matrix(self, wire_order: WiresLike = None, format="csr"): if wire_order is not None: raise NotImplementedError("wire_order argument is not yet implemented.") @@ -925,7 +936,14 @@ def __new__(cls, *_, **__): return object.__new__(cls) # pylint: disable=too-many-function-args - def __init__(self, base, control_wires, control_values=None, work_wires=None, id=None): + def __init__( + self, + base, + control_wires: WiresLike, + control_values=None, + work_wires: WiresLike = None, + id=None, + ): super().__init__(base, control_wires, control_values, work_wires, id) # check the grad_recipe validity if self.grad_recipe is None: @@ -975,7 +993,7 @@ def parameter_frequencies(self): if Controlled._primitive is not None: # pylint: disable=protected-access @Controlled._primitive.def_impl # pylint: disable=protected-access - def _(base, *control_wires, control_values=None, work_wires=None, id=None): + def _(base, *control_wires, control_values=None, work_wires: WiresLike = None, id=None): return type.__call__( Controlled, base, From fe8d4a5d43235a4d9feff10ca2c3683fa86c92bc Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 16:35:38 -0500 Subject: [PATCH 36/46] Revert "fix: further clean-up in controlled.py" This reverts commit b6e306a74cbf091e486d2bdc8bd60f4c05222c97. --- pennylane/ops/op_math/controlled.py | 46 +++++++++-------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index a88f0eba301..9997d86f1b1 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -42,20 +42,16 @@ def ctrl( op: Operator, control: Any, control_values: Optional[Sequence[bool]] = None, - work_wires: Optional[Any] = (), + work_wires: Optional[Any] = None, ) -> Operator: ... - - @overload def ctrl( op: Callable, control: Any, control_values: Optional[Sequence[bool]] = None, - work_wires: Optional[Any] = (), + work_wires: Optional[Any] = None, ) -> Callable: ... - - -def ctrl(op, control: WiresLike, control_values=None, work_wires: WiresLike = ()): +def ctrl(op, control: Any, control_values=None, work_wires=None): """Create a method that applies a controlled version of the provided op. :func:`~.qjit` compatible. @@ -152,7 +148,7 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control: WiresLike, control_values=None, work_wires: WiresLike = ()): +def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" control = Wires(control) @@ -205,7 +201,7 @@ def create_controlled_op(op, control: WiresLike, control_values=None, work_wires return _ctrl_transform(op, control, control_values, work_wires) -def _ctrl_transform(op, control: WiresLike, control_values, work_wires: WiresLike): +def _ctrl_transform(op, control, control_values, work_wires): @wraps(op) def wrapper(*args, **kwargs): qscript = qml.tape.make_qscript(op)(*args, **kwargs) @@ -265,9 +261,7 @@ def _(*_, **__): return ctrl_prim -def _capture_ctrl_transform( - qfunc: Callable, control: WiresLike, control_values, work_wires: WiresLike -) -> Callable: +def _capture_ctrl_transform(qfunc: Callable, control, control_values, work_wires) -> Callable: """Capture compatible way of performing an ctrl transform.""" # note that this logic is tested in `tests/capture/test_nested_plxpr.py` import jax # pylint: disable=import-outside-toplevel @@ -347,7 +341,7 @@ def _try_wrap_in_custom_ctrl_op( def _handle_pauli_x_based_controlled_ops( - op, control: WiresLike, control_values, work_wires: WiresLike = () + op, control: WiresLike, control_values, work_wires: WiresLike = None ): """Handles PauliX-based controlled operations.""" @@ -492,12 +486,7 @@ def __new__(cls, base, *_, **__): # pylint: disable=arguments-differ @classmethod def _primitive_bind_call( - cls, - base, - control_wires: WiresLike, - control_values=None, - work_wires: WiresLike = (), - id=None, + cls, base, control_wires, control_values=None, work_wires=None, id=None ): control_wires = Wires(control_wires) return cls._primitive.bind( @@ -510,7 +499,7 @@ def __init__( base, control_wires: WiresLike, control_values=None, - work_wires: WiresLike = (), + work_wires: WiresLike = None, id=None, ): control_wires = Wires(control_wires) @@ -674,17 +663,17 @@ def _compute_matrix_from_base(self): return qmlmath.block_diag([left_pad, base_matrix, right_pad]) - def matrix(self, wire_order: WiresLike = None): + def matrix(self, wire_order=None): if self.compute_matrix is not Operator.compute_matrix: canonical_matrix = self.compute_matrix(*self.data) else: canonical_matrix = self._compute_matrix_from_base() - wire_order = self.wires if wire_order is None else wire_order + wire_order = wire_order or self.wires return qml.math.expand_matrix(canonical_matrix, wires=self.wires, wire_order=wire_order) # pylint: disable=arguments-differ - def sparse_matrix(self, wire_order: WiresLike = None, format="csr"): + def sparse_matrix(self, wire_order=None, format="csr"): if wire_order is not None: raise NotImplementedError("wire_order argument is not yet implemented.") @@ -936,14 +925,7 @@ def __new__(cls, *_, **__): return object.__new__(cls) # pylint: disable=too-many-function-args - def __init__( - self, - base, - control_wires: WiresLike, - control_values=None, - work_wires: WiresLike = None, - id=None, - ): + def __init__(self, base, control_wires, control_values=None, work_wires=None, id=None): super().__init__(base, control_wires, control_values, work_wires, id) # check the grad_recipe validity if self.grad_recipe is None: @@ -993,7 +975,7 @@ def parameter_frequencies(self): if Controlled._primitive is not None: # pylint: disable=protected-access @Controlled._primitive.def_impl # pylint: disable=protected-access - def _(base, *control_wires, control_values=None, work_wires: WiresLike = None, id=None): + def _(base, *control_wires, control_values=None, work_wires=None, id=None): return type.__call__( Controlled, base, From 153984c9d3941fb3144a07eab1bfee4818b50ce0 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 16:48:48 -0500 Subject: [PATCH 37/46] fix: Update controlled_ops.py --- pennylane/ops/op_math/controlled_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index a454f9fa170..d3dc1da401c 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -1262,7 +1262,7 @@ def matrix(self, wire_order=None): # pylint: disable=unused-argument, arguments-differ @staticmethod def compute_decomposition( - wires: WiresLike, work_wires: WiresLike, control_values=None, **kwargs + wires: WiresLike, work_wires: WiresLike = (), control_values=None, **kwargs ): r"""Representation of the operator as a product of other operators (static method). From d0e252f96e22cbbdc3dcfe5098d14f17376c7947 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 17:14:32 -0500 Subject: [PATCH 38/46] fix: Update controlled_ops.py --- pennylane/ops/op_math/controlled.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index 9997d86f1b1..a3da9f2464a 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -148,11 +148,11 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): +def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = None): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" control = Wires(control) - work_wires = Wires(() if work_wires is None else work_wires) + # work_wires = Wires(() if work_wires is None else work_wires) if isinstance(control_values, (int, bool)): control_values = [control_values] @@ -321,7 +321,7 @@ def _get_pauli_x_based_ops(): def _try_wrap_in_custom_ctrl_op( - op, control: WiresLike, control_values=None, work_wires: WiresLike = () + op, control: WiresLike, control_values=None, work_wires: WiresLike = None ): """Wraps a controlled operation in custom ControlledOp, returns None if not applicable.""" @@ -341,7 +341,7 @@ def _try_wrap_in_custom_ctrl_op( def _handle_pauli_x_based_controlled_ops( - op, control: WiresLike, control_values, work_wires: WiresLike = None + op, control: WiresLike, control_values, work_wires: WiresLike ): """Handles PauliX-based controlled operations.""" From 4d7633beeeae7a7ba9d1038b170b45f22e7cf0f4 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 17:20:26 -0500 Subject: [PATCH 39/46] Revert "fix: Update controlled_ops.py" This reverts commit 153984c9d3941fb3144a07eab1bfee4818b50ce0. --- pennylane/ops/op_math/controlled_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index d3dc1da401c..a454f9fa170 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -1262,7 +1262,7 @@ def matrix(self, wire_order=None): # pylint: disable=unused-argument, arguments-differ @staticmethod def compute_decomposition( - wires: WiresLike, work_wires: WiresLike = (), control_values=None, **kwargs + wires: WiresLike, work_wires: WiresLike, control_values=None, **kwargs ): r"""Representation of the operator as a product of other operators (static method). From 67b12769400a51b9d67265797c52714ee055d301 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 17:20:38 -0500 Subject: [PATCH 40/46] Revert "fix: Update controlled_ops.py" This reverts commit d0e252f96e22cbbdc3dcfe5098d14f17376c7947. --- pennylane/ops/op_math/controlled.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index a3da9f2464a..9997d86f1b1 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -148,11 +148,11 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = None): +def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" control = Wires(control) - # work_wires = Wires(() if work_wires is None else work_wires) + work_wires = Wires(() if work_wires is None else work_wires) if isinstance(control_values, (int, bool)): control_values = [control_values] @@ -321,7 +321,7 @@ def _get_pauli_x_based_ops(): def _try_wrap_in_custom_ctrl_op( - op, control: WiresLike, control_values=None, work_wires: WiresLike = None + op, control: WiresLike, control_values=None, work_wires: WiresLike = () ): """Wraps a controlled operation in custom ControlledOp, returns None if not applicable.""" @@ -341,7 +341,7 @@ def _try_wrap_in_custom_ctrl_op( def _handle_pauli_x_based_controlled_ops( - op, control: WiresLike, control_values, work_wires: WiresLike + op, control: WiresLike, control_values, work_wires: WiresLike = None ): """Handles PauliX-based controlled operations.""" From 6839d94d020ff64960325df71329650fd7649d71 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 17:20:47 -0500 Subject: [PATCH 41/46] Revert "fix: clean up controlled_*.py" This reverts commit 0e39ee9142d13d665369021e029c73dc112cd3b0. --- pennylane/ops/op_math/controlled.py | 17 ++++++----------- pennylane/ops/op_math/controlled_ops.py | 7 ++++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index 9997d86f1b1..d49209660c6 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -148,12 +148,10 @@ def cond_fn(): return create_controlled_op(op, control, control_values=control_values, work_wires=work_wires) -def create_controlled_op(op, control, control_values=None, work_wires: WiresLike = ()): +def create_controlled_op(op, control, control_values=None, work_wires=None): """Default ``qml.ctrl`` implementation, allowing other implementations to call it when needed.""" - control = Wires(control) - work_wires = Wires(() if work_wires is None else work_wires) - + control = qml.wires.Wires(control) if isinstance(control_values, (int, bool)): control_values = [control_values] elif control_values is None: @@ -271,7 +269,7 @@ def _capture_ctrl_transform(qfunc: Callable, control, control_values, work_wires @wraps(qfunc) def new_qfunc(*args, **kwargs): jaxpr = jax.make_jaxpr(functools.partial(qfunc, **kwargs))(*args) - control_wires = Wires(control) # make sure is iterable + control_wires = qml.wires.Wires(control) # make sure is iterable ctrl_prim.bind( *jaxpr.consts, *args, @@ -320,9 +318,7 @@ def _get_pauli_x_based_ops(): return qml.X, qml.CNOT, qml.Toffoli, qml.MultiControlledX -def _try_wrap_in_custom_ctrl_op( - op, control: WiresLike, control_values=None, work_wires: WiresLike = () -): +def _try_wrap_in_custom_ctrl_op(op, control, control_values=None, work_wires=None): """Wraps a controlled operation in custom ControlledOp, returns None if not applicable.""" ops_with_custom_ctrl_ops = _get_special_ops() @@ -340,9 +336,7 @@ def _try_wrap_in_custom_ctrl_op( return None -def _handle_pauli_x_based_controlled_ops( - op, control: WiresLike, control_values, work_wires: WiresLike = None -): +def _handle_pauli_x_based_controlled_ops(op, control, control_values, work_wires): """Handles PauliX-based controlled operations.""" op_map = { @@ -361,6 +355,7 @@ def _handle_pauli_x_based_controlled_ops( wires=control + op.wires, control_values=control_values, work_wires=work_wires ) + work_wires = work_wires or [] return qml.MultiControlledX( wires=control + op.wires, control_values=control_values + op.control_values, diff --git a/pennylane/ops/op_math/controlled_ops.py b/pennylane/ops/op_math/controlled_ops.py index a454f9fa170..5a4ecdaf8b1 100644 --- a/pennylane/ops/op_math/controlled_ops.py +++ b/pennylane/ops/op_math/controlled_ops.py @@ -1262,7 +1262,7 @@ def matrix(self, wire_order=None): # pylint: disable=unused-argument, arguments-differ @staticmethod def compute_decomposition( - wires: WiresLike, work_wires: WiresLike, control_values=None, **kwargs + wires: WiresLike = None, work_wires: WiresLike = None, control_values=None, **kwargs ): r"""Representation of the operator as a product of other operators (static method). @@ -1283,7 +1283,7 @@ def compute_decomposition( **Example:** >>> print(qml.MultiControlledX.compute_decomposition( - ... wires=[0,1,2,3], control_values=[1,1,1], work_wires="aux")) + ... wires=[0,1,2,3], control_values=[1,1,1], work_wires=qml.wires.Wires("aux"))) [Toffoli(wires=[2, 'aux', 3]), Toffoli(wires=[0, 1, 'aux']), Toffoli(wires=[2, 'aux', 3]), @@ -1291,7 +1291,6 @@ def compute_decomposition( """ wires = Wires(() if wires is None else wires) - work_wires = Wires(() if work_wires is None else work_wires) if len(wires) < 2: raise ValueError(f"Wrong number of wires. {len(wires)} given. Need at least 2.") @@ -1302,6 +1301,8 @@ def compute_decomposition( if control_values is None: control_values = [True] * len(control_wires) + work_wires = work_wires or [] + flips1 = [qml.X(w) for w, val in zip(control_wires, control_values) if not val] decomp = decompose_mcx(control_wires, target_wire, work_wires) From 3ab6174234681f1a5ea11c9c48e2b204029d63de Mon Sep 17 00:00:00 2001 From: Andrija Paurevic <46359773+andrijapau@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:27:54 -0500 Subject: [PATCH 42/46] Update pennylane/ops/meta.py Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com> --- pennylane/ops/meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 3de2d2e5dbb..653a5fe62e8 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -120,8 +120,8 @@ class WireCut(Operation): num_wires = AnyWires grad_method = None - def __init__(self, *params, wires: WiresLike = None, id=None): - if wires == []: + def __init__(self, *params, wires: WiresLike = (), id=None): + if len(qml.wires.Wires(wires)) == 0: raise ValueError( f"{self.__class__.__name__}: wrong number of wires. " f"At least one wire has to be given." From 49336ae05fa6f06597d2c0e5a22d5950ee2d7ae0 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 21:33:58 -0500 Subject: [PATCH 43/46] Revert "Update pennylane/ops/meta.py" This reverts commit 3ab6174234681f1a5ea11c9c48e2b204029d63de. --- pennylane/ops/meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 653a5fe62e8..3de2d2e5dbb 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -120,8 +120,8 @@ class WireCut(Operation): num_wires = AnyWires grad_method = None - def __init__(self, *params, wires: WiresLike = (), id=None): - if len(qml.wires.Wires(wires)) == 0: + def __init__(self, *params, wires: WiresLike = None, id=None): + if wires == []: raise ValueError( f"{self.__class__.__name__}: wrong number of wires. " f"At least one wire has to be given." From 6455bfb8ad8daee396b5996584ca78236980c2d1 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Thu, 19 Dec 2024 21:42:01 -0500 Subject: [PATCH 44/46] fix: Update qft.py to not need n_wires --- pennylane/templates/subroutines/qft.py | 16 ++++++---------- tests/templates/test_subroutines/test_qft.py | 5 ----- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/pennylane/templates/subroutines/qft.py b/pennylane/templates/subroutines/qft.py index 0c9730a29e5..7be360f05d1 100644 --- a/pennylane/templates/subroutines/qft.py +++ b/pennylane/templates/subroutines/qft.py @@ -144,15 +144,16 @@ def _flatten(self): def num_params(self): return 0 + def decomposition(self): + return self.compute_decomposition(wires=self.wires) + @staticmethod @functools.lru_cache() def compute_matrix(n_wires): # pylint: disable=arguments-differ return np.fft.ifft(np.eye(2**n_wires), norm="ortho") @staticmethod - def compute_decomposition( - wires: WiresLike, n_wires=None - ): # pylint: disable=arguments-differ,unused-argument + def compute_decomposition(wires: WiresLike): # pylint: disable=arguments-differ,unused-argument r"""Representation of the operator as a product of other operators (static method). .. math:: O = O_1 O_2 \dots O_n. @@ -162,14 +163,13 @@ def compute_decomposition( Args: wires (Iterable, Wires): wires that the operator acts on - n_wires (int): number of wires or ``len(wires)`` Returns: list[Operator]: decomposition of the operator **Example:** - >>> qml.QFT.compute_decomposition(wires=(0,1,2), n_wires=3) + >>> qml.QFT.compute_decomposition(wires=(0,1,2)) [H(0), ControlledPhaseShift(1.5707963267948966, wires=Wires([1, 0])), ControlledPhaseShift(0.7853981633974483, wires=Wires([2, 0])), @@ -180,11 +180,7 @@ def compute_decomposition( """ wires = Wires(wires) - if n_wires is None: - n_wires = len(wires) - else: - if len(wires) != n_wires: - raise ValueError("`n_wires` does not match length of `wires`.") + n_wires = len(wires) shifts = [2 * np.pi * 2**-i for i in range(2, n_wires + 1)] diff --git a/tests/templates/test_subroutines/test_qft.py b/tests/templates/test_subroutines/test_qft.py index 37fe473e3b6..1716476fddd 100644 --- a/tests/templates/test_subroutines/test_qft.py +++ b/tests/templates/test_subroutines/test_qft.py @@ -37,11 +37,6 @@ def test_QFT(self): exp = QFT assert np.allclose(res, exp) - def test_QFT_compute_decomposition_error(self): - """Test that an error is raised for incorrect n_wires""" - with pytest.raises(ValueError, match="`n_wires` does not match length of `wires`."): - qml.QFT.compute_decomposition(wires=[0, 1], n_wires=1) - @pytest.mark.parametrize("n_qubits", range(2, 6)) def test_QFT_compute_decomposition(self, n_qubits): """Test if the QFT operation is correctly decomposed""" From 0c9d0dc4ffe35e412f7f42955d5b940efdac8176 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Fri, 20 Dec 2024 10:58:03 -0500 Subject: [PATCH 45/46] fix: Update WireCut __init__ in meta.py --- pennylane/ops/meta.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pennylane/ops/meta.py b/pennylane/ops/meta.py index 3de2d2e5dbb..39405982ec8 100644 --- a/pennylane/ops/meta.py +++ b/pennylane/ops/meta.py @@ -120,13 +120,9 @@ class WireCut(Operation): num_wires = AnyWires grad_method = None - def __init__(self, *params, wires: WiresLike = None, id=None): - if wires == []: - raise ValueError( - f"{self.__class__.__name__}: wrong number of wires. " - f"At least one wire has to be given." - ) - super().__init__(*params, wires=wires, id=id) + def __init__(self, wires: WiresLike = (), id=None): + wires = Wires(wires) + super().__init__(wires=wires, id=id) @staticmethod def compute_decomposition(wires: WiresLike): # pylint: disable=unused-argument From 7c3a7d9cbfff33ffe00c681c1c69f789ede3e311 Mon Sep 17 00:00:00 2001 From: andrijapau Date: Fri, 20 Dec 2024 12:38:07 -0500 Subject: [PATCH 46/46] doc: Update changelog-dev.md --- doc/releases/changelog-dev.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index edd92247fb4..fcaf0e877d1 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -341,6 +341,9 @@ such as `shots`, `rng` and `prng_key`.

Other Improvements

+* `Wires` object usage across Pennylane source code has been tidied up. + [(#6689)](https://github.com/PennyLaneAI/pennylane/pull/6689) + * `qml.equal` now supports `PauliWord` and `PauliSentence` instances. [(#6703)](https://github.com/PennyLaneAI/pennylane/pull/6703)