diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index ad48d2cbf1c..d68930812d3 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -295,6 +295,9 @@ * `pennylane.collections`, `pennylane.op_sum`, and `pennylane.utils.sparse_hamiltonian` are removed. +* `Operator.data` now returns a `tuple` instead of a `list`. + [(#4222)](https://github.com/PennyLaneAI/pennylane/pull/4222) +

Deprecations 👋

* `LieAlgebraOptimizer` is renamed. Please use `RiemannianGradientOptimizer` instead. diff --git a/pennylane/operation.py b/pennylane/operation.py index 78a1e4cc9a6..6a3919dc9d7 100644 --- a/pennylane/operation.py +++ b/pennylane/operation.py @@ -660,7 +660,7 @@ def compute_decomposition(theta, wires): def __copy__(self): cls = self.__class__ copied_op = cls.__new__(cls) - copied_op.data = self.data.copy() + copied_op.data = copy.copy(self.data) for attr, value in vars(self).items(): if attr != "data": setattr(copied_op, attr, value) @@ -680,7 +680,7 @@ def __deepcopy__(self, memo): # Shallow copy the list of parameters. We avoid a deep copy # here, since PyTorch does not support deep copying of tensors # within a differentiable computation. - copied_op.data = value.copy() + copied_op.data = copy.copy(value) else: # Deep copy everything else. setattr(copied_op, attribute, copy.deepcopy(value, memo)) @@ -1024,7 +1024,7 @@ def __init__(self, *params, wires=None, do_queue=None, id=None): self._check_batching(params) - self.data = [np.array(p) if isinstance(p, (list, tuple)) else p for p in params] + self.data = tuple(np.array(p) if isinstance(p, (list, tuple)) else p for p in params) if do_queue is not None: do_queue_deprecation_warning = ( @@ -1174,7 +1174,7 @@ def wires(self): @property def parameters(self): """Trainable parameters that the operator depends on.""" - return self.data.copy() + return list(self.data) @property def hyperparameters(self): @@ -2058,9 +2058,9 @@ def data(self): """Raw parameters of all constituent observables in the tensor product. Returns: - list[Any]: flattened list containing all dependent parameters + tuple[Any]: flattened list containing all dependent parameters """ - return sum((o.data for o in self.obs), []) + return tuple(d for op in self.obs for d in op.data) @data.setter def data(self, new_data): @@ -2081,8 +2081,14 @@ def data(self, new_data): [array([[5., 0.], [0., 5.]])] """ - for new_entry, op in zip(new_data, self.obs): - op.data = new_entry + if isinstance(new_data, tuple): + start = 0 + for op in self.obs: + op.data = new_data[start : start + len(op.data)] + start += len(op.data) + else: + for new_entry, op in zip(new_data, self.obs): + op.data = tuple(new_entry) @property def num_params(self): diff --git a/pennylane/ops/op_math/adjoint.py b/pennylane/ops/op_math/adjoint.py index f61987cc220..85edd82545a 100644 --- a/pennylane/ops/op_math/adjoint.py +++ b/pennylane/ops/op_math/adjoint.py @@ -175,7 +175,7 @@ class Adjoint(SymbolicOp): >>> qml.generator(Adjoint(qml.RX(1.0, wires=0))) (PauliX(wires=[0]), 0.5) >>> Adjoint(qml.RX(1.234, wires=0)).data - [1.234] + (1.234,) .. details:: :title: Developer Details diff --git a/pennylane/ops/op_math/composite.py b/pennylane/ops/op_math/composite.py index eb54934d7c7..2535b9a59f1 100644 --- a/pennylane/ops/op_math/composite.py +++ b/pennylane/ops/op_math/composite.py @@ -18,6 +18,7 @@ import abc from typing import Callable, List import warnings +import copy import numpy as np @@ -122,7 +123,7 @@ def _op_symbol(self) -> str: @property def data(self): """Create data property""" - return [d for op in self for d in op.data] + return tuple(d for op in self for d in op.data) @data.setter def data(self, new_data): @@ -351,7 +352,7 @@ def map_wires(self, wire_map: dict): new_op = cls.__new__(cls) new_op.operands = tuple(op.map_wires(wire_map=wire_map) for op in self) new_op._wires = Wires([wire_map.get(wire, wire) for wire in self.wires]) - new_op.data = self.data.copy() + new_op.data = copy.copy(self.data) for attr, value in vars(self).items(): if attr not in {"data", "operands", "_wires"}: setattr(new_op, attr, value) diff --git a/pennylane/ops/op_math/controlled.py b/pennylane/ops/op_math/controlled.py index 0715e2b76d3..3a83cf4b0bd 100644 --- a/pennylane/ops/op_math/controlled.py +++ b/pennylane/ops/op_math/controlled.py @@ -178,7 +178,7 @@ class Controlled(SymbolicOp): >>> op.base RX(1.234, wires=[1]) >>> op.data - [1.234] + (1.234,) >>> op.wires >>> op.control_wires diff --git a/pennylane/ops/op_math/evolution.py b/pennylane/ops/op_math/evolution.py index cbc67bee349..9b30ec3a9ab 100644 --- a/pennylane/ops/op_math/evolution.py +++ b/pennylane/ops/op_math/evolution.py @@ -85,7 +85,7 @@ def __init__(self, generator, param=1, num_steps=None, do_queue=None, id=None): super().__init__( generator, coeff=-1j * param, num_steps=num_steps, do_queue=do_queue, id=id ) - self._data = [param] + self._data = (param,) def __repr__(self): return ( diff --git a/pennylane/ops/op_math/symbolicop.py b/pennylane/ops/op_math/symbolicop.py index 2d5575445f8..dafedf0d67c 100644 --- a/pennylane/ops/op_math/symbolicop.py +++ b/pennylane/ops/op_math/symbolicop.py @@ -186,7 +186,7 @@ def batch_size(self): @property def data(self): - return [self.scalar, *self.base.data] + return (self.scalar, *self.base.data) @data.setter def data(self, new_data): diff --git a/pennylane/ops/qubit/hamiltonian.py b/pennylane/ops/qubit/hamiltonian.py index 39f23f35b95..e59aadb3d73 100644 --- a/pennylane/ops/qubit/hamiltonian.py +++ b/pennylane/ops/qubit/hamiltonian.py @@ -269,7 +269,7 @@ def terms(self): >>> t[0] [, ] """ - return self.data, self.ops + return self.parameters, self.ops @property def wires(self): @@ -475,7 +475,7 @@ def simplify(self): # hotfix: We `self.data`, since `self.parameters` returns a copy of the data and is now returned in # self.terms(). To be improved soon. - self.data = new_coeffs + self.data = tuple(new_coeffs) # hotfix: We overwrite the hyperparameter entry, which is now returned in self.terms(). # To be improved soon. self.hyperparameters["ops"] = new_ops @@ -752,7 +752,7 @@ def map_wires(self, wire_map: dict): """ cls = self.__class__ new_op = cls.__new__(cls) - new_op.data = self.data.copy() + new_op.data = copy(self.data) new_op._wires = Wires( # pylint: disable=protected-access [wire_map.get(wire, wire) for wire in self.wires] ) diff --git a/pennylane/optimize/adaptive.py b/pennylane/optimize/adaptive.py index 4676c9fe666..fefb9e2f375 100644 --- a/pennylane/optimize/adaptive.py +++ b/pennylane/optimize/adaptive.py @@ -33,7 +33,8 @@ def append_gate(tape, params, gates): for i, g in enumerate(gates): g = copy.copy(g) - g.data[0] = params[i] + new_params = (params[i], *g.data[1:]) + g.data = new_params qml.apply(g) for m in tape.measurements: diff --git a/pennylane/tape/qscript.py b/pennylane/tape/qscript.py index a0dbb9b8829..eccb8d3c95b 100644 --- a/pennylane/tape/qscript.py +++ b/pennylane/tape/qscript.py @@ -729,10 +729,20 @@ def set_parameters(self, params, trainable_only=True): if len(params) != required_length: raise ValueError("Number of provided parameters does not match.") + op_data = [] + for pinfo in self._par_info: + if pinfo["p_idx"] == 0: + op_data.append((pinfo["op"], list(pinfo["op"].data))) + else: + op_data.append(op_data[-1]) + for idx, p in iterator: - op = self._par_info[idx]["op"] - op.data[self._par_info[idx]["p_idx"]] = p + op_data[idx][1][self._par_info[idx]["p_idx"]] = p + + for op, d in op_data: + op.data = tuple(d) op._check_batching(op.data) + self._update_batch_size() self._update_output_dim() diff --git a/tests/gradients/parameter_shift/test_parameter_shift_cv.py b/tests/gradients/parameter_shift/test_parameter_shift_cv.py index abc46de23b5..b5e9e213db6 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift_cv.py +++ b/tests/gradients/parameter_shift/test_parameter_shift_cv.py @@ -444,7 +444,7 @@ def _mock_transform_observable(obs, Z, device_wires): # pylint: disable=unused- transformed_obs.parameters[0]`` the condition ``len(A.nonzero()[0]) == 1 and A.ndim == 2 and A[0, 0] != 0`` is ``True``.""" iden = qml.Identity(0) - iden.data = [np.array([[1, 0], [0, 0]])] + iden.data = (np.array([[1, 0], [0, 0]]),) return iden monkeypatch.setattr( diff --git a/tests/legacy/test_hamiltonian_expand_old.py b/tests/legacy/test_hamiltonian_expand_old.py index 7d2210e9a92..db96ba3e1fc 100644 --- a/tests/legacy/test_hamiltonian_expand_old.py +++ b/tests/legacy/test_hamiltonian_expand_old.py @@ -473,8 +473,8 @@ def test_sum_dif_autograd(self, tol): 3.50307411e-01, -3.41123470e-01, 0.0, - 0.0, - 0.0, + -4.36578753e-01, + 6.41233474e-01, ] with AnnotatedQueue() as q: @@ -567,8 +567,8 @@ def test_sum_dif_jax(self, tol): 3.50307411e-01, -3.41123470e-01, 0.0, - 0.0, - 0.0, + -4.36578753e-01, + 6.41233474e-01, ] with AnnotatedQueue() as q: diff --git a/tests/legacy/test_metric_tensor_old.py b/tests/legacy/test_metric_tensor_old.py index 5b2fc8bbaaf..73294757ea8 100644 --- a/tests/legacy/test_metric_tensor_old.py +++ b/tests/legacy/test_metric_tensor_old.py @@ -46,7 +46,7 @@ def test_rot_decomposition(self, diff_method): # Second parameter subcircuit assert len(tapes[1].operations) == 4 assert isinstance(tapes[1].operations[0], qml.RZ) - assert tapes[1].operations[0].data == [1] + assert tapes[1].operations[0].data == (1,) # PauliY decomp assert isinstance(tapes[1].operations[1], qml.PauliZ) assert isinstance(tapes[1].operations[2], qml.S) @@ -56,8 +56,8 @@ def test_rot_decomposition(self, diff_method): assert len(tapes[2].operations) == 2 assert isinstance(tapes[2].operations[0], qml.RZ) assert isinstance(tapes[2].operations[1], qml.RY) - assert tapes[2].operations[0].data == [1] - assert tapes[2].operations[1].data == [2] + assert tapes[2].operations[0].data == (1,) + assert tapes[2].operations[1].data == (2,) @pytest.mark.parametrize("diff_method", ["parameter-shift", "backprop"]) def test_multirz_decomposition(self, diff_method): diff --git a/tests/legacy/test_qscript_old.py b/tests/legacy/test_qscript_old.py index d566b29ba11..847afda0661 100644 --- a/tests/legacy/test_qscript_old.py +++ b/tests/legacy/test_qscript_old.py @@ -545,7 +545,6 @@ def test_shallow_copy_with_operations(self, copy_fn): # however, the underlying operation data *is still shared* assert copied_qs.operations[0].wires is qs.operations[0].wires # the data list is copied, but the elements of the list remain th same - assert copied_qs.operations[0].data is not qs.operations[0].data assert copied_qs.operations[0].data[0] is qs.operations[0].data[0] assert qs.get_parameters() == copied_qs.get_parameters() diff --git a/tests/ops/op_math/test_adjoint.py b/tests/ops/op_math/test_adjoint.py index cee37e600dd..58a9e1ac36b 100644 --- a/tests/ops/op_math/test_adjoint.py +++ b/tests/ops/op_math/test_adjoint.py @@ -108,7 +108,7 @@ def test_nonparametric_ops(self): assert op.num_params == 0 assert op.parameters == [] - assert op.data == [] + assert op.data == () assert op.wires == qml.wires.Wires("a") @@ -176,18 +176,18 @@ def test_data(self): base = qml.RX(x, wires="a") adj = Adjoint(base) - assert adj.data == [x] + assert adj.data == (x,) # update parameters through adjoint x_new = np.array(2.3456) - adj.data = [x_new] - assert base.data == [x_new] - assert adj.data == [x_new] + adj.data = (x_new,) + assert base.data == (x_new,) + assert adj.data == (x_new,) # update base data updates Adjoint data x_new2 = np.array(3.456) - base.data = [x_new2] - assert adj.data == [x_new2] + base.data = (x_new2,) + assert adj.data == (x_new2,) def test_has_matrix_true(self): """Test `has_matrix` property carries over when base op defines matrix.""" @@ -866,7 +866,7 @@ def test_adjoint_single_op_function(self): assert out == tape[0] assert isinstance(out, Adjoint) assert out.base.__class__ is qml.RX - assert out.data == [1.234] + assert out.data == (1.234,) assert out.wires == qml.wires.Wires("a") def test_adjoint_template(self): @@ -908,9 +908,9 @@ def func(x, y, z): assert tape[2].base.__class__ is qml.RX # check parameters assigned correctly - assert tape[0].data == [z] - assert tape[1].data == [y] - assert tape[2].data == [x] + assert tape[0].data == (z,) + assert tape[1].data == (y,) + assert tape[2].data == (x,) def test_nested_adjoint(self): """Test the adjoint transform on an adjoint transform.""" @@ -923,7 +923,7 @@ def test_nested_adjoint(self): assert isinstance(out, Adjoint) assert isinstance(out.base, Adjoint) assert out.base.base.__class__ is qml.RX - assert out.data == [x] + assert out.data == (x,) assert out.wires == qml.wires.Wires("b") @@ -942,7 +942,7 @@ def test_single_decomposeable_op(self): assert q.queue[0] is out assert isinstance(out, qml.RX) - assert out.data == [-1.23] + assert out.data == (-1.23,) def test_single_nondecomposable_op(self): """Test lazy=false for a single op that can't be decomposed.""" @@ -966,7 +966,7 @@ def test_single_decomposable_op_function(self): assert out is tape[0] assert not isinstance(out, Adjoint) assert isinstance(out, qml.RX) - assert out.data == [-x] + assert out.data == (-x,) def test_single_nondecomposable_op_function(self): """Test lazy=False for a single op function that can't be decomposed.""" @@ -1009,7 +1009,7 @@ def test_single_op(self): assert isinstance(out, Adjoint) assert out.base.__class__ is qml.RZ - assert out.data == [1.234] + assert out.data == (1.234,) assert out.wires == qml.wires.Wires(0) def test_single_op_eager(self): @@ -1020,7 +1020,7 @@ def test_single_op_eager(self): out = adjoint(base, lazy=False) assert isinstance(out, qml.RX) - assert out.data == [-x] + assert out.data == (-x,) def test_observable(self): """Test providing a preconstructed Observable outside of a queuing context.""" @@ -1039,7 +1039,7 @@ def test_single_op_function(self): assert isinstance(out, Adjoint) assert out.base.__class__ is qml.IsingXX - assert out.data == [1.234] + assert out.data == (1.234,) assert out.wires == qml.wires.Wires((0, 1)) def test_function(self): diff --git a/tests/ops/op_math/test_composite.py b/tests/ops/op_math/test_composite.py index d94089e1652..623150bc5e5 100644 --- a/tests/ops/op_math/test_composite.py +++ b/tests/ops/op_math/test_composite.py @@ -101,14 +101,14 @@ def test_parameters(self): def test_data(self): """Test that data is initialized correctly.""" op = ValidOp(qml.RX(9.87, wires=0), qml.Rot(1.23, 4.0, 5.67, wires=1), qml.PauliX(0)) - assert op.data == [9.87, 1.23, 4.0, 5.67] + assert op.data == (9.87, 1.23, 4.0, 5.67) def test_data_setter(self): """Test the setter method for data""" op = ValidOp(qml.RX(9.87, wires=0), qml.Rot(1.23, 4.0, 5.67, wires=1), qml.PauliX(0)) - assert op.data == [9.87, 1.23, 4.0, 5.67] + assert op.data == (9.87, 1.23, 4.0, 5.67) - new_data = [1.23, 0.0, -1.0, -2.0] + new_data = (1.23, 0.0, -1.0, -2.0) op.data = new_data # pylint:disable=attribute-defined-outside-init assert op.data == new_data diff --git a/tests/ops/op_math/test_controlled.py b/tests/ops/op_math/test_controlled.py index f1fcefb2b38..c851ea6d93c 100644 --- a/tests/ops/op_math/test_controlled.py +++ b/tests/ops/op_math/test_controlled.py @@ -148,7 +148,7 @@ def test_nonparametric_ops(self): assert op.num_params == 0 assert op.parameters == [] - assert op.data == [] + assert op.data == () assert op.num_wires == 4 @@ -207,16 +207,16 @@ def test_data(self): base = qml.RX(x, wires="a") op = Controlled(base, (0, 1)) - assert op.data == [x] + assert op.data == (x,) - x_new = np.array(2.3454) + x_new = (np.array(2.3454),) op.data = x_new - assert op.data == [x_new] - assert base.data == [x_new] + assert op.data == (x_new,) + assert base.data == (x_new,) - x_new2 = np.array(3.456) + x_new2 = (np.array(3.456),) base.data = x_new2 - assert op.data == [x_new2] + assert op.data == (x_new2,) assert op.parameters == [x_new2] @pytest.mark.parametrize( @@ -386,10 +386,10 @@ def test_copy(self): assert copied_op.__class__ is op.__class__ assert copied_op.control_wires == op.control_wires assert copied_op.control_values == op.control_values - assert copied_op.data == [param1] + assert copied_op.data == (param1,) - copied_op.data = [6.54] - assert op.data == [param1] + copied_op.data = (6.54,) + assert op.data == (param1,) def test_label(self): """Test that the label method defers to the label of the base.""" @@ -450,7 +450,7 @@ def test_generator(self): for wire, ob in zip(op.control_wires, gen_tensor.operands): assert isinstance(ob, qml.Projector) - assert ob.data == [[1]] + assert ob.data == ([1],) assert ob.wires == qml.wires.Wires(wire) assert gen_tensor.operands[-1].__class__ is base_gen.__class__ diff --git a/tests/ops/op_math/test_evolution.py b/tests/ops/op_math/test_evolution.py index 42afa745f64..f707be56f7f 100644 --- a/tests/ops/op_math/test_evolution.py +++ b/tests/ops/op_math/test_evolution.py @@ -36,7 +36,7 @@ def test_initialization(self): assert op.num_params == 1 assert op.parameters == [param] - assert op.data == [param] + assert op.data == (param,) assert op.wires == qml.wires.Wires(("b", "c")) @@ -79,14 +79,14 @@ def test_data(self): base = qml.PauliX(0) op = Evolution(base, param) - assert op.data == [param] + assert op.data == (param,) assert op.coeff == -1j * op.data[0] assert op.param == op.data[0] new_param = np.array(2.345) - op.data = [new_param] + op.data = (new_param,) - assert op.data == [new_param] + assert op.data == (new_param,) assert op.coeff == -1j * op.data[0] assert op.data == op.data[0] diff --git a/tests/ops/op_math/test_exp.py b/tests/ops/op_math/test_exp.py index 5579adcb3fb..6e0c8c5606d 100644 --- a/tests/ops/op_math/test_exp.py +++ b/tests/ops/op_math/test_exp.py @@ -44,7 +44,7 @@ def test_pauli_base(self, constructor): assert op.num_params == 1 assert op.parameters == [1] - assert op.data == [1] + assert op.data == (1,) assert op.wires == qml.wires.Wires("a") @@ -63,7 +63,7 @@ def test_provided_coeff(self, constructor): assert op.num_params == 1 assert op.parameters == [coeff] - assert op.data == [coeff] + assert op.data == (coeff,) assert op.wires == qml.wires.Wires(("b", "c")) @@ -81,7 +81,7 @@ def test_parametric_base(self, constructor): assert op.name == "Exp" assert op.num_params == 2 - assert op.data == [coeff, base_coeff] + assert op.data == (coeff, base_coeff) assert op.wires == qml.wires.Wires(5) @@ -110,14 +110,14 @@ def test_data(self): base = qml.RX(phi, wires=0) op = Exp(base, coeff) - assert op.data == [coeff, phi] + assert op.data == (coeff, phi) new_phi = np.array(0.1234) new_coeff = np.array(3.456) - op.data = [new_coeff, new_phi] + op.data = (new_coeff, new_phi) - assert op.data == [new_coeff, new_phi] - assert op.base.data == [new_phi] + assert op.data == (new_coeff, new_phi) + assert op.base.data == (new_phi,) assert op.scalar == new_coeff # pylint: disable=protected-access diff --git a/tests/ops/op_math/test_pow_op.py b/tests/ops/op_math/test_pow_op.py index 7aa214cd611..ee951011e70 100644 --- a/tests/ops/op_math/test_pow_op.py +++ b/tests/ops/op_math/test_pow_op.py @@ -186,7 +186,7 @@ def test_nonparametric_ops(self, power_method): assert op.num_params == 0 assert op.parameters == [] - assert op.data == [] + assert op.data == () assert op.wires == qml.wires.Wires("a") assert op.num_wires == 1 @@ -266,18 +266,18 @@ def test_data(self, power_method): base = qml.RX(x, wires="a") op: Pow = power_method(base=base, z=3.21) - assert op.data == [x] + assert op.data == (x,) # update parameters through pow x_new = np.array(2.3456) - op.data = [x_new] - assert base.data == [x_new] - assert op.data == [x_new] + op.data = (x_new,) + assert base.data == (x_new,) + assert op.data == (x_new,) # update base data updates pow data x_new2 = np.array(3.456) - base.data = [x_new2] - assert op.data == [x_new2] + base.data = (x_new2,) + assert op.data == (x_new2,) def test_has_matrix_true(self, power_method): """Test `has_matrix` property carries over when base op defines matrix.""" @@ -503,10 +503,10 @@ def test_copy(self): assert copied_op.__class__ is op.__class__ assert copied_op.z == op.z - assert copied_op.data == [param1] + assert copied_op.data == (param1,) - copied_op.data = [6.54] - assert op.data == [param1] + copied_op.data = (6.54,) + assert op.data == (param1,) def test_label(self): """Test that the label draws the exponent as superscript.""" diff --git a/tests/ops/op_math/test_prod.py b/tests/ops/op_math/test_prod.py index 84eb02f1db8..35220e12c40 100644 --- a/tests/ops/op_math/test_prod.py +++ b/tests/ops/op_math/test_prod.py @@ -130,7 +130,7 @@ def test_init_prod_op(self, id): assert prod_op.id == id assert prod_op.queue_idx is None - assert prod_op.data == [0.23] + assert prod_op.data == (0.23,) assert prod_op.parameters == [0.23] assert prod_op.num_params == 1 diff --git a/tests/ops/op_math/test_sprod.py b/tests/ops/op_math/test_sprod.py index 6688e24a2a2..37b80067222 100644 --- a/tests/ops/op_math/test_sprod.py +++ b/tests/ops/op_math/test_sprod.py @@ -112,7 +112,7 @@ def test_init_sprod_op(self, test_id): assert sprod_op.id == test_id assert sprod_op.queue_idx is None - assert sprod_op.data == [3.14, 0.23] + assert sprod_op.data == (3.14, 0.23) assert sprod_op.parameters == [3.14, 0.23] assert sprod_op.num_params == 2 @@ -122,17 +122,17 @@ def test_parameters(self): def test_data(self): sprod_op = s_prod(9.87, qml.Rot(1.23, 4.0, 5.67, wires=1)) - assert sprod_op.data == [9.87, 1.23, 4.0, 5.67] + assert sprod_op.data == (9.87, 1.23, 4.0, 5.67) def test_data_setter(self): """Test the setter method for data""" scalar, angles = (9.87, (1.23, 4.0, 5.67)) - old_data = [9.87, 1.23, 4.0, 5.67] + old_data = (9.87, 1.23, 4.0, 5.67) sprod_op = s_prod(scalar, qml.Rot(*angles, wires=1)) assert sprod_op.data == old_data - new_data = [1.23, 0.0, -1.0, -2.0] + new_data = (1.23, 0.0, -1.0, -2.0) sprod_op.data = new_data assert sprod_op.data == new_data assert sprod_op.scalar == new_data[0] @@ -141,20 +141,20 @@ def test_data_setter(self): def test_data_setter_shallow(self): """Test the setter method for data with a non-parametric base op.""" op = s_prod(0.1, qml.PauliX(0)) - op.data = [0.2] - assert op.data == [0.2] == [op.scalar] + op.data = (0.2,) + assert op.data == (0.2,) == (op.scalar,) def test_data_setter_deep(self): """Test the setter method for data with a deep base operator.""" op = s_prod(0.1, qml.sum(qml.PauliX(0), qml.prod(qml.PauliY(0), qml.RX(0.2, 1)))) - assert op.data == [0.1, 0.2] + assert op.data == (0.1, 0.2) - new_data = [0.3, 0.4] + new_data = (0.3, 0.4) op.data = new_data assert op.data == new_data assert op.scalar == 0.3 - assert op.base[1].data == [0.4] - assert op.base[1][1].data == [0.4] + assert op.base[1].data == (0.4,) + assert op.base[1][1].data == (0.4,) @pytest.mark.parametrize("scalar, op", ops) def test_terms(self, op, scalar): @@ -208,9 +208,6 @@ def test_copy(self, op_scalar_tup): assert sprod_op.base.name == copied_op.base.name assert sprod_op.base.wires == copied_op.base.wires assert sprod_op.base.data == copied_op.base.data - assert ( - sprod_op.base.data is not copied_op.base.data - ) # we want different object with same content def test_has_matrix_true_via_factor_has_matrix(self): """Test that a scalar product with an operator that has `has_matrix=True` diff --git a/tests/ops/op_math/test_sum.py b/tests/ops/op_math/test_sum.py index 3eeac1fe593..7c009a62e47 100644 --- a/tests/ops/op_math/test_sum.py +++ b/tests/ops/op_math/test_sum.py @@ -126,7 +126,7 @@ def test_init_sum_op(self, id, sum_method): if sum_method.__name__ == sum.__name__: assert sum_op.id == id - assert sum_op.data == [0.23] + assert sum_op.data == (0.23,) assert sum_op.parameters == [0.23] assert sum_op.num_params == 1 @@ -142,7 +142,7 @@ def test_init_sum_op_with_sum_summands(self, sum_method): assert sum_op.name == "Sum" assert sum_op.id is None - assert sum_op.data == [0.23, 9.87] + assert sum_op.data == (0.23, 9.87) assert sum_op.parameters == [0.23, 9.87] assert sum_op.num_params == 2 diff --git a/tests/ops/op_math/test_symbolic_op.py b/tests/ops/op_math/test_symbolic_op.py index ee3c7a0bfa0..04ae2cddea5 100644 --- a/tests/ops/op_math/test_symbolic_op.py +++ b/tests/ops/op_math/test_symbolic_op.py @@ -66,10 +66,10 @@ def test_copy(): copied_op = copy(op) assert copied_op.__class__ is op.__class__ - assert copied_op.data == [param1] + assert copied_op.data == (param1,) - copied_op.data = [6.54] - assert op.data == [param1] + copied_op.data = (6.54,) + assert op.data == (param1,) def test_map_wires(): @@ -101,18 +101,18 @@ def test_data(self): base = Operator(x, "a") op = SymbolicOp(base) - assert op.data == [x] + assert op.data == (x,) # update parameters through op x_new = np.array(2.345) - op.data = [x_new] - assert base.data == [x_new] - assert op.data == [x_new] + op.data = (x_new,) + assert base.data == (x_new,) + assert op.data == (x_new,) # update base data updates symbolic data x_new2 = np.array(3.45) - base.data = [x_new2] - assert op.data == [x_new2] + base.data = (x_new2,) + assert op.data == (x_new2,) def test_parameters(self): """Test parameter property is a list of the base's trainable parameters.""" @@ -232,7 +232,7 @@ def test_init(self): op = TempScalar(base, scalar) assert isinstance(op.scalar, float) assert op.scalar == 2.2 - assert op.data == [2.2, 1.1] + assert op.data == (2.2, 1.1) base = Operator(1.1, wires=[0]) scalar = [2.2, 3.3] @@ -246,19 +246,19 @@ def test_data(self): """Tests the data property.""" op = TempScalar(Operator(1.1, wires=[0]), 2.2) assert op.scalar == 2.2 - assert op.data == [2.2, 1.1] + assert op.data == (2.2, 1.1) # check setting through ScalarSymbolicOp - op.data = [3.3, 4.4] # pylint:disable=attribute-defined-outside-init - assert op.data == [3.3, 4.4] + op.data = (3.3, 4.4) # pylint:disable=attribute-defined-outside-init + assert op.data == (3.3, 4.4) assert op.scalar == 3.3 - assert op.base.data == [4.4] + assert op.base.data == (4.4,) # check setting through base - op.base.data = [5.5] - assert op.data == [3.3, 5.5] + op.base.data = (5.5,) + assert op.data == (3.3, 5.5) assert op.scalar == 3.3 - assert op.base.data == [5.5] + assert op.base.data == (5.5,) def test_hash(self): """Test that a hash correctly identifies ScalarSymbolicOps.""" diff --git a/tests/ops/qubit/test_parametric_ops.py b/tests/ops/qubit/test_parametric_ops.py index 973b5d44a28..fe17dfa4c99 100644 --- a/tests/ops/qubit/test_parametric_ops.py +++ b/tests/ops/qubit/test_parametric_ops.py @@ -3912,14 +3912,14 @@ def test_simplify_rot(self): simplify_rot_x = rot_x.simplify() assert simplify_rot_x.name == "RX" - assert simplify_rot_x.data == [0.1] + assert simplify_rot_x.data == (0.1,) assert np.allclose(simplify_rot_x.matrix(), rot_x.matrix()) rot_y = qml.Rot(0, 0.1, 0, wires=0) simplify_rot_y = rot_y.simplify() assert simplify_rot_y.name == "RY" - assert simplify_rot_y.data == [0.1] + assert simplify_rot_y.data == (0.1,) assert np.allclose(simplify_rot_y.matrix(), rot_y.matrix()) rot_z = qml.Rot(0.1, 0, 0.2, wires=0) @@ -3948,14 +3948,14 @@ def test_simplify_crot(self): simplify_crot_x = crot_x.simplify() assert simplify_crot_x.name == "CRX" - assert simplify_crot_x.data == [0.1] + assert simplify_crot_x.data == (0.1,) assert np.allclose(simplify_crot_x.matrix(), crot_x.matrix()) crot_y = qml.CRot(0, 0.1, 0, wires=[0, 1]) simplify_crot_y = crot_y.simplify() assert simplify_crot_y.name == "CRY" - assert simplify_crot_y.data == [0.1] + assert simplify_crot_y.data == (0.1,) assert np.allclose(simplify_crot_y.matrix(), crot_y.matrix()) crot_z = qml.CRot(0.1, 0, 0.2, wires=[0, 1]) @@ -3978,21 +3978,21 @@ def test_simplify_u2(self): simplify_u2_x = u2_x.simplify() assert simplify_u2_x.name == "RX" - assert simplify_u2_x.data == [np.pi / 2] + assert simplify_u2_x.data == (np.pi / 2,) assert np.allclose(simplify_u2_x.matrix(), u2_x.matrix()) u2_y = qml.U2(-2 * np.pi, 2 * np.pi, wires=0) simplify_u2_y = u2_y.simplify() assert simplify_u2_y.name == "RY" - assert simplify_u2_y.data == [np.pi / 2] + assert simplify_u2_y.data == (np.pi / 2,) assert np.allclose(simplify_u2_y.matrix(), u2_y.matrix()) u2 = qml.U2(0.1, 0.2, wires=0) u2_not_simplified = u2.simplify() assert u2_not_simplified.name == "U2" - assert u2_not_simplified.data == [0.1, 0.2] + assert u2_not_simplified.data == (0.1, 0.2) assert np.allclose(u2_not_simplified.matrix(), u2.matrix()) def test_simplify_u3(self): @@ -4002,28 +4002,28 @@ def test_simplify_u3(self): simplify_u3_x = u3_x.simplify() assert simplify_u3_x.name == "RX" - assert simplify_u3_x.data == [0.1] + assert simplify_u3_x.data == (0.1,) assert np.allclose(simplify_u3_x.matrix(), u3_x.matrix()) u3_y = qml.U3(0.1, 0.0, 0.0, wires=0) simplify_u3_y = u3_y.simplify() assert simplify_u3_y.name == "RY" - assert simplify_u3_y.data == [0.1] + assert simplify_u3_y.data == (0.1,) assert np.allclose(simplify_u3_y.matrix(), u3_y.matrix()) u3_z = qml.U3(0.0, 0.1, 0.0, wires=0) simplify_u3_z = u3_z.simplify() assert simplify_u3_z.name == "PhaseShift" - assert simplify_u3_z.data == [0.1] + assert simplify_u3_z.data == (0.1,) assert np.allclose(simplify_u3_z.matrix(), u3_z.matrix()) u3 = qml.U3(0.1, 0.2, 0.3, wires=0) u3_not_simplified = u3.simplify() assert u3_not_simplified.name == "U3" - assert u3_not_simplified.data == [0.1, 0.2, 0.3] + assert u3_not_simplified.data == (0.1, 0.2, 0.3) assert np.allclose(u3_not_simplified.matrix(), u3.matrix()) diff --git a/tests/tape/test_qscript.py b/tests/tape/test_qscript.py index 2f0b9036b00..8a5e8d36506 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -572,7 +572,6 @@ def test_shallow_copy_with_operations(self, copy_fn): # however, the underlying operation data *is still shared* assert copied_qs.operations[0].wires is qs.operations[0].wires # the data list is copied, but the elements of the list remain th same - assert copied_qs.operations[0].data is not qs.operations[0].data assert copied_qs.operations[0].data[0] is qs.operations[0].data[0] assert qs.get_parameters() == copied_qs.get_parameters() diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index 1d0200c5966..3bb41d0f20c 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -323,7 +323,7 @@ def f(x): assert isinstance(tape.circuit[2], qml.transforms.condition.Conditional) assert isinstance(tape.circuit[2].then_op, qml.RY) assert tape.circuit[2].then_op.wires == target_wire - assert tape.circuit[2].then_op.data == [r] + assert tape.circuit[2].then_op.data == (r,) assert isinstance(tape.circuit[3], qml.transforms.condition.Conditional) assert isinstance(tape.circuit[3].then_op, qml.PauliZ) @@ -770,13 +770,13 @@ def test_setting_parameters(self, make_tape): assert tape.get_parameters() == new_params - new_params = [0.1, -0.2, 1, 5, 0] + new_params = (0.1, -0.2, 1, 5, 0) tape.data = new_params for pinfo, pval in zip(tape._par_info, new_params): assert pinfo["op"].data[pinfo["p_idx"]] == pval - assert tape.get_parameters() == new_params + assert tape.get_parameters() == list(new_params) def test_setting_free_parameters(self, make_tape): """Test that free parameters are correctly modified after construction""" diff --git a/tests/test_operation.py b/tests/test_operation.py index fe841444bd5..92b16c071dc 100644 --- a/tests/test_operation.py +++ b/tests/test_operation.py @@ -235,7 +235,7 @@ class DummyOp(qml.operation.Operator): op = DummyOp(1.234, "a") assert op.wires[0] == "a" - assert op.data == [1.234] + assert op.data == (1.234,) def test_no_wires(self): """Test an error is raised if no wires are passed.""" @@ -1373,7 +1373,7 @@ def test_params(self): X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) - assert t.data == [p] + assert t.data == (p,) def test_data_setter(self): """Test the data setter""" @@ -1381,10 +1381,10 @@ def test_data_setter(self): X = qml.PauliX(0) Y = qml.Hermitian(p, wires=[1, 2]) t = Tensor(X, Y) - assert t.data == [p] + assert t.data == (p,) new_data = np.eye(4) * 6 - t.data = [[], [new_data]] - assert qml.math.allequal(t.data, [new_data]) + t.data = [(), (new_data,)] + assert qml.math.allequal(t.data, (new_data,)) def test_num_params(self): """Test that the correct number of parameters is returned""" diff --git a/tests/transforms/test_condition.py b/tests/transforms/test_condition.py index 369c1c838de..51279f658f8 100644 --- a/tests/transforms/test_condition.py +++ b/tests/transforms/test_condition.py @@ -73,7 +73,7 @@ def f(x): assert isinstance(ops[2], qml.transforms.condition.Conditional) assert isinstance(ops[2].then_op, qml.RY) assert ops[2].then_op.wires == target_wire - assert ops[2].then_op.data == [r] + assert ops[2].then_op.data == (r,) assert isinstance(ops[3], qml.transforms.condition.Conditional) assert isinstance(ops[3].then_op, qml.PauliZ) @@ -135,7 +135,7 @@ def g(x): assert isinstance(ops[2], qml.transforms.condition.Conditional) assert isinstance(ops[2].then_op, qml.RY) assert ops[2].then_op.wires == target_wire - assert ops[2].then_op.data == [r] + assert ops[2].then_op.data == (r,) assert isinstance(ops[3], qml.transforms.condition.Conditional) assert isinstance(ops[3].then_op, qml.PauliZ) @@ -232,7 +232,7 @@ def test_cond_operationss_with_adjoint(self, terminal_measurement): assert isinstance(ops[2], qml.transforms.condition.Conditional) assert isinstance(ops[2].then_op, qml.RX) - assert ops[2].then_op.data == [r] + assert ops[2].then_op.data == (r,) assert ops[2].then_op.wires == target_wire assert len(tape.measurements) == 1 diff --git a/tests/transforms/test_defer_measurements.py b/tests/transforms/test_defer_measurements.py index d2df719e182..c44205dc4a9 100644 --- a/tests/transforms/test_defer_measurements.py +++ b/tests/transforms/test_defer_measurements.py @@ -334,7 +334,7 @@ def test_quantum_teleportation(self, device, rads): op1 = tape.operations[0] assert isinstance(op1, qml.RY) assert op1.wires == qml.wires.Wires(0) - assert op1.data == [rads] + assert op1.data == (rads,) op2 = tape.operations[1] assert isinstance(op2, qml.Hadamard) diff --git a/tests/transforms/test_hamiltonian_expand.py b/tests/transforms/test_hamiltonian_expand.py index 04b59329315..f6a3c16b7bd 100644 --- a/tests/transforms/test_hamiltonian_expand.py +++ b/tests/transforms/test_hamiltonian_expand.py @@ -289,7 +289,6 @@ def test_hamiltonian_dif_tensorflow(self): assert np.isclose(res, output) g = gtape.gradient(res, var) - print(g) assert np.allclose(list(g[0]) + list(g[1]), output2) @@ -505,8 +504,8 @@ def test_sum_dif_autograd(self, tol): 3.50307411e-01, -3.41123470e-01, 0.0, - 0.0, - 0.0, + -4.36578753e-01, + 6.41233474e-01, ] with AnnotatedQueue() as q: @@ -599,8 +598,8 @@ def test_sum_dif_jax(self, tol): 3.50307411e-01, -3.41123470e-01, 0.0, - 0.0, - 0.0, + -4.36578753e-01, + 6.41233474e-01, ] with AnnotatedQueue() as q: diff --git a/tests/transforms/test_metric_tensor.py b/tests/transforms/test_metric_tensor.py index 482038bb8c5..94fa23d973a 100644 --- a/tests/transforms/test_metric_tensor.py +++ b/tests/transforms/test_metric_tensor.py @@ -46,7 +46,7 @@ def test_rot_decomposition(self, diff_method): # Second parameter subcircuit assert len(tapes[1].operations) == 4 assert isinstance(tapes[1].operations[0], qml.RZ) - assert tapes[1].operations[0].data == [1] + assert tapes[1].operations[0].data == (1,) # PauliY decomp assert isinstance(tapes[1].operations[1], qml.PauliZ) assert isinstance(tapes[1].operations[2], qml.S) @@ -56,8 +56,8 @@ def test_rot_decomposition(self, diff_method): assert len(tapes[2].operations) == 2 assert isinstance(tapes[2].operations[0], qml.RZ) assert isinstance(tapes[2].operations[1], qml.RY) - assert tapes[2].operations[0].data == [1] - assert tapes[2].operations[1].data == [2] + assert tapes[2].operations[0].data == (1,) + assert tapes[2].operations[1].data == (2,) @pytest.mark.parametrize("diff_method", ["parameter-shift", "backprop"]) def test_multirz_decomposition(self, diff_method): diff --git a/tests/transforms/test_tape_expand.py b/tests/transforms/test_tape_expand.py index d53856bd096..a56eb694c2c 100644 --- a/tests/transforms/test_tape_expand.py +++ b/tests/transforms/test_tape_expand.py @@ -228,7 +228,7 @@ def generator(self): new_tape = qml.transforms.expand_nonunitary_gen(tape) assert tape.operations[:2] == new_tape.operations[:2] exp_op = new_tape.operations[2] - assert exp_op.name == "RZ" and exp_op.data == [2.1] and exp_op.wires == qml.wires.Wires(1) + assert exp_op.name == "RZ" and exp_op.data == (2.1,) and exp_op.wires == qml.wires.Wires(1) assert tape.operations[3:] == new_tape.operations[3:] def test_expand_nonunitary_generator(self): @@ -246,7 +246,7 @@ def test_expand_nonunitary_generator(self): assert tape.operations[:2] == new_tape.operations[:2] exp_op = new_tape.operations[2] - assert exp_op.name == "RZ" and exp_op.data == [2.1] and exp_op.wires == qml.wires.Wires(1) + assert exp_op.name == "RZ" and exp_op.data == (2.1,) and exp_op.wires == qml.wires.Wires(1) assert tape.operations[3:] == new_tape.operations[3:] def test_decompose_all_nonunitary_generator(self): diff --git a/tests/transforms/test_transpile.py b/tests/transforms/test_transpile.py index 5873e52bff5..cb926e71f2b 100644 --- a/tests/transforms/test_transpile.py +++ b/tests/transforms/test_transpile.py @@ -218,7 +218,7 @@ def circuit(param): assert transpiled_ops[2].wires == qml.wires.Wires([1, 2]) assert isinstance(transpiled_ops[3], qml.MultiRZ) - assert transpiled_ops[3].data == [param] + assert transpiled_ops[3].data == (param,) assert transpiled_ops[3].wires == qml.wires.Wires([0, 1]) assert isinstance(transpiled_ops[4], qml.measurements.MeasurementProcess) @@ -261,7 +261,7 @@ def circuit(param): assert transpiled_ops[2].wires == qml.wires.Wires([1, 2]) assert isinstance(transpiled_ops[3], qml.MultiRZ) - assert transpiled_ops[3].data == [param] + assert transpiled_ops[3].data == (param,) assert transpiled_ops[3].wires == qml.wires.Wires([0, 1]) assert isinstance(transpiled_ops[4], qml.measurements.MeasurementProcess)