diff --git a/.github/workflows/interface-unit-tests.yml b/.github/workflows/interface-unit-tests.yml index 8ea39a1e5a5..07bae8e236b 100644 --- a/.github/workflows/interface-unit-tests.yml +++ b/.github/workflows/interface-unit-tests.yml @@ -263,9 +263,9 @@ jobs: strategy: matrix: config: - - device: default.qubit + - device: default.qubit.legacy shots: None - - device: default.qubit + - device: default.qubit.legacy shots: 10000 # - device: default.qubit.tf # shots: None diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 842d729aa2a..d4d6d286e9e 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -17,9 +17,10 @@ * Quantum information transforms are updated to the new transform program system. [(#4569)](https://github.com/PennyLaneAI/pennylane/pull/4569) -* `qml.devices.DefaultQubit` now implements the new device API. The old version of `default.qubit` - is still accessible via `qml.devices.DefaultQubitLegacy`, or via short name `default.qubit.legacy`. +* `default.qubit` now implements the new device API. The old version of the device is still + accessible by the short name `default.qubit.legacy`, or directly via `qml.devices.DefaultQubitLegacy`. [(#4594)](https://github.com/PennyLaneAI/pennylane/pull/4594) + [(#4436)](https://github.com/PennyLaneAI/pennylane/pull/4436)

Improvements 🛠

@@ -184,6 +185,12 @@ which effectively just called `marginal_prob` with `np.abs(state) ** 2`. [(#4602)](https://github.com/PennyLaneAI/pennylane/pull/4602) +* `default.qubit` now implements the new device API. If you initialize a device + with `qml.device("default.qubit")`, all functions and properties that were tied to the old + device API will no longer be on the device. The legacy version can still be accessed with + `qml.device("default.qubit.legacy", wires=n_wires)`. + [(#4436)](https://github.com/PennyLaneAI/pennylane/pull/4436) +

Deprecations 👋

* The ``prep`` keyword argument in ``QuantumScript`` is deprecated and will be removed from `QuantumScript`. diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py index 6359a262269..ed029cc3653 100644 --- a/pennylane/devices/default_qubit.py +++ b/pennylane/devices/default_qubit.py @@ -146,7 +146,7 @@ def f(x): @property def name(self): """The name of the device.""" - return "default.qubit.2" + return "default.qubit" # pylint:disable = too-many-arguments def __init__( @@ -193,6 +193,7 @@ def supports_derivatives( if ( execution_config.gradient_method == "backprop" and execution_config.device_options.get("max_workers", self._max_workers) is None + and execution_config.interface is not None ): return True diff --git a/pennylane/devices/default_qubit_legacy.py b/pennylane/devices/default_qubit_legacy.py index dc4983933c3..e7842935d43 100644 --- a/pennylane/devices/default_qubit_legacy.py +++ b/pennylane/devices/default_qubit_legacy.py @@ -104,8 +104,8 @@ class DefaultQubitLegacy(QubitDevice): returns analytical results. """ - name = "Default qubit PennyLane plugin" - short_name = "default.qubit" + name = "Default qubit PennyLane plugin (Legacy)" + short_name = "default.qubit.legacy" pennylane_requires = __version__ version = __version__ author = "Xanadu Inc." diff --git a/pennylane/devices/device_api.py b/pennylane/devices/device_api.py index 1fb8dcb81b1..c8bfd53a825 100644 --- a/pennylane/devices/device_api.py +++ b/pennylane/devices/device_api.py @@ -41,9 +41,6 @@ class Device(abc.ABC): """A device driver that can control one or more backends. A backend can be either a physical Quantum Processing Unit or a virtual one such as a simulator. - Device drivers should be configured to run under :func:`~.enable_return`, the newer - return shape specification, as the old return shape specification is deprecated. - Only the ``execute`` method must be defined to construct a device driver. .. details:: diff --git a/pennylane/devices/qubit/adjoint_jacobian.py b/pennylane/devices/qubit/adjoint_jacobian.py index 1c6bc8ba9db..8be6a99909b 100644 --- a/pennylane/devices/qubit/adjoint_jacobian.py +++ b/pennylane/devices/qubit/adjoint_jacobian.py @@ -75,6 +75,8 @@ def adjoint_jacobian(tape: QuantumTape, state=None): param_number = len(tape.get_parameters(trainable_only=False, operations_only=True)) - 1 trainable_param_number = len(tape.trainable_params) - 1 for op in reversed(tape.operations[tape.num_preps :]): + if isinstance(op, qml.Snapshot): + continue adj_op = qml.adjoint(op) ket = apply_operation(adj_op, ket) diff --git a/pennylane/math/single_dispatch.py b/pennylane/math/single_dispatch.py index dd40be00e78..2bf96bef5be 100644 --- a/pennylane/math/single_dispatch.py +++ b/pennylane/math/single_dispatch.py @@ -454,6 +454,7 @@ def _cond_tf(pred, true_fn, false_fn, args): "vander", lambda *args, **kwargs: _i("tf").experimental.numpy.vander(*args, **kwargs), ) +ar.register_function("tensorflow", "size", lambda x: _i("tf").size(x)) # -------------------------------- Torch --------------------------------- # diff --git a/pennylane/measurements/state.py b/pennylane/measurements/state.py index 952223ffb1a..2cc0c576b08 100644 --- a/pennylane/measurements/state.py +++ b/pennylane/measurements/state.py @@ -222,4 +222,4 @@ def process_state(self, state: Sequence[complex], wire_order: Wires): # pylint:disable=redefined-outer-name wire_map = dict(zip(wire_order, range(len(wire_order)))) mapped_wires = [wire_map[w] for w in self.wires] - return qml.math.reduce_statevector(state, indices=mapped_wires, c_dtype=state.dtype) + return qml.math.reduce_statevector(state, indices=mapped_wires) diff --git a/pennylane/optimize/spsa.py b/pennylane/optimize/spsa.py index a8313735640..a3a1e5faae8 100644 --- a/pennylane/optimize/spsa.py +++ b/pennylane/optimize/spsa.py @@ -262,11 +262,13 @@ def compute_grad(self, objective_fn, args, kwargs): yminus = objective_fn(*thetaminus, **kwargs) try: # pylint: disable=protected-access - shots = ( - Shots(objective_fn.device._raw_shot_sequence) - if objective_fn.device.shot_vector is not None - else Shots(None) - ) + dev_shots = objective_fn.device.shots + if isinstance(dev_shots, Shots): + shots = dev_shots if dev_shots.has_partitioned_shots else Shots(None) + elif objective_fn.device.shot_vector is not None: + shots = Shots(objective_fn.device._raw_shot_sequence) # pragma: no cover + else: + shots = Shots(None) if np.prod(objective_fn.func(*args).shape(objective_fn.device, shots)) > 1: raise ValueError( "The objective function must be a scalar function for the gradient " diff --git a/pennylane/qnode.py b/pennylane/qnode.py index 6112915bd74..8c0bddcd55d 100644 --- a/pennylane/qnode.py +++ b/pennylane/qnode.py @@ -705,7 +705,9 @@ def _validate_backprop_method(device, interface, shots=None): config = qml.devices.ExecutionConfig(gradient_method="backprop", interface=interface) if device.supports_derivatives(config): return "backprop", {}, device - raise qml.QuantumFunctionError(f"Device {device.name} does not support backprop") + raise qml.QuantumFunctionError( + f"Device {device.name} does not support backprop with {config}" + ) mapped_interface = INTERFACE_MAP.get(interface, interface) diff --git a/setup.py b/setup.py index 5bd049958f4..34021c1c337 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ # TODO: rename entry point 'pennylane.plugins' to 'pennylane.devices'. # This requires a rename in the setup file of all devices, and is best done during another refactor "pennylane.plugins": [ - "default.qubit = pennylane.devices:DefaultQubitLegacy", + "default.qubit = pennylane.devices:DefaultQubit", "default.qubit.legacy = pennylane.devices:DefaultQubitLegacy", "default.gaussian = pennylane.devices:DefaultGaussian", "default.qubit.tf = pennylane.devices.default_qubit_tf:DefaultQubitTF", diff --git a/tests/devices/experimental/test_default_qubit_2.py b/tests/devices/experimental/test_default_qubit_2.py index 849bc0006a2..c9233240776 100644 --- a/tests/devices/experimental/test_default_qubit_2.py +++ b/tests/devices/experimental/test_default_qubit_2.py @@ -27,7 +27,7 @@ def test_name(): """Tests the name of DefaultQubit.""" - assert DefaultQubit().name == "default.qubit.2" + assert DefaultQubit().name == "default.qubit" def test_shots(): @@ -200,6 +200,56 @@ def test_tracking_resources(self): assert len(tracker.history["resources"]) == 1 assert tracker.history["resources"][0] == expected_resources + def test_tracking_batched_execution(self): + """Test the number of times the device is executed over a QNode's + lifetime is tracked by the device's tracker.""" + + dev_1 = qml.device("default.qubit", wires=2) + + def circuit_1(x, y): + qml.RX(x, wires=[0]) + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)) + + node_1 = qml.QNode(circuit_1, dev_1) + num_evals_1 = 10 + + with qml.Tracker(dev_1, persistent=True) as tracker1: + for _ in range(num_evals_1): + node_1(0.432, np.array([0.12, 0.5, 3.2])) + assert tracker1.totals["executions"] == num_evals_1 + + # test a second instance of a default qubit device + dev_2 = qml.device("default.qubit", wires=2) + + def circuit_2(x): + qml.RX(x, wires=[0]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)) + + node_2 = qml.QNode(circuit_2, dev_2) + num_evals_2 = 5 + + with qml.Tracker(dev_2) as tracker2: + for _ in range(num_evals_2): + node_2(np.array([0.432, 0.61, 8.2])) + assert tracker2.totals["executions"] == num_evals_2 + + # test a new circuit on an existing instance of a qubit device + def circuit_3(y): + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)) + + node_3 = qml.QNode(circuit_3, dev_1) + num_evals_3 = 7 + + with tracker1: + for _ in range(num_evals_3): + node_3(np.array([0.12, 1.214])) + assert tracker1.totals["executions"] == num_evals_1 + num_evals_3 + # pylint: disable=too-few-public-methods class TestPreprocessing: @@ -302,7 +352,7 @@ def test_supports_backprop(self): assert dev.supports_jvp() is True assert dev.supports_vjp() is True - config = ExecutionConfig(gradient_method="backprop") + config = ExecutionConfig(gradient_method="backprop", interface="auto") assert dev.supports_derivatives(config) is True assert dev.supports_jvp(config) is True assert dev.supports_vjp(config) is True @@ -317,6 +367,11 @@ def test_supports_backprop(self): assert dev.supports_jvp(config) is False assert dev.supports_vjp(config) is False + config = ExecutionConfig(gradient_method="backprop", interface=None) + assert dev.supports_derivatives(config) is False + assert dev.supports_jvp(config) is False + assert dev.supports_vjp(config) is False + def test_supports_adjoint(self): """Test that DefaultQubit says that it supports adjoint differentiation.""" dev = DefaultQubit() diff --git a/tests/devices/test_default_qubit_autograd.py b/tests/devices/test_default_qubit_autograd.py index 78094c23191..150f95e6dad 100644 --- a/tests/devices/test_default_qubit_autograd.py +++ b/tests/devices/test_default_qubit_autograd.py @@ -487,7 +487,7 @@ def circuit(a, b): def cost(a, b): prob_wire_1 = circuit(a, b) - return prob_wire_1[1] - prob_wire_1[0] + return prob_wire_1[1] - prob_wire_1[0] # pylint:disable=unsubscriptable-object res = cost(a, b) expected = -np.cos(a) * np.cos(b) @@ -513,7 +513,7 @@ def circuit(a, b): def cost(a, b): prob_wire_1 = circuit(a, b) - return prob_wire_1[:, 1] - prob_wire_1[:, 0] + return prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object res = cost(a, b) expected = -np.cos(a) * np.cos(b) diff --git a/tests/devices/test_default_qubit_legacy.py b/tests/devices/test_default_qubit_legacy.py index ec98819a7d4..aaf2f8fe6ba 100644 --- a/tests/devices/test_default_qubit_legacy.py +++ b/tests/devices/test_default_qubit_legacy.py @@ -643,7 +643,7 @@ def test_apply_errors_qubit_state_vector(self, qubit_device_2_wires): with pytest.raises( DeviceError, match="Operation StatePrep cannot be used after other Operations have already been applied " - "on a default.qubit device.", + "on a default.qubit.legacy device.", ): qubit_device_2_wires.reset() qubit_device_2_wires.apply( @@ -664,7 +664,7 @@ def test_apply_errors_basis_state(self, qubit_device_2_wires): with pytest.raises( DeviceError, match="Operation BasisState cannot be used after other Operations have already been applied " - "on a default.qubit device.", + "on a default.qubit.legacy device.", ): qubit_device_2_wires.reset() qubit_device_2_wires.apply( @@ -2091,7 +2091,7 @@ def test_apply_parametrized_evolution_raises_error(self): param_ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX(0)])) with pytest.raises( NotImplementedError, - match="The device default.qubit cannot execute a ParametrizedEvolution operation", + match="The device default.qubit.legacy cannot execute a ParametrizedEvolution operation", ): self.dev._apply_parametrized_evolution(state=self.state, operation=param_ev) diff --git a/tests/devices/test_default_qubit_legacy_broadcasting.py b/tests/devices/test_default_qubit_legacy_broadcasting.py index 8040f505e4c..c737f194959 100644 --- a/tests/devices/test_default_qubit_legacy_broadcasting.py +++ b/tests/devices/test_default_qubit_legacy_broadcasting.py @@ -462,7 +462,7 @@ def test_apply_errors_qubit_state_vector_broadcasted(self, qubit_device_2_wires) with pytest.raises( DeviceError, match="Operation StatePrep cannot be used after other Operations have already been applied " - "on a default.qubit device.", + "on a default.qubit.legacy device.", ): qubit_device_2_wires.apply([qml.RZ(0.5, wires=[0]), vec]) @@ -491,7 +491,7 @@ def test_apply_errors_basis_state_broadcasted(self, qubit_device_2_wires): with pytest.raises( DeviceError, match="Operation BasisState cannot be used after other Operations have already been applied " - "on a default.qubit device.", + "on a default.qubit.legacy device.", ): qubit_device_2_wires.apply([vec]) diff --git a/tests/devices/test_default_qubit_tf.py b/tests/devices/test_default_qubit_tf.py index f30d4d70f17..5fbfcb1820d 100644 --- a/tests/devices/test_default_qubit_tf.py +++ b/tests/devices/test_default_qubit_tf.py @@ -1873,7 +1873,7 @@ def circuit(a, b): # get the probability of wire 1 prob_wire_1 = circuit(a, b) # compute Prob(|1>_1) - Prob(|0>_1) - res = prob_wire_1[1] - prob_wire_1[0] + res = prob_wire_1[1] - prob_wire_1[0] # pylint:disable=unsubscriptable-object expected = -tf.cos(a) * tf.cos(b) assert np.allclose(res, expected, atol=tol, rtol=0) @@ -1900,7 +1900,7 @@ def circuit(a, b): # get the probability of wire 1 prob_wire_1 = circuit(a, b) # compute Prob(|1>_1) - Prob(|0>_1) - res = prob_wire_1[:, 1] - prob_wire_1[:, 0] + res = prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object expected = -tf.cos(a) * tf.cos(b) assert np.allclose(res, expected, atol=tol, rtol=0) @@ -1938,6 +1938,7 @@ def circuit(a, b): [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] ) + # pylint:disable=no-member assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) res = tape.gradient(res, [a_tf, b_tf]) @@ -1971,6 +1972,7 @@ def circuit(a, b): [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] ) + # pylint:disable=no-member assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) jac = tape.jacobian(res, [a_tf, b_tf]) @@ -2112,8 +2114,8 @@ def circuit(a): res = circuit(a) assert isinstance(res, tf.Tensor) - assert res.shape == (shots,) - assert set(res.numpy()) == {-1, 1} + assert res.shape == (shots,) # pylint:disable=comparison-with-callable + assert set(res.numpy()) == {-1, 1} # pylint:disable=no-member def test_estimating_marginal_probability(self, tol): """Test that the probability of a subset of wires is accurately estimated.""" @@ -2190,8 +2192,8 @@ def circuit(a): res = circuit(a) assert isinstance(res, tf.Tensor) - assert res.shape == (3, shots) - assert set(res.numpy().flat) == {-1, 1} + assert res.shape == (3, shots) # pylint:disable=comparison-with-callable + assert set(res.numpy().flat) == {-1, 1} # pylint:disable=no-member @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_marginal_probability_broadcasted(self, batch_size, tol): diff --git a/tests/devices/test_default_qubit_torch.py b/tests/devices/test_default_qubit_torch.py index 9c2a4c53801..52f80820318 100644 --- a/tests/devices/test_default_qubit_torch.py +++ b/tests/devices/test_default_qubit_torch.py @@ -1808,7 +1808,7 @@ def circuit(p): return qml.expval(qml.PauliZ(0)) res = circuit([x, y, z]) - res.backward() + res.backward() # pylint:disable=no-member expected = torch.cos(3 * x) * torch.cos(y) * torch.cos(z / 2) - torch.sin( 3 * x @@ -1895,7 +1895,7 @@ def circuit(x): return qml.expval(qml.PauliZ(0)) res = circuit(p) - res.backward() + res.backward() # pylint:disable=no-member expected = torch.cos(y) ** 2 - torch.sin(x) * torch.sin(y) ** 2 @@ -2033,7 +2033,7 @@ def circuit(a, b): # get the probability of wire 1 prob_wire_1 = circuit(a, b) # compute Prob(|1>_1) - Prob(|0>_1) - res = prob_wire_1[1] - prob_wire_1[0] + res = prob_wire_1[1] - prob_wire_1[0] # pylint:disable=unsubscriptable-object res.backward() expected = -torch.cos(a) * torch.cos(b) @@ -2062,7 +2062,7 @@ def cost(a, b): # get the probability of wire 1 prob_wire_1 = circuit(a, b) # compute Prob(|1>_1) - Prob(|0>_1) - res = prob_wire_1[:, 1] - prob_wire_1[:, 0] + res = prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object return res res = cost(a, b) @@ -2087,7 +2087,7 @@ def circuit(a, b): b = torch.tensor(0.654, dtype=torch.float64, requires_grad=True, device=torch_device) res = circuit(a, b) - res.backward() + res.backward() # pylint:disable=no-member # the analytic result of evaluating circuit(a, b) expected_cost = 0.5 * (torch.cos(a) * torch.cos(b) + torch.cos(a) - torch.cos(b) + 1) @@ -2242,7 +2242,7 @@ def circuit(a): res = circuit(a) assert torch.is_tensor(res) - assert res.shape == (shots,) + assert res.shape == (shots,) # pylint:disable=comparison-with-callable assert torch.allclose( torch.unique(res), torch.tensor([-1, 1], dtype=torch.int64, device=torch_device) ) @@ -2326,7 +2326,7 @@ def circuit(a): res = circuit(a) assert torch.is_tensor(res) - assert res.shape == (batch_size, shots) + assert res.shape == (batch_size, shots) # pylint:disable=comparison-with-callable assert torch.allclose( torch.unique(res), torch.tensor([-1, 1], dtype=torch.int64, device=torch_device) ) diff --git a/tests/docs/test_supported_confs.py b/tests/docs/test_supported_confs.py index b8d83a0d72f..84e38b40822 100644 --- a/tests/docs/test_supported_confs.py +++ b/tests/docs/test_supported_confs.py @@ -24,7 +24,6 @@ A configuration is supported if gradients can be computed for the QNode without an exception being raised.""" # pylint: disable=too-many-arguments -import re import pytest import pennylane as qml @@ -47,7 +46,6 @@ jax = pytest.importorskip("jax") jnp = pytest.importorskip("jax.numpy") -devices = ["default.qubit"] interfaces = [None, "autograd", "jax", "tf", "torch"] diff_interfaces = ["autograd", "jax", "tf", "torch"] shots_list = [None, 100] @@ -277,13 +275,10 @@ def test_all_device(self, interface, return_type, shots, wire_specs): @pytest.mark.parametrize("wire_specs", wire_specs_list) def test_none_backprop(self, return_type, wire_specs): """Test interface=None and diff_method=backprop raises an error""" - msg = ( - "Device default.qubit only supports diff_method='backprop' when " - "using the ['tf', 'torch', 'autograd', 'jax'] interfaces." - ) - msg = re.escape(msg) - - with pytest.raises(QuantumFunctionError, match=msg): + with pytest.raises( + QuantumFunctionError, + match=r"Device default\.qubit does not support backprop with .*gradient_method='backprop'.*interface=None", + ): get_qnode(None, "backprop", return_type, None, wire_specs) @pytest.mark.parametrize( @@ -295,17 +290,33 @@ def test_none_backprop(self, return_type, wire_specs): def test_none_all(self, diff_method, return_type, shots, wire_specs): """Test interface=None and diff_method in [adjoint, parameter-shift, finite-diff, spsa, hadamard] has a working forward pass""" - warn_msg = ( - "Requested adjoint differentiation to be computed with finite shots. " - "Adjoint differentiation always calculated exactly." - ) + circuit = get_qnode(None, diff_method, return_type, shots, wire_specs) + x = get_variable(None, wire_specs) + + msg = None + if not shots and return_type is Sample: + msg = "Analytic circuits must only contain StateMeasurements" + elif diff_method == "adjoint": + if shots: + msg = ( + "Circuits with finite shots must be executed with non-analytic gradient methods" + ) + elif return_type not in ("Hermitian", "Projector", Expectation): + msg = "Adjoint differentiation method does not support measurement .*" + elif shots and return_type in ( + VnEntropy, + MutualInfo, + "DensityMatrix", + "StateCost", + "StateVector", + ): + msg = "Circuits with finite shots must only contain" - if diff_method == "adjoint" and shots is not None: - # this warning is still raised in the forward pass - with pytest.warns(UserWarning, match=warn_msg): - get_qnode(None, diff_method, return_type, shots, wire_specs) + if msg is not None: + with pytest.raises(qml.DeviceError, match=msg): + circuit(x) else: - get_qnode(None, diff_method, return_type, shots, wire_specs) + circuit(x) @pytest.mark.parametrize("interface", diff_interfaces) @pytest.mark.parametrize( @@ -348,18 +359,16 @@ def test_all_backprop_finite_shots(self, interface, return_type, wire_specs): def test_all_adjoint_nonexp(self, interface, return_type, shots, wire_specs): """Test diff_method=adjoint raises an error for non-expectation measurements for all interfaces""" - msg = "Adjoint differentiation method does not support measurement .*" - - warn_msg = ( - "Requested adjoint differentiation to be computed with finite shots. " - "Adjoint differentiation always calculated exactly." + msg = ( + "Circuits with finite shots must be executed with non-analytic gradient methods" + if shots + else "Adjoint differentiation method does not support measurement .*" ) - with pytest.raises(QuantumFunctionError, match=msg): - with pytest.warns(UserWarning, match=warn_msg): - circuit = get_qnode(interface, "adjoint", return_type, shots, wire_specs) - x = get_variable(interface, wire_specs) - compute_gradient(x, interface, circuit, return_type) + circuit = get_qnode(interface, "adjoint", return_type, shots, wire_specs) + x = get_variable(interface, wire_specs) + with pytest.raises(qml.DeviceError, match=msg): + compute_gradient(x, interface, circuit, return_type) @pytest.mark.parametrize("interface", diff_interfaces) @pytest.mark.parametrize("return_type", [Expectation, "Hermitian", "Projector"]) @@ -367,11 +376,6 @@ def test_all_adjoint_nonexp(self, interface, return_type, shots, wire_specs): @pytest.mark.parametrize("wire_specs", wire_specs_list) def test_all_adjoint_exp(self, interface, return_type, shots, wire_specs): """Test diff_method=adjoint works for expectation measurements for all interfaces""" - warn_msg = ( - "Requested adjoint differentiation to be computed with finite shots. " - "Adjoint differentiation always calculated exactly." - ) - if shots is None: # test that everything runs # correctness is already tested in other test files @@ -379,10 +383,12 @@ def test_all_adjoint_exp(self, interface, return_type, shots, wire_specs): x = get_variable(interface, wire_specs) compute_gradient(x, interface, circuit, return_type) else: - # test warning is raised when shots > 0 - with pytest.warns(UserWarning, match=warn_msg): - circuit = get_qnode(interface, "adjoint", return_type, shots, wire_specs) - x = get_variable(interface, wire_specs) + circuit = get_qnode(interface, "adjoint", return_type, shots, wire_specs) + x = get_variable(interface, wire_specs) + with pytest.raises( + qml.DeviceError, + match="Circuits with finite shots must be executed with non-analytic gradient methods", + ): compute_gradient(x, interface, circuit, return_type) @pytest.mark.parametrize("interface", diff_interfaces) @@ -416,13 +422,16 @@ def test_all_paramshift_state(self, interface, return_type, shots, wire_specs): ) complex = return_type == "StateVector" - with pytest.raises(ValueError, match=msg): - circuit = get_qnode(interface, "parameter-shift", return_type, shots, wire_specs) - x = get_variable(interface, wire_specs, complex=complex) - if shots is not None: - with pytest.warns(UserWarning, match="the returned result is analytic"): - compute_gradient(x, interface, circuit, return_type, complex=complex) - else: + # with pytest.raises(ValueError, match=msg): + circuit = get_qnode(interface, "parameter-shift", return_type, shots, wire_specs) + x = get_variable(interface, wire_specs, complex=complex) + if shots is not None: + with pytest.raises( + qml.DeviceError, match="Circuits with finite shots must only contain" + ): + compute_gradient(x, interface, circuit, return_type, complex=complex) + else: + with pytest.raises(ValueError, match=msg): compute_gradient(x, interface, circuit, return_type, complex=complex) @pytest.mark.parametrize("interface", diff_interfaces) @@ -441,7 +450,9 @@ def test_all_finitediff_nonstate(self, interface, return_type, shots, wire_specs circuit = get_qnode(interface, diff_method, return_type, shots, wire_specs) x = get_variable(interface, wire_specs) if shots is not None and return_type in (VnEntropy, MutualInfo): - with pytest.warns(UserWarning, match="unaffected by sampling"): + with pytest.raises( + qml.DeviceError, match="Circuits with finite shots must only contain" + ): compute_gradient(x, interface, circuit, return_type) else: compute_gradient(x, interface, circuit, return_type) @@ -480,12 +491,8 @@ def test_all_finitediff_state(self, interface, return_type, shots, wire_specs, d def test_all_sample_none_shots(self, interface, diff_method, wire_specs): """Test sample measurement fails for all interfaces and diff_methods when shots=None""" - msg = ( - "The number of shots has to be explicitly set on the device " - "when using sample-based measurements." - ) - with pytest.raises(QuantumFunctionError, match=msg): + with pytest.raises(qml.DeviceError, match="Analytic circuits must only contain"): circuit = get_qnode(interface, diff_method, Sample, None, wire_specs) x = get_variable(interface, wire_specs) circuit(x) @@ -540,11 +547,13 @@ def test_all_hadamard_nonstate_non_var( circuit = get_qnode(interface, diff_method, return_type, shots, wire_specs) x = get_variable(interface, wire_specs) if return_type in (VnEntropy, MutualInfo): - msg = ( - "Computing the gradient of circuits that return the state with the " - "Hadamard test gradient transform is not supported." - ) - with pytest.raises(ValueError, match=msg): + if shots: + err_cls = qml.DeviceError + msg = "Circuits with finite shots must only contain" + else: + err_cls = ValueError + msg = "Computing the gradient of circuits that return the state with the Hadamard test gradient transform is not supported" + with pytest.raises(err_cls, match=msg): compute_gradient(x, interface, circuit, return_type) elif return_type == Variance: with pytest.raises( diff --git a/tests/gradients/core/test_gradient_transform.py b/tests/gradients/core/test_gradient_transform.py index 3aded27707f..f592a535129 100644 --- a/tests/gradients/core/test_gradient_transform.py +++ b/tests/gradients/core/test_gradient_transform.py @@ -616,7 +616,7 @@ def test_setting_shots(self): """Test that setting the number of shots works correctly for a gradient transform""" - dev = qml.device("default.qubit", wires=1, shots=1000) + dev = qml.device("default.qubit.legacy", wires=1, shots=1000) @qml.qnode(dev) def circuit(x): diff --git a/tests/gradients/core/test_hadamard_gradient.py b/tests/gradients/core/test_hadamard_gradient.py index 92bfbf67357..3b485b7aaab 100644 --- a/tests/gradients/core/test_hadamard_gradient.py +++ b/tests/gradients/core/test_hadamard_gradient.py @@ -25,7 +25,7 @@ def grad_fn(tape, dev, fn=qml.gradients.hadamard_grad, **kwargs): """Utility function to automate execution and processing of gradient tapes""" tapes, fn = fn(tape, **kwargs) - return fn(dev.batch_execute(tapes)), tapes + return fn(dev.execute(tapes)), tapes def cost1(x): @@ -548,6 +548,8 @@ def test_shots_attribute(self, shots): class TestHadamardGradEdgeCases: """Test the Hadamard gradient transform and edge cases such as non diff parameters, auxiliary wires, etc...""" + # pylint:disable=too-many-public-methods + device_wires = [qml.wires.Wires([0, 1, "aux"])] device_wires_no_aux = [qml.wires.Wires([0, 1, 2])] @@ -725,7 +727,7 @@ def test_no_trainable_params_qnode_autograd(self, mocker): """Test that the correct ouput and warning is generated in the absence of any trainable parameters""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(dev, "expval") + spy = mocker.spy(qml.devices.qubit, "measure") @qml.qnode(dev, interface="autograd") def circuit(weights): @@ -745,7 +747,7 @@ def test_no_trainable_params_qnode_torch(self, mocker): """Test that the correct ouput and warning is generated in the absence of any trainable parameters""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(dev, "expval") + spy = mocker.spy(qml.devices.qubit, "measure") @qml.qnode(dev, interface="torch") def circuit(weights): @@ -765,7 +767,7 @@ def test_no_trainable_params_qnode_tf(self, mocker): """Test that the correct ouput and warning is generated in the absence of any trainable parameters""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(dev, "expval") + spy = mocker.spy(qml.devices.qubit, "measure") @qml.qnode(dev, interface="tf") def circuit(weights): @@ -785,6 +787,86 @@ def test_no_trainable_params_qnode_jax(self, mocker): """Test that the correct ouput and warning is generated in the absence of any trainable parameters""" dev = qml.device("default.qubit", wires=2) + spy = mocker.spy(qml.devices.qubit, "measure") + + @qml.qnode(dev, interface="jax") + def circuit(weights): + qml.RX(weights[0], wires=0) + qml.RY(weights[1], wires=0) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + weights = [0.1, 0.2] + with pytest.warns(UserWarning, match="gradient of a QNode with no trainable parameters"): + res_hadamard = qml.gradients.hadamard_grad(circuit)(weights) + + assert res_hadamard == () + spy.assert_not_called() + + @pytest.mark.autograd + def test_no_trainable_params_qnode_autograd_legacy(self, mocker): + """Test that the correct ouput and warning is generated in the absence of any trainable + parameters""" + dev = qml.device("default.qubit.autograd", wires=2) + spy = mocker.spy(dev, "expval") + + @qml.qnode(dev, interface="autograd") + def circuit(weights): + qml.RX(weights[0], wires=0) + qml.RY(weights[1], wires=0) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + weights = [0.1, 0.2] + with pytest.warns(UserWarning, match="gradient of a QNode with no trainable parameters"): + res_hadamard = qml.gradients.hadamard_grad(circuit)(weights) + + assert res_hadamard == () + spy.assert_not_called() + + @pytest.mark.torch + def test_no_trainable_params_qnode_torch_legacy(self, mocker): + """Test that the correct ouput and warning is generated in the absence of any trainable + parameters""" + dev = qml.device("default.qubit.torch", wires=2) + spy = mocker.spy(dev, "expval") + + @qml.qnode(dev, interface="torch") + def circuit(weights): + qml.RX(weights[0], wires=0) + qml.RY(weights[1], wires=0) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + weights = [0.1, 0.2] + with pytest.warns(UserWarning, match="gradient of a QNode with no trainable parameters"): + res_hadamard = qml.gradients.hadamard_grad(circuit)(weights) + + assert res_hadamard == () + spy.assert_not_called() + + @pytest.mark.tf + def test_no_trainable_params_qnode_tf_legacy(self, mocker): + """Test that the correct ouput and warning is generated in the absence of any trainable + parameters""" + dev = qml.device("default.qubit.tf", wires=2) + spy = mocker.spy(dev, "expval") + + @qml.qnode(dev, interface="tf") + def circuit(weights): + qml.RX(weights[0], wires=0) + qml.RY(weights[1], wires=0) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + weights = [0.1, 0.2] + with pytest.warns(UserWarning, match="gradient of a QNode with no trainable parameters"): + res_hadamard = qml.gradients.hadamard_grad(circuit)(weights) + + assert res_hadamard == () + spy.assert_not_called() + + @pytest.mark.jax + def test_no_trainable_params_qnode_jax_legacy(self, mocker): + """Test that the correct ouput and warning is generated in the absence of any trainable + parameters""" + dev = qml.device("default.qubit.jax", wires=2) spy = mocker.spy(dev, "expval") @qml.qnode(dev, interface="jax") @@ -971,10 +1053,12 @@ class TestHadamardTestGradDiff: """Test that the transform is differentiable""" @pytest.mark.autograd - def test_autograd(self): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name): """Tests that the output of the hadamard gradient transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=3) + dev = qml.device(dev_name, wires=3) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn_hadamard(x): @@ -987,7 +1071,7 @@ def cost_fn_hadamard(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return qml.math.stack(jac) def cost_fn_param_shift(x): @@ -1000,7 +1084,7 @@ def cost_fn_param_shift(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.param_shift(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return qml.math.stack(jac) res_hadamard = qml.jacobian(cost_fn_hadamard)(params) @@ -1008,12 +1092,14 @@ def cost_fn_param_shift(x): assert np.allclose(res_hadamard, res_param_shift) @pytest.mark.tf - def test_tf(self): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name): """Tests that the output of the hadamard gradient transform can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=3) + dev = qml.device(dev_name, wires=3) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) with tf.GradientTape() as t_h: @@ -1026,7 +1112,7 @@ def test_tf(self): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac_h = fn(dev.batch_execute(tapes)) + jac_h = fn(execute_fn(tapes)) jac_h = qml.math.stack(jac_h) with tf.GradientTape() as t_p: @@ -1039,7 +1125,7 @@ def test_tf(self): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.param_shift(tape) - jac_p = fn(dev.batch_execute(tapes)) + jac_p = fn(execute_fn(tapes)) jac_p = qml.math.stack(jac_p) res_hadamard = t_h.jacobian(jac_h, params) @@ -1048,12 +1134,14 @@ def test_tf(self): assert np.allclose(res_hadamard, res_param_shift) @pytest.mark.torch - def test_torch(self): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name): """Tests that the output of the hadamard gradient transform can be differentiated using Torch, yielding second derivatives.""" import torch - dev = qml.device("default.qubit.torch", wires=3) + dev = qml.device(dev_name, wires=3) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = torch.tensor([0.543, -0.654], dtype=torch.float64, requires_grad=True) def cost_h(x): @@ -1066,7 +1154,7 @@ def cost_h(x): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac def cost_p(x): @@ -1079,7 +1167,7 @@ def cost_p(x): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = qml.gradients.param_shift(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res_hadamard = torch.autograd.functional.jacobian(cost_h, params) @@ -1089,7 +1177,8 @@ def cost_p(x): assert np.allclose(res_hadamard[1].detach(), res_param_shift[1].detach()) @pytest.mark.jax - def test_jax(self): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name): """Tests that the output of the hadamard gradient transform can be differentiated using JAX, yielding second derivatives.""" import jax @@ -1098,7 +1187,8 @@ def test_jax(self): config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=3) + dev = qml.device(dev_name, wires=3) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = jnp.array([0.543, -0.654]) def cost_h(x): @@ -1112,7 +1202,7 @@ def cost_h(x): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac def cost_p(x): @@ -1126,7 +1216,7 @@ def cost_p(x): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res_hadamard = jax.jacobian(cost_h)(params) diff --git a/tests/gradients/core/test_hamiltonian_gradient.py b/tests/gradients/core/test_hamiltonian_gradient.py index 488b8e7dd8a..1bcb4bfc4fe 100644 --- a/tests/gradients/core/test_hamiltonian_gradient.py +++ b/tests/gradients/core/test_hamiltonian_gradient.py @@ -30,10 +30,10 @@ def test_behaviour(): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {2, 3} tapes, processing_fn = hamiltonian_grad(tape, idx=0) - res1 = processing_fn(dev.batch_execute(tapes)) + res1 = processing_fn(dev.execute(tapes)) tapes, processing_fn = hamiltonian_grad(tape, idx=1) - res2 = processing_fn(dev.batch_execute(tapes)) + res2 = processing_fn(dev.execute(tapes)) with qml.queuing.AnnotatedQueue() as q1: qml.RY(0.3, wires=0) @@ -49,9 +49,7 @@ def test_behaviour(): qml.expval(qml.PauliZ(1)) tape2 = qml.tape.QuantumScript.from_queue(q2) - dev.reset() res_expected1 = qml.math.squeeze(dev.execute(tape1)) - dev.reset() res_expected2 = qml.math.squeeze(dev.execute(tape2)) assert res_expected1 == res1 diff --git a/tests/gradients/core/test_jvp.py b/tests/gradients/core/test_jvp.py index beb2cc9bf8e..ac973027534 100644 --- a/tests/gradients/core/test_jvp.py +++ b/tests/gradients/core/test_jvp.py @@ -484,7 +484,7 @@ def test_single_expectation_value(self, tol, batch_dim): tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert res.shape == () if batch_dim is None else (batch_dim,) exp = np.sum(np.array([-np.sin(y) * np.sin(x), np.cos(y) * np.cos(x)]), axis=0) @@ -514,7 +514,7 @@ def test_multiple_expectation_values(self, tol, batch_dim): tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 assert all(r.shape == () if batch_dim is None else (batch_dim,) for r in res) @@ -546,7 +546,7 @@ def test_prob_expval_single_param(self, tol, batch_dim): tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) assert len(tapes) == 2 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 assert res[0].shape == () if batch_dim is None else (batch_dim,) @@ -583,7 +583,7 @@ def test_prob_expval_multi_param(self, tol, batch_dim): tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -655,10 +655,12 @@ class TestJVPGradients: # Include batch_dim!=None cases once #4462 is resolved @pytest.mark.autograd @pytest.mark.parametrize("batch_dim", [None]) # , 1, 3]) - def test_autograd(self, tol, batch_dim): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, tol, dev_name, batch_dim): """Tests that the output of the JVP transform can be differentiated using autograd.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) if batch_dim is not None: params = np.outer(np.arange(1, 1 + batch_dim), params, requires_grad=True) @@ -671,7 +673,7 @@ def cost_fn(params, tangent): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) - jvp = fn(dev.batch_execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) @@ -685,12 +687,14 @@ def cost_fn(params, tangent): # Include batch_dim!=None cases once #4462 is resolved @pytest.mark.torch @pytest.mark.parametrize("batch_dim", [None]) # , 1, 3]) - def test_torch(self, tol, batch_dim): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, tol, dev_name, batch_dim): """Tests that the output of the JVP transform can be differentiated using Torch.""" import torch - dev = qml.device("default.qubit.torch", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params_np = np.array([0.543, -0.654], requires_grad=True) if batch_dim is not None: @@ -706,7 +710,7 @@ def cost_fn(params, tangent): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) - jvp = fn(dev.batch_execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) @@ -721,12 +725,14 @@ def cost_fn(params, tangent): @pytest.mark.tf @pytest.mark.slow @pytest.mark.parametrize("batch_dim", [None]) # , 1, 3]) - def test_tf(self, tol, batch_dim): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, tol, dev_name, batch_dim): """Tests that the output of the JVP transform can be differentiated using Tensorflow.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params_np = np.array([0.543, -0.654], requires_grad=True) if batch_dim is not None: params_np = np.outer(np.arange(1, 1 + batch_dim), params_np, requires_grad=True) @@ -741,7 +747,7 @@ def cost_fn(params, tangent): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) - jvp = fn(dev.batch_execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp with tf.GradientTape() as t: @@ -757,13 +763,15 @@ def cost_fn(params, tangent): # Include batch_dim!=None cases once #4462 is resolved @pytest.mark.jax @pytest.mark.parametrize("batch_dim", [None]) # , 1, 3]) - def test_jax(self, tol, batch_dim): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, tol, dev_name, batch_dim): """Tests that the output of the JVP transform can be differentiated using JAX.""" import jax from jax import numpy as jnp - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params_np = np.array([0.543, -0.654], requires_grad=True) if batch_dim is not None: params_np = np.outer(np.arange(1, 1 + batch_dim), params_np, requires_grad=True) @@ -778,7 +786,7 @@ def cost_fn(params, tangent): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.jvp(tape, tangent, param_shift) - jvp = fn(dev.batch_execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) @@ -821,7 +829,7 @@ def test_one_tape_no_trainable_parameters(self): # Even though there are 3 parameters, only two contribute # to the JVP, so only 2*2=4 quantum evals - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) assert res[0] is None assert res[1] is not None @@ -877,7 +885,7 @@ def test_zero_tangent(self): tangents = [np.array([0.0]), np.array([1.0, 1.0])] v_tapes, fn = qml.gradients.batch_jvp(tapes, tangents, param_shift) - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Even though there are 3 parameters, only two contribute # to the JVP, so only 2*2=4 quantum evals @@ -909,7 +917,7 @@ def test_reduction_append(self): tangents = [np.array([1.0]), np.array([1.0, 1.0])] v_tapes, fn = qml.gradients.batch_jvp(tapes, tangents, param_shift, reduction="append") - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Returned JVPs will be appended to a list, one JVP per tape @@ -942,7 +950,7 @@ def test_reduction_extend(self): tangents = [np.array([1.0]), np.array([1.0])] v_tapes, fn = qml.gradients.batch_jvp(tapes, tangents, param_shift, reduction="extend") - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) assert len(res) == 4 def test_reduction_extend_special(self): @@ -977,7 +985,7 @@ def test_reduction_extend_special(self): if not isinstance(x, tuple) and x.shape == () else jvps.extend(x), ) - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) assert len(res) == 3 @@ -1008,6 +1016,6 @@ def test_reduction_callable(self): v_tapes, fn = qml.gradients.batch_jvp( tapes, tangents, param_shift, reduction=lambda jvps, x: jvps.append(x) ) - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Returned JVPs will be appended to a list, one JVP per tape assert len(res) == 2 diff --git a/tests/gradients/core/test_pulse_generator_gradient.py b/tests/gradients/core/test_pulse_generator_gradient.py index 1f6b5b255f1..3396fe02210 100644 --- a/tests/gradients/core/test_pulse_generator_gradient.py +++ b/tests/gradients/core/test_pulse_generator_gradient.py @@ -40,7 +40,7 @@ def grad_fn(tape, dev, fn=pulse_generator, **kwargs): """Utility function to automate execution and processing of gradient tapes""" _tapes, fn = fn(tape, **kwargs) - return fn(dev.batch_execute(_tapes)), _tapes + return fn(dev.execute(_tapes)), _tapes def integral_of_polyval(params, t): @@ -474,7 +474,7 @@ def test_output_properties(self, ops_and_meas, op_idx, ops): """Test that the input tape and inserted ops are taken into account correctly.""" evolve_op = qml.evolve(qml.pulse.constant * Z("a"))([np.array(0.2)], 0.2) operations, measurements = ops_and_meas - operations = [evolve_op if op == "evolve_op" else op for op in operations] + operations = [evolve_op if isinstance(op, str) else op for op in operations] tape = qml.tape.QuantumScript(operations, measurements) new_tapes = _insert_op(tape, ops, op_idx) assert isinstance(new_tapes, list) and len(new_tapes) == len(ops) @@ -870,7 +870,7 @@ def test_no_trainable_params_multiple_return_tape(self): with pytest.warns(UserWarning, match="gradient of a tape with no trainable parameters"): _tapes, fn = pulse_generator(tape) - res = fn(dev.batch_execute(_tapes)) + res = fn(dev.execute(_tapes)) assert _tapes == [] assert isinstance(res, tuple) @@ -965,19 +965,21 @@ def test_all_zero_diff_methods_multiple_returns_tape(self): assert np.allclose(res_pulse_gen[1][2], 0) +# TODO: add default.qubit once it supports PRNG key @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit.jax"]) class TestPulseGeneratorTape: """Test that differentiating tapes with ``pulse_generator`` works.""" @pytest.mark.parametrize("shots, tol", [(None, 1e-7), (1000, 0.05), ([1000, 100], 0.05)]) - def test_single_pulse_single_term(self, shots, tol): + def test_single_pulse_single_term(self, dev_name, shots, tol): """Test that a single pulse with a single Hamiltonian term is differentiated correctly.""" import jax import jax.numpy as jnp prng_key = jax.random.PRNGKey(8251) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=prng_key) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=prng_key) H = jnp.polyval * X(0) x = jnp.array([0.4, 0.2, 0.1]) @@ -1005,15 +1007,15 @@ def test_single_pulse_single_term(self, shots, tol): @pytest.mark.slow @pytest.mark.parametrize("shots, tol", [(None, 1e-7), ([1000, 100], 0.05)]) - def test_single_pulse_multi_term(self, shots, tol): + def test_single_pulse_multi_term(self, dev_name, shots, tol): """Test that a single pulse with multiple Hamiltonian terms is differentiated correctly.""" import jax import jax.numpy as jnp prng_key = jax.random.PRNGKey(8251) - dev = qml.device("default.qubit.jax", wires=1, shots=None) - dev_shots = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=prng_key) + dev = qml.device(dev_name, wires=1, shots=None) + dev_shots = qml.device(dev_name, wires=1, shots=shots, prng_key=prng_key) H = 0.1 * Z(0) + jnp.polyval * X(0) + qml.pulse.constant * Y(0) x = jnp.array([0.4, 0.2, 0.1]) @@ -1045,13 +1047,13 @@ def circuit(par): assert all(qml.math.allclose(g, e, atol=tol) for g, e in zip(grad, exp_grad)) @pytest.mark.parametrize("argnum", (0, [0], 1, [1])) - def test_single_pulse_multi_term_argnum(self, argnum): + def test_single_pulse_multi_term_argnum(self, dev_name, argnum): """Test that a single pulse with multiple Hamiltonian terms is differentiated correctly when setting ``argnum``.""" import jax import jax.numpy as jnp - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) H = jnp.polyval * X(0) + qml.pulse.constant * X(0) x = jnp.array([0.4, 0.2, 0.1]) @@ -1085,15 +1087,15 @@ def test_single_pulse_multi_term_argnum(self, argnum): @pytest.mark.slow @pytest.mark.parametrize("shots, tol", [(None, 1e-7), ([1000, 100], 0.05)]) - def test_multi_pulse(self, shots, tol): + def test_multi_pulse(self, dev_name, shots, tol): """Test that a single pulse with multiple Hamiltonian terms is differentiated correctly.""" import jax import jax.numpy as jnp prng_key = jax.random.PRNGKey(8251) - dev = qml.device("default.qubit.jax", wires=1, shots=None) - dev_shots = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=prng_key) + dev = qml.device(dev_name, wires=1, shots=None) + dev_shots = qml.device(dev_name, wires=1, shots=shots, prng_key=prng_key) H0 = 0.1 * Z(0) + jnp.polyval * X(0) H1 = 0.2 * Y(0) + qml.pulse.constant * Y(0) + jnp.polyval * Z(0) @@ -1129,14 +1131,15 @@ def circuit(par): @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) class TestPulseGeneratorQNode: """Test that pulse_generator integrates correctly with QNodes.""" - def test_raises_for_application_to_qnodes(self): + def test_raises_for_application_to_qnodes(self, dev_name): """Test that an error is raised when applying ``stoch_pulse_grad`` to a QNode directly.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @qml.qnode(dev, interface="jax") @@ -1150,14 +1153,14 @@ def circuit(params): # TODO: include the following tests when #4225 is resolved. @pytest.mark.skip("Applying this gradient transform to QNodes directly is not supported.") - def test_qnode_expval_single_par(self): + def test_qnode_expval_single_par(self, dev_name): """Test that a simple qnode that returns an expectation value can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = qml.pulse.constant * Y(0) @@ -1176,14 +1179,14 @@ def circuit(params): assert tracker.totals["executions"] == 2 # two shifted tapes @pytest.mark.skip("Applying this gradient transform to QNodes directly is not supported.") - def test_qnode_expval_probs_single_par(self): + def test_qnode_expval_probs_single_par(self, dev_name): """Test that a simple qnode that returns an expectation value can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = jnp.polyval * Y(0) @@ -1208,14 +1211,14 @@ def circuit(params): assert qml.math.allclose(j, e) @pytest.mark.skip("Applying this gradient transform to QNodes directly is not supported.") - def test_qnode_probs_expval_multi_par(self): + def test_qnode_probs_expval_multi_par(self, dev_name): """Test that a simple qnode that returns probabilities can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=None) + dev = qml.device(dev_name, wires=1, shots=None) T = 0.2 ham_single_q_const = jnp.polyval * Y(0) + qml.pulse.constant * Y(0) @@ -1248,17 +1251,18 @@ def circuit(params, c): @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) class TestPulseGeneratorIntegration: """Test that pulse_generator integrates correctly with QNodes.""" - def test_simple_qnode_expval(self): + def test_simple_qnode_expval(self, dev_name): """Test that a simple qnode that returns an expectation value can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = qml.pulse.constant * Y(0) @@ -1275,14 +1279,14 @@ def circuit(params): assert qml.math.allclose(grad, exp_grad) assert tracker.totals["executions"] == 1 + 2 # one forward pass, two shifted tapes - def test_simple_qnode_expval_two_evolves(self): + def test_simple_qnode_expval_two_evolves(self, dev_name): """Test that a simple qnode that returns an expectation value can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T_x = 0.1 T_y = 0.2 ham_x = qml.pulse.constant * X(0) @@ -1301,14 +1305,14 @@ def circuit(params): exp_grad = [[-2 * jnp.sin(2 * (p_x + p_y)) * T_x], [-2 * jnp.sin(2 * (p_x + p_y)) * T_y]] assert qml.math.allclose(grad, exp_grad) - def test_simple_qnode_probs(self): + def test_simple_qnode_probs(self, dev_name): """Test that a simple qnode that returns probabilities can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = qml.pulse.constant * Y(0) @@ -1323,14 +1327,14 @@ def circuit(params): exp_jac = jnp.array([-1, 1]) * jnp.sin(2 * p) * T assert qml.math.allclose(jac, exp_jac) - def test_simple_qnode_probs_expval(self): + def test_simple_qnode_probs_expval(self, dev_name): """Test that a simple qnode that returns probabilities can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = jnp.polyval * Y(0) @@ -1352,13 +1356,13 @@ def circuit(params): @pytest.mark.xfail @pytest.mark.parametrize("time_interface", ["python", "numpy", "jax"]) - def test_simple_qnode_jit(self, time_interface): + def test_simple_qnode_jit(self, dev_name, time_interface): """Test that a simple qnode can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = {"python": 0.2, "numpy": np.array(0.2), "jax": jnp.array(0.2)}[time_interface] ham_single_q_const = qml.pulse.constant * Y(0) @@ -1374,7 +1378,7 @@ def circuit(params, T=None): assert qml.math.isclose(jit_grad, exp_grad) @pytest.mark.slow - def test_advanced_qnode(self): + def test_advanced_qnode(self, dev_name): """Test that an advanced qnode can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp @@ -1382,7 +1386,7 @@ def test_advanced_qnode(self): jax.config.update("jax_enable_x64", True) params = [jnp.array(0.21), jnp.array(-0.171), jnp.array([0.05, 0.03, -0.1])] - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) ham = ( qml.pulse.constant * X(0) + (lambda p, t: jnp.sin(p * t)) * Z(0) @@ -1401,8 +1405,9 @@ def ansatz(params): ) qnode_backprop = qml.QNode(ansatz, dev, interface="jax") - grad_pulse_grad = jax.grad(qnode_pulse_grad)(params) - assert dev.num_executions == 1 + 12 # one forward execution, dim(DLA)=6 + with qml.Tracker(dev) as tracker: + grad_pulse_grad = jax.grad(qnode_pulse_grad)(params) + assert tracker.totals["executions"] == 1 + 12 # one forward execution, dim(DLA)=6 grad_backprop = jax.grad(qnode_backprop)(params) assert all( @@ -1410,14 +1415,14 @@ def ansatz(params): ) @pytest.mark.parametrize("argnums", [[0, 1], 0, 1]) - def test_simple_qnode_expval_multiple_params(self, argnums): + def test_simple_qnode_expval_multiple_params(self, dev_name, argnums): """Test that a simple qnode with two parameters can be differentiated with pulse_generator and `argnums` works as expected.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham1 = qml.pulse.constant * Y(0) ham2 = qml.pulse.constant * Y(0) @@ -1442,7 +1447,9 @@ def circuit(param1, param2): assert tracker.totals["executions"] == 1 + 2 # one forward pass, two shifted tapes +# TODO: port ParametrizedEvolution to new default.qubit @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit.jax"]) class TestPulseGeneratorDiff: """Test that pulse_generator is differentiable, i.e. that computing the derivative with pulse_generator is differentiable a second time, @@ -1450,14 +1457,14 @@ class TestPulseGeneratorDiff: # pylint: disable=too-few-public-methods @pytest.mark.slow - def test_jax(self): + def test_jax(self, dev_name): """Test that pulse_generator is differentiable, allowing to compute the Hessian, with JAX..""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.5 ham_single_q_const = qml.pulse.constant * Y(0) diff --git a/tests/gradients/core/test_pulse_gradient.py b/tests/gradients/core/test_pulse_gradient.py index ac6abd9d2cb..38ea9f3af65 100644 --- a/tests/gradients/core/test_pulse_gradient.py +++ b/tests/gradients/core/test_pulse_gradient.py @@ -823,6 +823,7 @@ def test_raises_for_invalid_reorder_fn(self, reorder_fn): @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) class TestStochPulseGrad: """Test working cases of stoch_pulse_grad.""" @@ -856,7 +857,7 @@ def sine(p, t): ), ), ) - def test_all_zero_grads(self, ops, arg, exp_shapes): + def test_all_zero_grads(self, dev_name, ops, arg, exp_shapes): # pylint:disable=unused-argument """Test that a zero gradient is returned when all trainable parameters are identified to have zero gradient in advance.""" import jax @@ -878,7 +879,7 @@ def test_all_zero_grads(self, ops, arg, exp_shapes): assert qml.math.allclose(r, np.zeros(exp_shape)) jax.clear_caches() - def test_some_zero_grads(self): + def test_some_zero_grads(self, dev_name): """Test that a zero gradient is returned for trainable parameters that are identified to have a zero gradient in advance.""" import jax @@ -894,7 +895,7 @@ def test_some_zero_grads(self): tapes, fn = stoch_pulse_grad(tape, num_split_times=3) assert len(tapes) == 2 * 3 - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) res = fn(qml.execute(tapes, dev, None)) assert isinstance(res, tuple) and len(res) == 2 assert qml.math.allclose(res[0][0], np.zeros(5)) @@ -903,7 +904,7 @@ def test_some_zero_grads(self): @pytest.mark.parametrize("num_split_times", [1, 3]) @pytest.mark.parametrize("t", [2.0, 3, (0.5, 0.6), (0.1, 0.9, 1.2)]) - def test_constant_ry(self, num_split_times, t): + def test_constant_ry(self, dev_name, num_split_times, t): """Test that the derivative of a pulse generated by a constant Hamiltonian, which is a Pauli word, is computed correctly.""" import jax @@ -916,7 +917,7 @@ def test_constant_ry(self, num_split_times, t): op = qml.evolve(ham_single_q_const)(params, t) tape = qml.tape.QuantumScript([op], [qml.expval(qml.PauliZ(0))]) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) # Effective rotation parameter p = params[0] * (delta_t := (T[-1] - T[0])) r = qml.execute([tape], dev, None) @@ -930,7 +931,7 @@ def test_constant_ry(self, num_split_times, t): @pytest.mark.parametrize("num_split_times", [1, 3]) @pytest.mark.parametrize("t", [2.0, 3, (0.5, 0.6), (0.1, 0.9, 1.2)]) - def test_constant_ry_rescaled(self, num_split_times, t): + def test_constant_ry_rescaled(self, dev_name, num_split_times, t): """Test that the derivative of a pulse generated by a constant Hamiltonian, which is a Pauli sentence, is computed correctly.""" import jax @@ -945,7 +946,7 @@ def test_constant_ry_rescaled(self, num_split_times, t): op = qml.evolve(ham_single_q_const)(params, t) tape = qml.tape.QuantumScript([op], [qml.expval(qml.PauliZ(0))]) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) # Prefactor due to the generator being a Pauli sentence prefactor = np.sqrt(0.85) # Effective rotation parameter @@ -960,7 +961,7 @@ def test_constant_ry_rescaled(self, num_split_times, t): jax.clear_caches() @pytest.mark.parametrize("t", [0.02, (0.5, 0.6)]) - def test_sin_envelope_rz_expval(self, t): + def test_sin_envelope_rz_expval(self, dev_name, t): """Test that the derivative of a pulse with a sine wave envelope is computed correctly when returning an expectation value.""" import jax @@ -968,7 +969,7 @@ def test_sin_envelope_rz_expval(self, t): T = t if isinstance(t, tuple) else (0, t) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) params = [jnp.array([2.3, -0.245])] ham = self.sine * qml.PauliZ(0) @@ -999,7 +1000,7 @@ def test_sin_envelope_rz_expval(self, t): jax.clear_caches() @pytest.mark.parametrize("t", [0.02, (0.5, 0.6)]) - def test_sin_envelope_rx_probs(self, t): + def test_sin_envelope_rx_probs(self, dev_name, t): """Test that the derivative of a pulse with a sine wave envelope is computed correctly when returning probabilities.""" import jax @@ -1007,7 +1008,7 @@ def test_sin_envelope_rx_probs(self, t): T = t if isinstance(t, tuple) else (0, t) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) params = [jnp.array([2.3, -0.245])] ham = self.sine * qml.PauliX(0) @@ -1040,7 +1041,7 @@ def test_sin_envelope_rx_probs(self, t): jax.clear_caches() @pytest.mark.parametrize("t", [0.02, (0.5, 0.6)]) - def test_sin_envelope_rx_expval_probs(self, t): + def test_sin_envelope_rx_expval_probs(self, dev_name, t): """Test that the derivative of a pulse with a sine wave envelope is computed correctly when returning expectation.""" import jax @@ -1048,7 +1049,7 @@ def test_sin_envelope_rx_expval_probs(self, t): T = t if isinstance(t, tuple) else (0, t) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) params = [jnp.array([2.3, -0.245])] ham = self.sine * qml.PauliX(0) @@ -1085,7 +1086,7 @@ def test_sin_envelope_rx_expval_probs(self, t): jax.clear_caches() @pytest.mark.parametrize("t", [0.02, (0.5, 0.6)]) - def test_pwc_envelope_rx(self, t): + def test_pwc_envelope_rx(self, dev_name, t): """Test that the derivative of a pulse generated by a piecewise constant Hamiltonian is computed correctly.""" import jax @@ -1093,7 +1094,7 @@ def test_pwc_envelope_rx(self, t): T = t if isinstance(t, tuple) else (0, t) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) params = [jnp.array([0.24, 0.9, -0.1, 2.3, -0.245])] op = qml.evolve(qml.pulse.pwc(t) * qml.PauliZ(0))(params, t) tape = qml.tape.QuantumScript([qml.Hadamard(0), op], [qml.expval(qml.PauliX(0))]) @@ -1115,7 +1116,7 @@ def test_pwc_envelope_rx(self, t): jax.clear_caches() @pytest.mark.parametrize("t", [2.0, 3, (0.5, 0.6)]) - def test_constant_commuting(self, t): + def test_constant_commuting(self, dev_name, t): """Test that the derivative of a pulse generated by two constant commuting Hamiltonians is computed correctly.""" import jax @@ -1129,7 +1130,7 @@ def test_constant_commuting(self, t): ) tape = qml.tape.QuantumScript([op], [qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))]) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) r = qml.execute([tape], dev, None) # Effective rotation parameters p = [_p * (T[1] - T[0]) for _p in params] @@ -1145,7 +1146,7 @@ def test_constant_commuting(self, t): assert qml.math.allclose(res, exp_grad) jax.clear_caches() - def test_advanced_pulse(self): + def test_advanced_pulse(self, dev_name): """Test the derivative of a more complex pulse.""" import jax import jax.numpy as jnp @@ -1159,7 +1160,7 @@ def test_advanced_pulse(self): * qml.dot([1.0, 0.4], [qml.PauliY(0) @ qml.PauliY(1), qml.PauliX(0) @ qml.PauliX(1)]) ) params = [jnp.array(1.51), jnp.array(-0.371), jnp.array([0.2, 0.2, -0.4])] - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) @qml.qnode(dev, interface="jax") def qnode(params): @@ -1183,7 +1184,7 @@ def qnode(params): assert all(qml.math.allclose(r, e, rtol=0.4) for r, e in zip(res, exp_grad)) jax.clear_caches() - def test_randomness(self): + def test_randomness(self, dev_name): """Test that the derivative of a pulse is exactly the same when reusing a seed and that it differs when using a different seed.""" import jax @@ -1213,7 +1214,7 @@ def test_randomness(self): else: assert qml.equal(op_a_0, op_a_1) and qml.equal(op_a_0, op_b) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) res_a_0 = fn_a_0(qml.execute(tapes_a_0, dev, None)) res_a_1 = fn_a_1(qml.execute(tapes_a_1, dev, None)) res_b = fn_b(qml.execute(tapes_b, dev, None)) @@ -1222,7 +1223,7 @@ def test_randomness(self): assert not res_a_0 == res_b jax.clear_caches() - def test_two_pulses(self): + def test_two_pulses(self, dev_name): """Test that the derivatives of two pulses in a circuit are computed correctly.""" import jax import jax.numpy as jnp @@ -1233,7 +1234,7 @@ def test_two_pulses(self): ham_1 = qml.dot([0.3, jnp.polyval], [qml.PauliZ(0), qml.PauliY(0) @ qml.PauliY(1)]) params_0 = [jnp.array(1.51), jnp.array(-0.371)] params_1 = [jnp.array([0.2, 0.2, -0.4])] - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) @qml.qnode(dev, interface="jax") def qnode(params_0, params_1): @@ -1262,13 +1263,13 @@ def qnode(params_0, params_1): (qml.Hamiltonian([0.25, 1.2], [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1)]), 8, 1.45), ], ) - def test_with_jit(self, generator, exp_num_tapes, prefactor): + def test_with_jit(self, dev_name, generator, exp_num_tapes, prefactor): """Test that the stochastic parameter-shift rule works with JITting.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=len(generator.wires)) + dev = qml.device(dev_name, wires=len(generator.wires)) T = (0.2, 0.5) ham_single_q_const = qml.dot([qml.pulse.constant], [generator]) meas = [qml.expval(qml.PauliZ(0))] @@ -1280,7 +1281,7 @@ def fun(params): tape = qml.tape.QuantumScript([op], meas) tapes, fn = stoch_pulse_grad(tape) assert len(tapes) == exp_num_tapes - res = fn(qml.execute(tapes, dev, None)) + res = fn(qml.execute(tapes, dev, "backprop")) return res params = [jnp.array(0.24)] @@ -1293,7 +1294,7 @@ def fun(params): jax.clear_caches() @pytest.mark.parametrize("shots", [None, 100]) - def test_shots_attribute(self, shots): + def test_shots_attribute(self, dev_name, shots): # pylint:disable=unused-argument """Tests that the shots attribute is copied to the new tapes""" tape = qml.tape.QuantumTape([], [qml.expval(qml.PauliZ(0)), qml.probs([1, 2])], shots=shots) with pytest.warns(UserWarning, match="Attempted to compute the gradient of a tape with no"): @@ -1303,13 +1304,14 @@ def test_shots_attribute(self, shots): @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) class TestStochPulseGradQNode: """Test that pulse_generator integrates correctly with QNodes.""" - def test_raises_for_application_to_qnodes(self): + def test_raises_for_application_to_qnodes(self, dev_name): """Test that an error is raised when applying ``stoch_pulse_grad`` to a QNode directly.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @qml.qnode(dev, interface="jax") @@ -1323,14 +1325,14 @@ def circuit(params): # TODO: include the following tests when #4225 is resolved. @pytest.mark.skip("Applying this gradient transform to QNodes directly is not supported.") - def test_qnode_expval_single_par(self): + def test_qnode_expval_single_par(self, dev_name): """Test that a simple qnode that returns an expectation value can be differentiated with pulse_generator.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1350,20 +1352,22 @@ def circuit(params): assert tracker.totals["executions"] == 4 # two shifted tapes, two splitting times +# TODO: add default.qubit once it supports PRNG key @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit.jax"]) class TestStochPulseGradIntegration: """Test that stoch_pulse_grad integrates correctly with QNodes and ML interfaces.""" @pytest.mark.parametrize("shots, tol", [(None, 1e-4), (100, 0.1), ([100, 99], 0.1)]) @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_simple_qnode_expval(self, num_split_times, shots, tol): + def test_simple_qnode_expval(self, dev_name, num_split_times, shots, tol): """Test that a simple qnode that returns an expectation value can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1383,14 +1387,14 @@ def circuit(params): @pytest.mark.parametrize("shots, tol", [(None, 1e-4), (100, 0.1), ([100, 99], 0.1)]) @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_simple_qnode_expval_two_evolves(self, num_split_times, shots, tol): + def test_simple_qnode_expval_two_evolves(self, dev_name, num_split_times, shots, tol): """Test that a simple qnode that returns an expectation value can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T_x = 0.1 T_y = 0.2 ham_x = qml.pulse.constant * qml.PauliX(0) @@ -1414,14 +1418,14 @@ def circuit(params): @pytest.mark.parametrize("shots, tol", [(None, 1e-4), (100, 0.1), ([100, 99], 0.1)]) @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_simple_qnode_probs(self, num_split_times, shots, tol): + def test_simple_qnode_probs(self, dev_name, num_split_times, shots, tol): """Test that a simple qnode that returns an probabilities can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1441,14 +1445,14 @@ def circuit(params): @pytest.mark.parametrize("shots, tol", [(None, 1e-4), (100, 0.1), ([100, 100], 0.1)]) @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_simple_qnode_probs_expval(self, num_split_times, shots, tol): + def test_simple_qnode_probs_expval(self, dev_name, num_split_times, shots, tol): """Test that a simple qnode that returns an probabilities can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1475,13 +1479,13 @@ def circuit(params): @pytest.mark.xfail @pytest.mark.parametrize("num_split_times", [1, 2]) @pytest.mark.parametrize("time_interface", ["python", "numpy", "jax"]) - def test_simple_qnode_jit(self, num_split_times, time_interface): + def test_simple_qnode_jit(self, dev_name, num_split_times, time_interface): """Test that a simple qnode can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = {"python": 0.2, "numpy": np.array(0.2), "jax": jnp.array(0.2)}[time_interface] ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1500,7 +1504,7 @@ def circuit(params, T=None): jax.clear_caches() @pytest.mark.slow - def test_advanced_qnode(self): + def test_advanced_qnode(self, dev_name): """Test that an advanced qnode can be differentiated with stoch_pulse_grad.""" import jax import jax.numpy as jnp @@ -1508,7 +1512,7 @@ def test_advanced_qnode(self): jax.config.update("jax_enable_x64", True) params = [jnp.array(0.21), jnp.array(-0.171), jnp.array([0.05, 0.03, -0.1])] - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) ham = ( qml.pulse.constant * qml.PauliX(0) + (lambda p, t: jnp.sin(p * t)) * qml.PauliZ(0) @@ -1540,7 +1544,7 @@ def ansatz(params): ) jax.clear_caches() - def test_multi_return_broadcasting_multi_shots_raises(self): + def test_multi_return_broadcasting_multi_shots_raises(self, dev_name): """Test that a simple qnode that returns an expectation value and probabilities can be differentiated with stoch_pulse_grad with use_broadcasting.""" import jax @@ -1548,7 +1552,7 @@ def test_multi_return_broadcasting_multi_shots_raises(self): jax.config.update("jax_enable_x64", True) shots = [100, 100] - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1571,14 +1575,14 @@ def circuit(params): # TODO: delete error test above and uncomment the following test case once #2690 is resolved. @pytest.mark.parametrize("shots, tol", [(None, 1e-4), (100, 0.1)]) # , ([100, 100], 0.1)]) @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_qnode_probs_expval_broadcasting(self, num_split_times, shots, tol): + def test_qnode_probs_expval_broadcasting(self, dev_name, num_split_times, shots, tol): """Test that a simple qnode that returns an expectation value and probabilities can be differentiated with stoch_pulse_grad with use_broadcasting.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) + dev = qml.device(dev_name, wires=1, shots=shots, prng_key=jax.random.PRNGKey(74)) T = 0.2 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) @@ -1607,13 +1611,13 @@ def circuit(params): jax.clear_caches() @pytest.mark.parametrize("num_split_times", [1, 2]) - def test_broadcasting_coincides_with_nonbroadcasting(self, num_split_times): + def test_broadcasting_coincides_with_nonbroadcasting(self, dev_name, num_split_times): """Test that using broadcasting or not does not change the result.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) T = 0.2 def f(p, t): @@ -1651,7 +1655,7 @@ def ansatz(params): assert qml.math.allclose(j0, j1) jax.clear_caches() - def test_with_drive_exact(self): + def test_with_drive_exact(self, dev_name): """Test that a HardwareHamiltonian only containing a drive is differentiated correctly for a constant amplitude and zero frequency and phase.""" import jax @@ -1660,7 +1664,7 @@ def test_with_drive_exact(self): H = qml.pulse.transmon_drive(qml.pulse.constant, 0.0, 0.0, wires=[0]) atol = 1e-5 - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) def ansatz(params): qml.evolve(H, atol=atol)(params, t=timespan) @@ -1676,7 +1680,7 @@ def ansatz(params): assert qml.math.allclose(res, exact, atol=6e-5) jax.clear_caches() - def test_with_drive_approx(self): + def test_with_drive_approx(self, dev_name): """Test that a HardwareHamiltonian only containing a drive is differentiated approximately correctly for a constant phase and zero frequency.""" import jax @@ -1685,7 +1689,7 @@ def test_with_drive_approx(self): H = qml.pulse.transmon_drive(1 / (2 * np.pi), qml.pulse.constant, 0.0, wires=[0]) atol = 1e-5 - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) def ansatz(params): qml.evolve(H, atol=atol)(params, t=timespan) @@ -1710,7 +1714,7 @@ def ansatz(params): jax.clear_caches() @pytest.mark.parametrize("num_params", [1, 2]) - def test_with_two_drives(self, num_params): + def test_with_two_drives(self, dev_name, num_params): """Test that a HardwareHamiltonian only containing two drives is differentiated approximately correctly. The two cases of the parametrization test the cases where reordered parameters @@ -1729,7 +1733,7 @@ def test_with_two_drives(self, num_params): amps[0], qml.pulse.constant, 0.0, wires=[0] ) + qml.pulse.rydberg_drive(amps[1], qml.pulse.constant, 0.0, wires=[1]) atol = 1e-5 - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) def ansatz(params): qml.evolve(H, atol=atol)(params, t=timespan) @@ -1753,19 +1757,21 @@ def ansatz(params): jax.clear_caches() +# TODO: port ParametrizedEvolution to new default.qubit @pytest.mark.jax +@pytest.mark.parametrize("dev_name", ["default.qubit.jax"]) class TestStochPulseGradDiff: """Test that stoch_pulse_grad is differentiable.""" # pylint: disable=too-few-public-methods @pytest.mark.slow - def test_jax(self): + def test_jax(self, dev_name): """Test that stoch_pulse_grad is differentiable with JAX.""" import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=1) + dev = qml.device(dev_name, wires=1) T = 0.5 ham_single_q_const = qml.pulse.constant * qml.PauliY(0) diff --git a/tests/gradients/core/test_vjp.py b/tests/gradients/core/test_vjp.py index 2e3824e99a3..0904d1a19c2 100644 --- a/tests/gradients/core/test_vjp.py +++ b/tests/gradients/core/test_vjp.py @@ -247,7 +247,7 @@ def test_single_expectation_value(self, tol): tapes, fn = qml.gradients.vjp(tape, dy, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert res.shape == (2,) exp = np.array([-np.sin(y) * np.sin(x), np.cos(y) * np.cos(x)]) @@ -274,7 +274,7 @@ def test_multiple_expectation_values(self, tol): tapes, fn = qml.gradients.vjp(tape, dy, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert res.shape == (2,) exp = np.array([-np.sin(x), 2 * np.cos(y)]) @@ -301,7 +301,7 @@ def test_prob_expectation_values(self, tol): tapes, fn = qml.gradients.vjp(tape, dy, param_shift) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert res.shape == (2,) exp = ( @@ -374,10 +374,12 @@ class TestVJPGradients: """Gradient tests for the vjp function""" @pytest.mark.autograd - def test_autograd(self, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, tol): """Tests that the output of the VJP transform can be differentiated using autograd.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x, dy): @@ -387,7 +389,7 @@ def cost_fn(x, dy): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.vjp(tape, dy, param_shift) - vjp = fn(dev.batch_execute(tapes)) + vjp = fn(execute_fn(tapes)) return vjp dy = np.array([-1.0, 0.0, 0.0, 1.0], requires_grad=False) @@ -398,12 +400,13 @@ def cost_fn(x, dy): assert np.allclose(res, qml.jacobian(expected)(params), atol=tol, rtol=0) @pytest.mark.torch - def test_torch(self, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, tol): """Tests that the output of the VJP transform can be differentiated using Torch.""" import torch - dev = qml.device("default.qubit", wires=2) + dev = qml.device(dev_name, wires=2) params_np = np.array([0.543, -0.654], requires_grad=True) params = torch.tensor(params_np, requires_grad=True, dtype=torch.float64) @@ -427,12 +430,14 @@ def test_torch(self, tol): @pytest.mark.tf @pytest.mark.slow - def test_tf(self, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, tol): """Tests that the output of the VJP transform can be differentiated using TF.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params_np = np.array([0.543, -0.654], requires_grad=True) params = tf.Variable(params_np, dtype=tf.float64) @@ -445,7 +450,7 @@ def test_tf(self, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.vjp(tape, dy, param_shift) - vjp = fn(dev.batch_execute(tapes)) + vjp = fn(execute_fn(tapes)) assert np.allclose(vjp, expected(params), atol=tol, rtol=0) @@ -490,13 +495,15 @@ def test_tf(self, tol): @pytest.mark.jax @pytest.mark.slow - def test_jax(self, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, tol): """Tests that the output of the VJP transform can be differentiated using JAX.""" import jax from jax import numpy as jnp - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params_np = np.array([0.543, -0.654], requires_grad=True) params = jnp.array(params_np) @@ -508,7 +515,7 @@ def cost_fn(x): dy = jax.numpy.array([-1.0, 0.0, 0.0, 1.0]) tape.trainable_params = {0, 1} tapes, fn = qml.gradients.vjp(tape, dy, param_shift) - vjp = fn(dev.batch_execute(tapes)) + vjp = fn(execute_fn(tapes)) return vjp res = cost_fn(params) @@ -550,7 +557,7 @@ def test_one_tape_no_trainable_parameters(self): # Even though there are 3 parameters, only two contribute # to the VJP, so only 2*2=4 quantum evals - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) assert res[0] is None assert res[1] is not None @@ -604,7 +611,7 @@ def test_zero_dy(self): dys = [np.array(0.0), np.array(1.0)] v_tapes, fn = qml.gradients.batch_vjp(tapes, dys, param_shift) - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Even though there are 3 parameters, only two contribute # to the VJP, so only 2*2=4 quantum evals @@ -635,7 +642,7 @@ def test_reduction_append(self): dys = [np.array(1.0), np.array(1.0)] v_tapes, fn = qml.gradients.batch_vjp(tapes, dys, param_shift, reduction="append") - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Returned VJPs will be appended to a list, one vjp per tape assert len(res) == 2 @@ -666,7 +673,7 @@ def test_reduction_extend(self): dys = [np.array(1.0), np.array(1.0)] v_tapes, fn = qml.gradients.batch_vjp(tapes, dys, param_shift, reduction="extend") - res = fn(dev.batch_execute(v_tapes)) + res = fn(dev.execute(v_tapes)) # Returned VJPs will be extended into a list. Each element of the returned # list will correspond to a single input parameter of the combined diff --git a/tests/gradients/finite_diff/test_finite_difference.py b/tests/gradients/finite_diff/test_finite_difference.py index 003a3cfe665..0e2a296d4c0 100644 --- a/tests/gradients/finite_diff/test_finite_difference.py +++ b/tests/gradients/finite_diff/test_finite_difference.py @@ -130,7 +130,7 @@ def test_non_differentiable_error(self): dev = qml.device("default.qubit", wires=2) tapes, fn = finite_diff(tape) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert isinstance(res[0], numpy.ndarray) @@ -152,7 +152,7 @@ def test_independent_parameter(self, mocker): tape = qml.tape.QuantumScript.from_queue(q) dev = qml.device("default.qubit", wires=2) tapes, fn = finite_diff(tape) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -413,13 +413,14 @@ def test_independent_parameters(self): tape2 = qml.tape.QuantumScript.from_queue(q2) tapes, fn = finite_diff(tape1, approx_order=1) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter (2 executions) - assert dev.num_executions == 2 + assert tracker.latest["executions"] == 2 tapes, fn = finite_diff(tape2, approx_order=1) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) exp = -np.sin(1) @@ -564,7 +565,7 @@ def test_ragged_output(self, approx_order, strategy, validate): tapes, fn = finite_diff( tape, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) @@ -597,7 +598,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate, tol): tapes, fn = finite_diff( tape, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -634,7 +635,7 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, strategy=strategy, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -671,7 +672,7 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, tapes, fn = finite_diff( tape, argnum=1, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -712,7 +713,7 @@ def test_multiple_expectation_value_with_argnum_one( tapes, fn = finite_diff( tape, argnum=1, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert isinstance(res[0], tuple) @@ -738,7 +739,7 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate, tol tapes, fn = finite_diff( tape, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -773,7 +774,7 @@ def test_var_expectation_values(self, approx_order, strategy, validate, tol): tapes, fn = finite_diff( tape, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -808,7 +809,7 @@ def test_prob_expectation_values(self, approx_order, strategy, validate, tol): tapes, fn = finite_diff( tape, approx_order=approx_order, strategy=strategy, validate_params=validate ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -854,10 +855,12 @@ class TestFiniteDiffGradients: """Test that the transform is differentiable""" @pytest.mark.autograd - def test_autograd(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x): @@ -870,7 +873,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(execute_fn(tapes))) return jac res = qml.jacobian(cost_fn)(params) @@ -885,10 +888,12 @@ def cost_fn(x): assert np.allclose(res, expected, atol=tol, rtol=0) @pytest.mark.autograd - def test_autograd_ragged(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd_ragged(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform of a ragged tape can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x): @@ -902,7 +907,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac[1][0] x, y = params @@ -912,12 +917,14 @@ def cost_fn(x): @pytest.mark.tf @pytest.mark.slow - def test_tf(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) with tf.GradientTape(persistent=True) as t: @@ -930,7 +937,7 @@ def test_tf(self, approx_order, strategy, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac_0, jac_1 = fn(dev.batch_execute(tapes)) + jac_0, jac_1 = fn(execute_fn(tapes)) x, y = 1.0 * params @@ -946,12 +953,14 @@ def test_tf(self, approx_order, strategy, tol): assert np.allclose([res_0, res_1], expected, atol=tol, rtol=0) @pytest.mark.tf - def test_tf_ragged(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf_ragged(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform of a ragged tape can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) with tf.GradientTape(persistent=True) as t: @@ -966,7 +975,7 @@ def test_tf_ragged(self, approx_order, strategy, tol): tape.trainable_params = {0, 1} tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(execute_fn(tapes))[1][0] x, y = 1.0 * params @@ -977,12 +986,14 @@ def test_tf_ragged(self, approx_order, strategy, tol): assert np.allclose(res_01[0], expected, atol=tol, rtol=0) @pytest.mark.torch - def test_torch(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform can be differentiated using Torch, yielding second derivatives.""" import torch - dev = qml.device("default.qubit.torch", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = torch.tensor([0.543, -0.654], dtype=torch.float64, requires_grad=True) def cost_fn(params): @@ -994,7 +1005,7 @@ def cost_fn(params): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1012,7 +1023,8 @@ def cost_fn(params): assert np.allclose(hess[1].detach().numpy(), expected[1], atol=tol, rtol=0) @pytest.mark.jax - def test_jax(self, approx_order, strategy, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, approx_order, strategy, tol): """Tests that the output of the finite-difference transform can be differentiated using JAX, yielding second derivatives.""" import jax @@ -1021,7 +1033,8 @@ def test_jax(self, approx_order, strategy, tol): config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = jnp.array([0.543, -0.654]) def cost_fn(x): @@ -1034,7 +1047,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = finite_diff(tape, n=1, approx_order=approx_order, strategy=strategy) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res = jax.jacobian(cost_fn)(params) diff --git a/tests/gradients/finite_diff/test_finite_difference_shot_vec.py b/tests/gradients/finite_diff/test_finite_difference_shot_vec.py index d335db4068f..b2179096206 100644 --- a/tests/gradients/finite_diff/test_finite_difference_shot_vec.py +++ b/tests/gradients/finite_diff/test_finite_difference_shot_vec.py @@ -60,7 +60,7 @@ def test_non_differentiable_error(self): dev = qml.device("default.qubit", wires=2, shots=default_shot_vector) tapes, fn = finite_diff(tape, h=h_val) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -87,7 +87,7 @@ def test_independent_parameter_skipped(self, mocker): tape = qml.tape.QuantumScript.from_queue(q, shots=default_shot_vector) dev = qml.device("default.qubit", wires=2, shots=default_shot_vector) tapes, fn = finite_diff(tape, h=h_val) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -270,7 +270,7 @@ def circuit(params): params = np.array([0.5, 0.5, 0.5], requires_grad=True) all_result = qml.gradients.finite_diff(circuit, h=h_val)(params) - assert len(all_result) == len(default_shot_vector) + assert len(all_result) == len(many_shots_shot_vector) for result in all_result: assert isinstance(result, tuple) @@ -358,20 +358,21 @@ def test_independent_parameters(self): tape2 = qml.tape.QuantumScript.from_queue(q2, shots=many_shots_shot_vector) tapes, fn = finite_diff(tape1, approx_order=1, h=h_val) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter (2 executions) - assert dev.num_executions == 2 + assert tracker.latest["executions"] == 2 tapes, fn = finite_diff(tape2, approx_order=1, h=h_val) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) exp = -np.sin(1) assert isinstance(j1, tuple) - assert len(j1) == len(default_shot_vector) + assert len(j1) == len(many_shots_shot_vector) assert isinstance(j2, tuple) - assert len(j2) == len(default_shot_vector) + assert len(j2) == len(many_shots_shot_vector) for _j1, _j2 in zip(j1, j2): assert np.allclose(_j1, [exp, 0], atol=finite_diff_shot_vec_tol) @@ -519,7 +520,7 @@ def test_ragged_output(self, approx_order, strategy, validate): strategy=strategy, validate_params=validate, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(many_shots_shot_vector) @@ -551,7 +552,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate): qml.CNOT(wires=[0, 1]) qml.expval(qml.PauliZ(0) @ qml.PauliX(1)) - tape = qml.tape.QuantumScript.from_queue(q, shots=default_shot_vector) + tape = qml.tape.QuantumScript.from_queue(q, shots=many_shots_shot_vector) tapes, fn = finite_diff( tape, approx_order=approx_order, @@ -559,10 +560,10 @@ def test_single_expectation_value(self, approx_order, strategy, validate): validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) expected = np.array([[-np.sin(y) * np.sin(x), np.cos(y) * np.cos(x)]]) for res in all_res: @@ -601,10 +602,10 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) expected = np.array([[-np.sin(y) * np.sin(x), np.cos(y) * np.cos(x)]]) for res in all_res: @@ -647,10 +648,10 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) expected = [0, np.cos(y) * np.cos(x)] @@ -674,6 +675,9 @@ def test_probs_expval_with_argnum_one(self, approx_order, strategy, validate): This test relies on the fact that exactly one term of the estimated jacobian will match the expected analytical value. """ + if approx_order == 4 and strategy != "center": + pytest.skip("The latest default.qubit is unreliable with an approx_order of 4") + dev = qml.device("default.qubit", wires=2, shots=many_shots_shot_vector) x = 0.543 y = -0.654 @@ -695,10 +699,10 @@ def test_probs_expval_with_argnum_one(self, approx_order, strategy, validate): validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) cx, sx, cy, sy = np.cos(x / 2), np.sin(x / 2), np.cos(y / 2), np.sin(y / 2) # probability vector is [cx**2 * cy**2, cx**2 * sy**2, sx**2 * sy**2, sx**2 * cy**2] @@ -734,10 +738,10 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate): validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) for res in all_res: assert isinstance(res, tuple) @@ -777,10 +781,10 @@ def test_var_expectation_values(self, approx_order, strategy, validate): validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) for res in all_res: assert isinstance(res, tuple) @@ -822,10 +826,10 @@ def test_prob_expectation_values(self, approx_order, strategy, validate): validate_params=validate, h=h_val, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) for res in all_res: assert isinstance(res, tuple) @@ -873,10 +877,12 @@ class TestFiniteDiffGradients: """Test that the transform is differentiable""" @pytest.mark.autograd - def test_autograd(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x): @@ -895,13 +901,13 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(execute_fn(tapes))) return jac all_res = qml.jacobian(cost_fn)(params) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) for res in all_res: x, y = params @@ -915,10 +921,12 @@ def cost_fn(x): assert np.allclose(res, expected, atol=finite_diff_shot_vec_tol, rtol=0) @pytest.mark.autograd - def test_autograd_ragged(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd_ragged(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform of a ragged tape can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x): @@ -938,14 +946,14 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac[1][0] x, y = params all_res = qml.jacobian(cost_fn)(params)[0] assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) for res in all_res: expected = np.array([-np.cos(x) * np.cos(y) / 2, np.sin(x) * np.sin(y) / 2]) @@ -953,12 +961,14 @@ def cost_fn(x): @pytest.mark.tf @pytest.mark.slow - def test_tf(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) with tf.GradientTape(persistent=True) as t: @@ -977,7 +987,7 @@ def test_tf(self, approx_order, strategy): strategy=strategy, h=h_val, ) - jac_0, jac_1 = fn(dev.batch_execute(tapes)) + jac_0, jac_1 = fn(execute_fn(tapes)) x, y = 1.0 * params @@ -993,12 +1003,14 @@ def test_tf(self, approx_order, strategy): assert np.allclose([res_0, res_1], expected, atol=finite_diff_shot_vec_tol, rtol=0) @pytest.mark.tf - def test_tf_ragged(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf_ragged(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform of a ragged tape can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) with tf.GradientTape(persistent=True) as t: @@ -1019,7 +1031,7 @@ def test_tf_ragged(self, approx_order, strategy): h=h_val, ) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(execute_fn(tapes))[1][0] x, y = 1.0 * params @@ -1030,12 +1042,14 @@ def test_tf_ragged(self, approx_order, strategy): assert np.allclose(res_01[0], expected, atol=finite_diff_shot_vec_tol, rtol=0) @pytest.mark.torch - def test_torch(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform can be differentiated using Torch, yielding second derivatives.""" import torch - dev = qml.device("default.qubit.torch", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = torch.tensor([0.543, -0.654], dtype=torch.float64, requires_grad=True) def cost_fn(params): @@ -1053,7 +1067,7 @@ def cost_fn(params): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1075,7 +1089,8 @@ def cost_fn(params): ) @pytest.mark.jax - def test_jax(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, approx_order, strategy): """Tests that the output of the finite-difference transform can be differentiated using JAX, yielding second derivatives.""" import jax @@ -1084,7 +1099,8 @@ def test_jax(self, approx_order, strategy): config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = jnp.array([0.543, -0.654]) def cost_fn(x): @@ -1103,13 +1119,13 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac all_res = jax.jacobian(cost_fn)(params) assert isinstance(all_res, tuple) - assert len(all_res) == len(default_shot_vector) + assert len(all_res) == len(many_shots_shot_vector) x, y = params expected = np.array( @@ -1176,7 +1192,7 @@ def test_1_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0} tapes, fn = qml.gradients.finite_diff(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1210,7 +1226,7 @@ def test_1_N(self, shot_vec, op_wire): tape.trainable_params = {0} tapes, fn = qml.gradients.finite_diff(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1244,7 +1260,7 @@ def test_N_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.finite_diff(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1286,7 +1302,7 @@ def test_N_N(self, shot_vec, op_wires): tape.trainable_params = {0, 1, 2, 3, 4} tapes, fn = qml.gradients.finite_diff(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) diff --git a/tests/gradients/finite_diff/test_spsa_gradient.py b/tests/gradients/finite_diff/test_spsa_gradient.py index 44a149041cb..5897aed4b88 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient.py +++ b/tests/gradients/finite_diff/test_spsa_gradient.py @@ -201,7 +201,7 @@ def test_non_differentiable_error(self): dev = qml.device("default.qubit", wires=2) tapes, fn = spsa_grad(tape) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -225,7 +225,7 @@ def test_independent_parameter(self, num_directions, mocker): tape = qml.tape.QuantumScript.from_queue(q) dev = qml.device("default.qubit", wires=2) tapes, fn = spsa_grad(tape, num_directions=num_directions) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -498,13 +498,14 @@ def test_independent_parameters(self): tapes, fn = spsa_grad( tape1, approx_order=1, strategy="forward", num_directions=n1, sampler_rng=rng ) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) - assert len(tapes) == dev.num_executions == n1 + 1 + assert len(tapes) == tracker.latest["executions"] == n1 + 1 n2 = 11 tapes, fn = spsa_grad(tape2, num_directions=n2, sampler_rng=rng) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) assert len(tapes) == 2 * n2 @@ -657,7 +658,7 @@ def test_ragged_output(self, approx_order, strategy, validate): num_directions=11, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) @@ -696,7 +697,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate, tol): sampler=coordinate_sampler, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -740,7 +741,7 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, sampler=coordinate_sampler, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -789,7 +790,7 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, sampler=coordinate_sampler, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -834,7 +835,7 @@ def test_multiple_expectation_value_with_argnum_one(self, approx_order, strategy sampler=coordinate_sampler, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert isinstance(res[0], tuple) @@ -865,7 +866,7 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate, tol sampler=coordinate_sampler, validate_params=validate, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -910,7 +911,7 @@ def test_var_expectation_values(self, approx_order, strategy, validate, tol): sampler=coordinate_sampler, num_directions=2, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -955,7 +956,7 @@ def test_prob_expectation_values(self, approx_order, strategy, validate, tol): sampler=coordinate_sampler, num_directions=2, ) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -1007,10 +1008,12 @@ class TestSpsaGradientDifferentiation: """Test that the transform is differentiable""" @pytest.mark.autograd - def test_autograd(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) rng = np.random.default_rng(42) @@ -1026,7 +1029,7 @@ def cost_fn(x): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(execute_fn(tapes))) if sampler is coordinate_sampler: jac *= 2 return jac @@ -1043,10 +1046,12 @@ def cost_fn(x): assert np.allclose(res, expected, atol=atol, rtol=0) @pytest.mark.autograd - def test_autograd_ragged(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd_ragged(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform of a ragged tape can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) rng = np.random.default_rng(42) @@ -1063,7 +1068,7 @@ def cost_fn(x): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac = tuple(tuple(2 * _j for _j in _jac) for _jac in jac) return jac[1][0] @@ -1075,12 +1080,14 @@ def cost_fn(x): @pytest.mark.tf @pytest.mark.slow - def test_tf(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) rng = np.random.default_rng(42) @@ -1096,7 +1103,7 @@ def test_tf(self, sampler, num_directions, atol): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac_0, jac_1 = fn(dev.batch_execute(tapes)) + jac_0, jac_1 = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac_0 *= 2 jac_1 *= 2 @@ -1116,12 +1123,14 @@ def test_tf(self, sampler, num_directions, atol): @pytest.mark.tf @pytest.mark.slow - def test_tf_ragged(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf_ragged(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform of a ragged tape can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) rng = np.random.default_rng(42) @@ -1139,7 +1148,7 @@ def test_tf_ragged(self, sampler, num_directions, atol): tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(execute_fn(tapes))[1][0] if sampler is coordinate_sampler: jac_01 *= 2 @@ -1152,12 +1161,14 @@ def test_tf_ragged(self, sampler, num_directions, atol): assert np.allclose(res_01[0], expected, atol=atol, rtol=0) @pytest.mark.torch - def test_torch(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform can be differentiated using Torch, yielding second derivatives.""" import torch - dev = qml.device("default.qubit.torch", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = torch.tensor([0.543, -0.654], dtype=torch.float64, requires_grad=True) rng = np.random.default_rng(42) @@ -1172,7 +1183,7 @@ def cost_fn(params): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac = tuple(2 * _jac for _jac in jac) return jac @@ -1192,7 +1203,8 @@ def cost_fn(params): assert np.allclose(hess[1].detach().numpy(), expected[1], atol=atol, rtol=0) @pytest.mark.jax - def test_jax(self, sampler, num_directions, atol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, sampler, num_directions, atol): """Tests that the output of the SPSA gradient transform can be differentiated using JAX, yielding second derivatives.""" import jax @@ -1201,7 +1213,8 @@ def test_jax(self, sampler, num_directions, atol): config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = jnp.array([0.543, -0.654]) rng = np.random.default_rng(42) @@ -1217,7 +1230,7 @@ def cost_fn(x): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac = tuple(2 * _jac for _jac in jac) return jac diff --git a/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py b/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py index 3d8fa8017df..f04dcd7ca25 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py +++ b/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py @@ -71,7 +71,7 @@ def test_non_differentiable_error(self): dev = qml.device("default.qubit", wires=2, shots=default_shot_vector) tapes, fn = spsa_grad(tape, h=h_val) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -99,7 +99,7 @@ def test_independent_parameter(self, num_directions, mocker): tape = qml.tape.QuantumScript.from_queue(q, shots=default_shot_vector) dev = qml.device("default.qubit", wires=2, shots=default_shot_vector) tapes, fn = spsa_grad(tape, h=h_val, num_directions=num_directions) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -409,9 +409,10 @@ def test_independent_parameters(self): h=h_val, sampler_rng=rng, ) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) - assert len(tapes) == dev.num_executions == n1 + 1 + assert len(tapes) == tracker.latest["executions"] == n1 + 1 n2 = 3 tapes, fn = spsa_grad( @@ -422,7 +423,7 @@ def test_independent_parameters(self): num_directions=n2, sampler_rng=rng, ) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) assert len(tapes) == n2 + 1 @@ -584,7 +585,7 @@ def test_ragged_output(self, approx_order, strategy, validate): num_directions=3, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(many_shots_shot_vector) @@ -628,7 +629,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate): sampler=coordinate_sampler, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -677,7 +678,7 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, h=h_val, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -730,7 +731,7 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, h=h_val, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -784,7 +785,7 @@ def test_multiple_expectation_value_with_argnum_one(self, approx_order, strategy h=h_val, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -824,7 +825,7 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate): num_directions=20, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -878,7 +879,7 @@ def test_var_expectation_values(self, approx_order, strategy, validate): sampler=coordinate_sampler, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -933,7 +934,7 @@ def test_prob_expectation_values(self, approx_order, strategy, validate): h=h_val, sampler_rng=rng, ) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(default_shot_vector) @@ -991,10 +992,12 @@ class TestSpsaGradientDifferentiation: """Test that the transform is differentiable""" @pytest.mark.autograd - def test_autograd(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) rng = np.random.default_rng(42) @@ -1015,7 +1018,7 @@ def cost_fn(x): h=h_val, sampler_rng=rng, ) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(execute_fn(tapes))) return jac all_res = qml.jacobian(cost_fn)(params) @@ -1035,10 +1038,12 @@ def cost_fn(x): assert np.allclose(res, expected, atol=spsa_shot_vec_tol, rtol=0) @pytest.mark.autograd - def test_autograd_ragged(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd_ragged(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform of a ragged tape can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) rng = np.random.default_rng(42) @@ -1060,7 +1065,7 @@ def cost_fn(x): h=h_val, sampler_rng=rng, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac[1][0] x, y = params @@ -1075,12 +1080,14 @@ def cost_fn(x): @pytest.mark.tf @pytest.mark.slow - def test_tf(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) rng = np.random.default_rng(42) @@ -1101,7 +1108,7 @@ def test_tf(self, approx_order, strategy): h=h_val, sampler_rng=rng, ) - jac_0, jac_1 = fn(dev.batch_execute(tapes)) + jac_0, jac_1 = fn(execute_fn(tapes)) x, y = 1.0 * params @@ -1117,12 +1124,14 @@ def test_tf(self, approx_order, strategy): assert np.allclose([res_0, res_1], expected, atol=spsa_shot_vec_tol, rtol=0) @pytest.mark.tf - def test_tf_ragged(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf_ragged(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform of a ragged tape can be differentiated using TF, yielding second derivatives.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = tf.Variable([0.543, -0.654], dtype=tf.float64) rng = np.random.default_rng(42) @@ -1145,7 +1154,7 @@ def test_tf_ragged(self, approx_order, strategy): sampler_rng=rng, ) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(execute_fn(tapes))[1][0] x, y = 1.0 * params @@ -1156,12 +1165,14 @@ def test_tf_ragged(self, approx_order, strategy): assert np.allclose(res_01[0], expected, atol=spsa_shot_vec_tol, rtol=0) @pytest.mark.torch - def test_torch(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform can be differentiated using Torch, yielding second derivatives.""" import torch - dev = qml.device("default.qubit.torch", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = torch.tensor([0.543, -0.654], dtype=torch.float64, requires_grad=True) rng = np.random.default_rng(42) @@ -1181,7 +1192,7 @@ def cost_fn(params): h=h_val, sampler_rng=rng, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1199,7 +1210,8 @@ def cost_fn(params): assert np.allclose(hess[1].detach().numpy(), expected[1], atol=spsa_shot_vec_tol, rtol=0) @pytest.mark.jax - def test_jax(self, approx_order, strategy): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, approx_order, strategy): """Tests that the output of the SPSA gradient transform can be differentiated using JAX, yielding second derivatives.""" import jax @@ -1208,7 +1220,8 @@ def test_jax(self, approx_order, strategy): config.update("jax_enable_x64", True) - dev = qml.device("default.qubit.jax", wires=2, shots=many_shots_shot_vector) + dev = qml.device(dev_name, wires=2, shots=many_shots_shot_vector) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = jnp.array([0.543, -0.654]) rng = np.random.default_rng(42) @@ -1229,7 +1242,7 @@ def cost_fn(x): h=h_val, sampler_rng=rng, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac all_res = jax.jacobian(cost_fn)(params) @@ -1302,7 +1315,7 @@ def test_1_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0} tapes, fn = spsa_grad(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1336,7 +1349,7 @@ def test_1_N(self, shot_vec, op_wire): tape.trainable_params = {0} tapes, fn = spsa_grad(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1370,7 +1383,7 @@ def test_N_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -1409,7 +1422,7 @@ def test_N_N(self, shot_vec, op_wires): tape.trainable_params = {0, 1, 2, 3, 4} tapes, fn = spsa_grad(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) diff --git a/tests/gradients/parameter_shift/test_parameter_shift.py b/tests/gradients/parameter_shift/test_parameter_shift.py index a8e0aaa1858..d483c065837 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift.py +++ b/tests/gradients/parameter_shift/test_parameter_shift.py @@ -315,7 +315,7 @@ def test_multi_measure_partitioned_shots_par_shapes(self, g, par_shapes): def grad_fn(tape, dev, fn=qml.gradients.param_shift, **kwargs): """Utility function to automate execution and processing of gradient tapes""" tapes, fn = fn(tape, **kwargs) - return fn(dev.batch_execute(tapes)) + return fn(dev.execute(tapes)) class TestParamShift: @@ -370,7 +370,7 @@ def test_independent_parameter(self, mocker): assert len(tapes) == 2 assert tapes[0].batch_size == tapes[1].batch_size == None - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 assert res[0].shape == () @@ -761,7 +761,7 @@ def test_f0_provided(self, y_wire): # one tape per parameter that impacts the expval assert len(tapes) == 2 if y_wire == 0 else 1 - fn(dev.batch_execute(tapes)) + fn(dev.execute(tapes)) def test_op_with_custom_unshifted_term(self): """Test that an operation with a gradient recipe that depends on @@ -798,7 +798,7 @@ class RX(qml.RX): assert tape.operations[0].data[0] == x[0] + expected[0] assert tape.operations[1].data[0] == x[1] + expected[1] - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) exp = np.stack([-np.sin(x[0] + x[1]), -np.sin(x[0] + x[1]) + 0.2 * np.cos(x[0] + x[1])]) assert len(grad) == len(exp) for ( @@ -825,15 +825,16 @@ def test_independent_parameters_analytic(self): tape2 = qml.tape.QuantumScript.from_queue(q2) tapes, fn = qml.gradients.param_shift(tape1) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) # We should only be executing the device twice: Two shifted evaluations to differentiate # one parameter overall, as the other parameter does not impact the returned measurement. - assert dev.num_executions == 2 + assert tracker.latest["executions"] == 2 tapes, fn = qml.gradients.param_shift(tape2) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) exp = -np.sin(1) @@ -863,7 +864,7 @@ def test_grad_recipe_parameter_dependent(self): assert qml.math.allclose(tapes[0].operations[0].data[0], 0) assert qml.math.allclose(tapes[1].operations[0].data[0], 2 * x) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) assert np.allclose(grad, -np.sin(x)) def test_error_no_diff_info(self): @@ -946,7 +947,7 @@ def test_with_single_parameter_broadcasted(self, dim, pos): assert np.allclose([t.batch_size for t in tapes], dim) dev = qml.device("default.qubit", wires=2) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -974,7 +975,7 @@ def test_with_multiple_parameters_broadcasted(self, dim, argnum): assert np.allclose([t.batch_size for t in tapes], dim) dev = qml.device("default.qubit", wires=2) - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 3 @@ -1001,7 +1002,7 @@ def test_independent_parameter(self, mocker): assert len(tapes) == 1 assert tapes[0].batch_size == 2 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 assert res[0].shape == () assert res[1].shape == () @@ -1080,15 +1081,16 @@ def test_independent_parameters_analytic(self): tape2 = qml.tape.QuantumScript.from_queue(q2) tapes, fn = qml.gradients.param_shift(tape1, broadcast=True) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter # (1 broadcasted execution) - assert dev.num_executions == 1 + assert tracker.latest["executions"] == 1 tapes, fn = qml.gradients.param_shift(tape2, broadcast=True) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) exp = -np.sin(1) @@ -1122,7 +1124,7 @@ def fail(*args, **kwargs): assert tapes[0].batch_size == 2 assert qml.math.allclose(tapes[0].operations[0].data[0], [0, 2 * x]) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) assert np.allclose(grad, -np.sin(x)) @@ -1153,12 +1155,12 @@ def test_pauli_rotation_gradient(self, mocker, G, theta, shift, tol): tapes, fn = qml.gradients.param_shift(tape, shifts=[(shift,)]) assert len(tapes) == 2 - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) tape_fwd = tape.bind_new_parameters([theta + np.pi / 2], [1]) tape_bwd = tape.bind_new_parameters([theta - np.pi / 2], [1]) - manualgrad_val = np.subtract(*dev.batch_execute([tape_fwd, tape_bwd])) / 2 + manualgrad_val = np.subtract(*dev.execute([tape_fwd, tape_bwd])) / 2 assert np.allclose(autograd_val, manualgrad_val, atol=tol, rtol=0) assert isinstance(autograd_val, np.ndarray) @@ -1167,7 +1169,7 @@ def test_pauli_rotation_gradient(self, mocker, G, theta, shift, tol): assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert np.allclose(autograd_val, numeric_val, atol=tol, rtol=0) @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, 2 * np.pi, 7)) @@ -1190,7 +1192,7 @@ def test_Rot_gradient(self, mocker, theta, shift, tol): num_params = len(tape.trainable_params) assert len(tapes) == 2 * num_params - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) assert isinstance(autograd_val, tuple) assert len(autograd_val) == num_params @@ -1215,7 +1217,7 @@ def test_Rot_gradient(self, mocker, theta, shift, tol): assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for a_val, n_val in zip(autograd_val, numeric_val): assert np.allclose(a_val, n_val, atol=tol, rtol=0) @@ -1237,12 +1239,12 @@ def test_controlled_rotation_gradient(self, G, tol): assert np.allclose(res, -np.cos(b / 2), atol=tol, rtol=0) tapes, fn = qml.gradients.param_shift(tape) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.sin(b / 2) / 2 assert np.allclose(grad, expected, atol=tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert np.allclose(grad, numeric_val, atol=tol, rtol=0) @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, np.pi, 7)) @@ -1267,7 +1269,7 @@ def test_CRot_gradient(self, theta, tol): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 * len(tape.trainable_params) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.array( [ 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), @@ -1281,7 +1283,7 @@ def test_CRot_gradient(self, theta, tol): assert np.allclose(g, expected[idx], atol=tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for idx, g in enumerate(grad): assert np.allclose(g, numeric_val[idx], atol=tol, rtol=0) @@ -1373,7 +1375,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {1} - return fn(dev.batch_execute(tapes)) + return fn(dev.execute(tapes)) res = cost_fn(params) @@ -1402,10 +1404,12 @@ def cost_fn(params): # assert np.allclose(jac[1, 1, 1], -2 * np.cos(2 * y), atol=tol, rtol=0) @pytest.mark.autograd - def test_fallback_single_meas(self, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback_single_meas(self, dev_name, mocker): """Test that fallback gradient functions are correctly used for a single measurement.""" spy = mocker.spy(qml.gradients, "finite_diff") - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -1425,7 +1429,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {1} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) res = cost_fn(params) @@ -1442,10 +1446,12 @@ def cost_fn(params): @pytest.mark.autograd @pytest.mark.parametrize("RX, RY, argnum", [(RX_with_F, qml.RY, 0), (qml.RX, RY_with_F, 1)]) - def test_fallback_probs(self, RX, RY, argnum, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback_probs(self, dev_name, RX, RY, argnum, mocker): """Test that fallback gradient functions are correctly used with probs""" spy = mocker.spy(qml.gradients, "finite_diff") - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -1467,7 +1473,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {argnum} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) res = cost_fn(params) @@ -1524,13 +1530,15 @@ def cost_fn(params): assert np.allclose(res[1][1], probs_expected[:, 1]) @pytest.mark.autograd - def test_all_fallback(self, mocker, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_all_fallback(self, dev_name, mocker, tol): """Test that *only* the fallback logic is called if no parameters support the parameter-shift rule""" spy_fd = mocker.spy(qml.gradients, "finite_diff") spy_ps = mocker.spy(qml.gradients.parameter_shift, "expval_param_shift") - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -1548,7 +1556,7 @@ def test_all_fallback(self, mocker, tol): spy_fd.assert_called() spy_ps.assert_not_called() - res = fn(dev.batch_execute(tapes)) + res = fn(execute_fn(tapes)) assert isinstance(res, tuple) assert res[0].shape == () @@ -1574,7 +1582,7 @@ def test_single_expectation_value(self, tol): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 assert not isinstance(res[0], tuple) assert not isinstance(res[1], tuple) @@ -1619,7 +1627,7 @@ def test_multiple_expectation_values(self, tol): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 assert len(res[0]) == 2 assert len(res[1]) == 2 @@ -1646,7 +1654,7 @@ def test_var_expectation_values(self, tol): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 5 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 assert len(res[0]) == 2 assert len(res[1]) == 2 @@ -1675,7 +1683,7 @@ def test_prob_expectation_values(self): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 for r in res: @@ -1732,13 +1740,13 @@ def test_involutory_variance_single_param(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, np.ndarray) assert gradA.shape == () assert len(tapes) == 1 + 2 * 1 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = 2 * np.sin(a) * np.cos(a) @@ -1765,7 +1773,7 @@ def test_involutory_variance_multi_param(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, tuple) assert isinstance(gradA[0], np.ndarray) @@ -1777,7 +1785,7 @@ def test_involutory_variance_multi_param(self, tol): assert len(tapes) == 1 + 2 * 2 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 3 expected = 2 * np.sin(a + b) * np.cos(a + b) @@ -1806,13 +1814,13 @@ def test_non_involutory_variance_single_param(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, np.ndarray) assert gradA.shape == () assert len(tapes) == 1 + 4 * 1 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = -35 * np.sin(2 * a) - 12 * np.cos(2 * a) @@ -1840,7 +1848,7 @@ def test_non_involutory_variance_multi_param(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, tuple) assert isinstance(gradA[0], np.ndarray) @@ -1851,7 +1859,7 @@ def test_non_involutory_variance_multi_param(self, tol): assert len(tapes) == 1 + 4 * 2 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 3 expected = -35 * np.sin(2 * (a + b)) - 12 * np.cos(2 * (a + b)) @@ -1884,11 +1892,11 @@ def test_involutory_and_noninvolutory_variance_single_param(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert len(tapes) == 1 + 4 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 1 + 1 expected = [2 * np.sin(a) * np.cos(a), 0] @@ -1937,7 +1945,7 @@ def test_var_and_probs_single_param(self, ind): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, tuple) assert len(gradA) == 3 @@ -1987,7 +1995,7 @@ def test_var_and_probs_multi_params(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, tuple) assert len(gradA) == 3 @@ -2117,10 +2125,10 @@ def test_expval_and_variance_single_param(self, tol): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) expected = np.array([2 * np.cos(a) * np.sin(a), -np.cos(b) * np.sin(a), 0]) assert isinstance(gradA, tuple) @@ -2164,10 +2172,10 @@ def test_expval_and_variance_multi_param(self, tol): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) expected = np.array( [ @@ -2238,10 +2246,10 @@ def test_projector_variance(self, state, tol): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) expected = np.array( [ @@ -2432,7 +2440,7 @@ def test_multi_measure_no_warning(self): tape = qml.tape.QuantumScript.from_queue(q) with warnings.catch_warnings(record=True) as record: tapes, fn = qml.gradients.param_shift(tape) - fn(dev.batch_execute(tapes)) + fn(dev.execute(tapes)) assert len(record) == 0 @@ -2463,18 +2471,18 @@ def test_pauli_rotation_gradient(self, mocker, G, theta, shift, tol): assert len(tapes) == 1 assert tapes[0].batch_size == 2 - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) tape_fwd = tape.bind_new_parameters([theta + np.pi / 2], [1]) tape_bwd = tape.bind_new_parameters([theta - np.pi / 2], [1]) - manualgrad_val = np.subtract(*dev.batch_execute([tape_fwd, tape_bwd])) / 2 + manualgrad_val = np.subtract(*dev.execute([tape_fwd, tape_bwd])) / 2 assert np.allclose(autograd_val, manualgrad_val, atol=tol, rtol=0) assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert np.allclose(autograd_val, numeric_val, atol=tol, rtol=0) @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, 2 * np.pi, 7)) @@ -2497,7 +2505,7 @@ def test_Rot_gradient(self, mocker, theta, shift, tol): assert len(tapes) == len(tape.trainable_params) assert [t.batch_size for t in tapes] == [2, 2, 2] - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) manualgrad_val = np.zeros_like(autograd_val) for idx in list(np.ndindex(*params.shape)): @@ -2516,7 +2524,7 @@ def test_Rot_gradient(self, mocker, theta, shift, tol): assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert len(autograd_val) == len(numeric_val) for a, n in zip(autograd_val, numeric_val): @@ -2540,12 +2548,12 @@ def test_controlled_rotation_gradient(self, G, tol): assert np.allclose(res, -np.cos(b / 2), atol=tol, rtol=0) tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.sin(b / 2) / 2 assert np.allclose(grad, expected, atol=tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert np.allclose(grad, numeric_val, atol=tol, rtol=0) @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, np.pi, 7)) @@ -2571,7 +2579,7 @@ def test_CRot_gradient(self, theta, tol): assert len(tapes) == len(tape.trainable_params) assert [t.batch_size for t in tapes] == [4, 4, 4] - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.array( [ 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), @@ -2584,7 +2592,7 @@ def test_CRot_gradient(self, theta, tol): assert np.allclose(g, e, atol=tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) assert np.allclose(grad, numeric_val, atol=tol, rtol=0) def test_gradients_agree_finite_differences(self, tol): @@ -2650,10 +2658,12 @@ def test_variance_gradients_agree_finite_differences(self, tol): assert np.allclose(g, grad_F2[idx1][idx2], atol=tol, rtol=0) @pytest.mark.autograd - def test_fallback(self, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback(self, dev_name, mocker): """Test that fallback gradient functions are correctly used""" spy = mocker.spy(qml.gradients, "finite_diff") - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -2675,7 +2685,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {1} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) with pytest.raises(NotImplementedError, match="Broadcasting with multiple measurements"): cost_fn(params) @@ -2691,13 +2701,15 @@ def cost_fn(params): # assert np.allclose(jac[1, 1, 1], -2 * np.cos(2 * y), atol=tol, rtol=0) @pytest.mark.autograd - def test_all_fallback(self, mocker, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_all_fallback(self, dev_name, mocker, tol): """Test that *only* the fallback logic is called if no parameters support the parameter-shift rule""" spy_fd = mocker.spy(qml.gradients, "finite_diff") spy_ps = mocker.spy(qml.gradients.parameter_shift, "expval_param_shift") - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -2715,7 +2727,7 @@ def test_all_fallback(self, mocker, tol): spy_fd.assert_called() spy_ps.assert_not_called() - res = fn(dev.batch_execute(tapes)) + res = fn(execute_fn(tapes)) assert len(res) == 2 assert res[0].shape == () assert res[1].shape == () @@ -2741,7 +2753,7 @@ def test_single_expectation_value(self, tol): assert len(tapes) == 2 assert tapes[0].batch_size == tapes[1].batch_size == 2 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert len(res) == 2 assert res[0].shape == () assert res[1].shape == () @@ -2773,7 +2785,7 @@ def test_multiple_expectation_values(self): # assert len(tapes) == 2 # assert tapes[0].batch_size == tapes[1].batch_size == 2 - # res = fn(dev.batch_execute(tapes)) + # res = fn(dev.execute(tapes)) # assert res.shape == (2, 2) # expected = np.array([[-np.sin(x), 0], [0, np.cos(y)]]) @@ -2802,7 +2814,7 @@ def test_var_expectation_values(self): # assert tapes[0].batch_size is None # assert tapes[1].batch_size == tapes[2].batch_size == 2 - # res = fn(dev.batch_execute(tapes)) + # res = fn(dev.execute(tapes)) # assert res.shape == (2, 2) # expected = np.array([[-np.sin(x), 0], [0, -2 * np.cos(y) * np.sin(y)]]) @@ -2832,7 +2844,7 @@ def test_prob_expectation_values(self): # assert len(tapes) == 2 # assert tapes[0].batch_size == tapes[1].batch_size == 2 - # res = fn(dev.batch_execute(tapes)) + # res = fn(dev.execute(tapes)) # assert res.shape == (5, 2) # expected = ( @@ -2878,7 +2890,7 @@ def test_involutory_variance(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, np.ndarray) assert gradA.shape == () @@ -2887,7 +2899,7 @@ def test_involutory_variance(self, tol): assert tapes[1].batch_size == 2 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = 2 * np.sin(a) * np.cos(a) @@ -2914,7 +2926,7 @@ def test_non_involutory_variance(self, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, np.ndarray) assert gradA.shape == () @@ -2923,7 +2935,7 @@ def test_non_involutory_variance(self, tol): assert tapes[1].batch_size == tapes[2].batch_size == 2 tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = -35 * np.sin(2 * a) - 12 * np.cos(2 * a) @@ -2955,11 +2967,11 @@ def test_involutory_and_noninvolutory_variance(self, tol): qml.gradients.param_shift(tape, broadcast=True) # TODO: Uncomment the following when #2693 is resolved. # tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - # gradA = fn(dev.batch_execute(tapes)) + # gradA = fn(dev.execute(tapes)) # assert len(tapes) == 1 + 2 * 4 # tapes, fn = qml.gradients.finite_diff(tape) - # gradF = fn(dev.batch_execute(tapes)) + # gradF = fn(dev.execute(tapes)) # assert len(tapes) == 1 + 2 # expected = [2 * np.sin(a) * np.cos(a), -35 * np.sin(2 * a) - 12 * np.cos(2 * a)] @@ -3001,10 +3013,10 @@ def test_expval_and_variance(self, tol): qml.gradients.param_shift(tape, broadcast=True) # TODO: Uncomment the following when #2693 is resolved. # tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - # gradA = fn(dev.batch_execute(tapes)) + # gradA = fn(dev.execute(tapes)) # tapes, fn = qml.gradients.finite_diff(tape) - # gradF = fn(dev.batch_execute(tapes)) + # gradF = fn(dev.execute(tapes)) # ca, sa, cb, sb = np.cos(a), np.sin(a), np.cos(b), np.sin(b) # c2c, s2c = np.cos(2 * c), np.sin(2 * c) # expected = np.array( @@ -3038,10 +3050,10 @@ def test_projector_variance(self, state, tol): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape, broadcast=True) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) expected = np.array( [ @@ -3113,10 +3125,12 @@ class TestParamShiftGradients: @pytest.mark.autograd # TODO: support Hessian with the new return types @pytest.mark.skip - def test_autograd(self, tol, broadcast, expected): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, tol, broadcast, expected): """Tests that the output of the parameter-shift transform can be differentiated using autograd, yielding second derivatives.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute params = np.array([0.543, -0.654], requires_grad=True) exp_num_tapes, exp_batch_sizes = expected @@ -3132,7 +3146,7 @@ def cost_fn(x): tapes, fn = qml.gradients.param_shift(tape, broadcast=broadcast) assert len(tapes) == exp_num_tapes assert [t.batch_size for t in tapes] == exp_batch_sizes - jac = fn(dev.batch_execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res = qml.jacobian(cost_fn)(params) @@ -3194,7 +3208,7 @@ def test_no_trainable_coeffs(self, mocker, tol, broadcast): x, y = weights tape.trainable_params = {0, 1} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = -c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)) assert np.allclose(res, expected, atol=tol, rtol=0) @@ -3204,7 +3218,7 @@ def test_no_trainable_coeffs(self, mocker, tol, broadcast): assert [t.batch_size for t in tapes] == ([2, 2] if broadcast else [None] * 4) spy.assert_not_called() - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 @@ -3240,7 +3254,7 @@ def test_trainable_coeffs(self, mocker, tol, broadcast): x, y = weights tape.trainable_params = {0, 1, 2, 4} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = -c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)) assert np.allclose(res, expected, atol=tol, rtol=0) @@ -3251,7 +3265,7 @@ def test_trainable_coeffs(self, mocker, tol, broadcast): assert [t.batch_size for t in tapes] == ([2, 2, None, None] if broadcast else [None] * 6) spy.assert_called() - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 4 assert res[0].shape == () @@ -3298,7 +3312,7 @@ def test_multiple_hamiltonians(self, mocker, tol, broadcast): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1, 2, 4, 5} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = [-c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)), d * np.cos(x)] assert np.allclose(res, expected, atol=tol, rtol=0) @@ -3313,7 +3327,7 @@ def test_multiple_hamiltonians(self, mocker, tol, broadcast): assert len(tapes) == 2 * 2 + 3 spy.assert_called() - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 assert len(res[0]) == 5 @@ -3351,7 +3365,8 @@ def cost_fn(weights, coeffs1, coeffs2, dev=None, broadcast=False): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1, 2, 3, 4, 5} tapes, fn = qml.gradients.param_shift(tape, broadcast=broadcast) - jac = fn(dev.batch_execute(tapes)) + execute_fn = dev.batch_execute if isinstance(dev, qml.Device) else dev.execute + jac = fn(execute_fn(tapes)) return jac @staticmethod @@ -3373,13 +3388,14 @@ def cost_fn_expected(weights, coeffs1, coeffs2): ] @pytest.mark.autograd - def test_autograd(self, tol, broadcast): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, tol, broadcast): """Test gradient of multiple trainable Hamiltonian coefficients using autograd""" coeffs1 = np.array([0.1, 0.2, 0.3], requires_grad=True) coeffs2 = np.array([0.7], requires_grad=True) weights = np.array([0.4, 0.5], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( @@ -3399,7 +3415,8 @@ def test_autograd(self, tol, broadcast): # assert np.allclose(res[2][:, -1], np.zeros([2, 1, 1]), atol=tol, rtol=0) @pytest.mark.tf - def test_tf(self, tol, broadcast): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, tol, broadcast): """Test gradient of multiple trainable Hamiltonian coefficients using tf""" import tensorflow as tf @@ -3408,7 +3425,7 @@ def test_tf(self, tol, broadcast): coeffs2 = tf.Variable([0.7], dtype=tf.float64) weights = tf.Variable([0.4, 0.5], dtype=tf.float64) - dev = qml.device("default.qubit.tf", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( @@ -3435,7 +3452,8 @@ def test_tf(self, tol, broadcast): # TODO: Torch support for param-shift @pytest.mark.torch @pytest.mark.xfail - def test_torch(self, tol, broadcast): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, tol, broadcast): """Test gradient of multiple trainable Hamiltonian coefficients using torch""" import torch @@ -3444,7 +3462,7 @@ def test_torch(self, tol, broadcast): coeffs2 = torch.tensor([0.7], dtype=torch.float64, requires_grad=True) weights = torch.tensor([0.4, 0.5], dtype=torch.float64, requires_grad=True) - dev = qml.device("default.qubit.torch", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( @@ -3466,7 +3484,8 @@ def test_torch(self, tol, broadcast): assert np.allclose(hess[2][:, -1], np.zeros([2, 1, 1]), atol=tol, rtol=0) @pytest.mark.jax - def test_jax(self, tol, broadcast): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, tol, broadcast): """Test gradient of multiple trainable Hamiltonian coefficients using JAX""" import jax @@ -3476,7 +3495,7 @@ def test_jax(self, tol, broadcast): coeffs1 = jnp.array([0.1, 0.2, 0.3]) coeffs2 = jnp.array([0.7]) weights = jnp.array([0.4, 0.5]) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( diff --git a/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py b/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py index 16499641081..563423a0416 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py +++ b/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py @@ -40,7 +40,7 @@ def grad_fn(tape, dev, fn=qml.gradients.param_shift, **kwargs): """Utility function to automate execution and processing of gradient tapes""" tapes, fn = fn(tape, **kwargs) - return fn(dev.batch_execute(tapes)) + return fn(dev.execute(tapes)) # pylint: disable=too-few-public-methods @@ -90,7 +90,7 @@ def test_independent_parameter(self, mocker): assert len(tapes) == 2 assert tapes[0].batch_size == tapes[1].batch_size == None - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) for r in res: assert isinstance(r, tuple) assert len(r) == 2 @@ -293,7 +293,7 @@ def test_all_zero_diff_methods_multiple_returns_tape(self): g_tapes, post_processing = qml.gradients.param_shift(tape) assert g_tapes == [] - all_result = post_processing(dev.batch_execute(g_tapes)) + all_result = post_processing(dev.execute(g_tapes)) assert isinstance(all_result, tuple) @@ -414,7 +414,7 @@ def test_f0_provided(self, y_wire): # one tape per parameter that impacts the expval assert len(tapes) == 2 if y_wire == 0 else 1 - fn(dev.batch_execute(tapes)) + fn(dev.execute(tapes)) def test_op_with_custom_unshifted_term(self): """Test that an operation with a gradient recipe that depends on @@ -451,7 +451,7 @@ class RX(qml.RX): assert tape.operations[0].data[0] == x[0] + expected[0] assert tape.operations[1].data[0] == x[1] + expected[1] - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) exp = np.stack([-np.sin(x[0] + x[1]), -np.sin(x[0] + x[1]) + 0.2 * np.cos(x[0] + x[1])]) assert isinstance(grad, tuple) assert len(grad) == len(default_shot_vector) @@ -484,15 +484,16 @@ def test_independent_parameters_analytic(self): tape2 = qml.tape.QuantumScript.from_queue(q2, shots=shot_vec) tapes, fn = qml.gradients.param_shift(tape1) - j1 = fn(dev.batch_execute(tapes)) + with qml.Tracker(dev) as tracker: + j1 = fn(dev.execute(tapes)) # We should only be executing the device twice: Two shifted evaluations to differentiate # one parameter overall, as the other parameter does not impact the returned measurement. - assert dev.num_executions == 2 + assert tracker.latest["executions"] == 2 tapes, fn = qml.gradients.param_shift(tape2) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) exp = -np.sin(1) @@ -532,7 +533,7 @@ def test_grad_recipe_parameter_dependent(self): assert qml.math.allclose(tapes[0].operations[0].data[0], 0) assert qml.math.allclose(tapes[1].operations[0].data[0], 2 * x) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) assert np.allclose(grad, -np.sin(x), atol=shot_vec_tol) def test_error_no_diff_info(self): @@ -606,14 +607,14 @@ def test_pauli_rotation_gradient(self, mocker, G, theta, shift): tapes, fn = qml.gradients.param_shift(tape, shifts=[(shift,)]) assert len(tapes) == 2 - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) tape_fwd = tape.bind_new_parameters([theta + np.pi / 2], [1]) tape_bwd = tape.bind_new_parameters([theta - np.pi / 2], [1]) - shot_vec_manual_res = dev.batch_execute([tape_fwd, tape_bwd]) + shot_vec_manual_res = dev.execute([tape_fwd, tape_bwd]) - # Parameter axis is the first - reorder the results from batch_execute + # Parameter axis is the first - reorder the results from execute shot_vec_len = len(many_shots_shot_vector) shot_vec_manual_res = [ tuple(comp[l] for comp in shot_vec_manual_res) for l in range(shot_vec_len) @@ -628,7 +629,7 @@ def test_pauli_rotation_gradient(self, mocker, G, theta, shift): assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for a_val, n_val in zip(autograd_val, numeric_val): assert np.allclose(a_val, n_val, atol=finite_diff_tol, rtol=0) @@ -654,7 +655,7 @@ def test_Rot_gradient(self, mocker, theta, shift): num_params = len(tape.trainable_params) assert len(tapes) == 2 * num_params - autograd_val = fn(dev.batch_execute(tapes)) + autograd_val = fn(dev.execute(tapes)) assert isinstance(autograd_val, tuple) assert len(autograd_val) == len(shot_vec) @@ -687,7 +688,7 @@ def test_Rot_gradient(self, mocker, theta, shift): assert spy.call_args[1]["shifts"] == (shift,) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for a_val, n_val in zip(autograd_val, numeric_val): assert np.allclose(a_val, n_val, atol=finite_diff_tol, rtol=0) @@ -710,14 +711,14 @@ def test_controlled_rotation_gradient(self, G): assert np.allclose(res, -np.cos(b / 2), atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.param_shift(tape) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.sin(b / 2) / 2 assert isinstance(grad, tuple) assert len(grad) == len(many_shots_shot_vector) assert np.allclose(grad, expected, atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for a_val, n_val in zip(grad, numeric_val): assert np.allclose(a_val, n_val, atol=finite_diff_tol, rtol=0) @@ -744,7 +745,7 @@ def test_CRot_gradient(self, theta): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 * len(tape.trainable_params) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.array( [ 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), @@ -762,7 +763,7 @@ def test_CRot_gradient(self, theta): assert np.allclose(g, expected[idx], atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - numeric_val = fn(dev.batch_execute(tapes)) + numeric_val = fn(dev.execute(tapes)) for a_val, n_val in zip(grad, numeric_val): assert np.allclose(a_val, n_val, atol=finite_diff_tol, rtol=0) @@ -842,10 +843,12 @@ def test_variance_gradients_agree_finite_differences(self): assert np.allclose(g, grad_F2[idx1][idx2], atol=finite_diff_tol, rtol=0) @pytest.mark.autograd - def test_fallback(self, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback(self, dev_name, mocker): """Test that fallback gradient functions are correctly used""" spy = mocker.spy(qml.gradients, "finite_diff") - dev = qml.device("default.qubit.autograd", wires=3, shots=fallback_shot_vec) + dev = qml.device(dev_name, wires=3, shots=fallback_shot_vec) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -869,7 +872,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {1} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) all_res = cost_fn(params) @@ -898,11 +901,13 @@ def cost_fn(params): # assert np.allclose(jac[1, 1, 1], -2 * np.cos(2 * y), atol=shot_vec_tol, rtol=0) @pytest.mark.autograd - def test_fallback_single_meas(self, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback_single_meas(self, dev_name, mocker): """Test that fallback gradient functions are correctly used for a single measurement.""" spy = mocker.spy(qml.gradients, "finite_diff") shot_vec = tuple([1000000] * 4) - dev = qml.device("default.qubit.autograd", wires=3, shots=shot_vec) + dev = qml.device(dev_name, wires=3, shots=shot_vec) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -923,7 +928,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {1} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) all_res = cost_fn(params) @@ -941,10 +946,14 @@ def cost_fn(params): @pytest.mark.autograd @pytest.mark.parametrize("RX, RY, argnum", [(RX_with_F, qml.RY, 0), (qml.RX, RY_with_F, 1)]) - def test_fallback_probs(self, RX, RY, argnum, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_fallback_probs( + self, dev_name, RX, RY, argnum, mocker + ): # pylint:disable=too-many-arguments """Test that fallback gradient functions are correctly used with probs""" spy = mocker.spy(qml.gradients, "finite_diff") - dev = qml.device("default.qubit.autograd", wires=3, shots=fallback_shot_vec) + dev = qml.device(dev_name, wires=3, shots=fallback_shot_vec) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -967,7 +976,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {argnum} - return fn(dev.batch_execute(tapes)) + return fn(execute_fn(tapes)) all_res = cost_fn(params) assert isinstance(all_res, tuple) @@ -1028,13 +1037,15 @@ def cost_fn(params): assert np.allclose(res[1][1], probs_expected[:, 1], atol=finite_diff_tol) @pytest.mark.autograd - def test_all_fallback(self, mocker): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_all_fallback(self, dev_name, mocker): """Test that *only* the fallback logic is called if no parameters support the parameter-shift rule""" spy_fd = mocker.spy(qml.gradients, "finite_diff") spy_ps = mocker.spy(qml.gradients.parameter_shift, "expval_param_shift") - dev = qml.device("default.qubit.autograd", wires=3, shots=fallback_shot_vec) + dev = qml.device(dev_name, wires=3, shots=fallback_shot_vec) + execute_fn = dev.execute if dev_name == "default.qubit" else dev.batch_execute x = 0.543 y = -0.654 @@ -1053,7 +1064,7 @@ def test_all_fallback(self, mocker): spy_fd.assert_called() spy_ps.assert_not_called() - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(execute_fn(tapes)) assert len(all_res) == len(fallback_shot_vec) assert isinstance(all_res, tuple) @@ -1085,7 +1096,7 @@ def test_single_expectation_value(self): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1118,7 +1129,7 @@ def test_multiple_expectation_values(self): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1151,7 +1162,7 @@ def test_var_expectation_values(self): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 5 - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1185,7 +1196,7 @@ def test_prob_expectation_values(self): tapes, fn = qml.gradients.param_shift(tape) assert len(tapes) == 4 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == len(many_shots_shot_vector) @@ -1272,7 +1283,7 @@ def test_involutory_variance_single_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) for _gA in gradA: assert isinstance(_gA, np.ndarray) assert _gA.shape == () @@ -1280,7 +1291,7 @@ def test_involutory_variance_single_param(self): assert len(tapes) == 1 + 2 * 1 tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = 2 * np.sin(a) * np.cos(a) @@ -1312,7 +1323,7 @@ def test_involutory_variance_multi_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1326,7 +1337,7 @@ def test_involutory_variance_multi_param(self): assert len(tapes) == 1 + 2 * 2 tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_Fres = fn(dev.batch_execute(tapes)) + all_Fres = fn(dev.execute(tapes)) for gradF, gradA in zip(all_Fres, all_res): assert len(tapes) == 3 @@ -1359,11 +1370,11 @@ def test_non_involutory_variance_single_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert len(tapes) == 1 + 4 * 1 tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) assert len(tapes) == 2 expected = -35 * np.sin(2 * a) - 12 * np.cos(2 * a) @@ -1401,7 +1412,7 @@ def test_non_involutory_variance_multi_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1419,7 +1430,7 @@ def test_non_involutory_variance_multi_param(self): assert gradA[1] == pytest.approx(expected, abs=herm_shot_vec_tol) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) assert len(all_gradF) == len(many_shots_shot_vector) assert isinstance(all_gradF, tuple) for gradF in all_gradF: @@ -1456,11 +1467,11 @@ def test_involutory_and_noninvolutory_variance_single_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert len(tapes) == 1 + 4 tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 1 + 1 expected = [2 * np.sin(a) * np.cos(a), 0] @@ -1507,7 +1518,7 @@ def test_involutory_and_noninvolutory_variance_multi_param(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - gradA = fn(dev.batch_execute(tapes)) + gradA = fn(dev.execute(tapes)) assert isinstance(gradA, tuple) assert len(gradA) == len(many_shots_shot_vector) @@ -1524,7 +1535,7 @@ def test_involutory_and_noninvolutory_variance_multi_param(self): assert len(tapes) == 1 + 2 * 4 tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) assert len(tapes) == 1 + 2 expected = [2 * np.sin(a) * np.cos(a), 0, 0, -35 * np.sin(2 * a) - 12 * np.cos(2 * a)] @@ -1590,7 +1601,7 @@ def test_var_and_probs_single_param(self, ind): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1647,7 +1658,7 @@ def test_var_and_probs_multi_params(self): # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1750,7 +1761,7 @@ def test_expval_and_variance_single_param(self): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1764,7 +1775,7 @@ def test_expval_and_variance_single_param(self): assert np.allclose(a_comp, e_comp, atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) assert isinstance(all_gradF, tuple) for gradF in all_gradF: @@ -1806,7 +1817,7 @@ def test_expval_and_variance_multi_param(self): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1831,7 +1842,7 @@ def test_expval_and_variance_multi_param(self): assert np.allclose(a_comp, e_comp, atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) for gradF in all_gradF: assert gradF == pytest.approx(expected, abs=finite_diff_tol) @@ -1861,7 +1872,7 @@ def test_projector_variance(self, state): # # circuit jacobians tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == len(many_shots_shot_vector) assert isinstance(all_res, tuple) @@ -1876,7 +1887,7 @@ def test_projector_variance(self, state): assert np.allclose(gradA, expected, atol=shot_vec_tol, rtol=0) tapes, fn = qml.gradients.finite_diff(tape, h=h_val) - all_gradF = fn(dev.batch_execute(tapes)) + all_gradF = fn(dev.execute(tapes)) for gradF in all_gradF: assert gradF == pytest.approx(expected, abs=finite_diff_tol) @@ -2074,7 +2085,7 @@ def test_multi_measure_no_warning(self): tape = qml.tape.QuantumScript.from_queue(q, shots=shot_vec) with warnings.catch_warnings(record=True) as record: tapes, fn = qml.gradients.param_shift(tape) - fn(dev.batch_execute(tapes)) + fn(dev.execute(tapes)) assert len(record) == 0 @@ -2132,7 +2143,7 @@ def test_no_trainable_coeffs(self, mocker, broadcast, tol): x, y = weights tape.trainable_params = {0, 1} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = -c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)) assert np.allclose(res, expected, atol=shot_vec_tol, rtol=0) @@ -2142,7 +2153,7 @@ def test_no_trainable_coeffs(self, mocker, broadcast, tol): assert [t.batch_size for t in tapes] == ([2, 2] if broadcast else [None] * 4) spy.assert_not_called() - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert isinstance(all_res, tuple) assert len(all_res) == len(many_shots_shot_vector) @@ -2183,7 +2194,7 @@ def test_trainable_coeffs(self, mocker, broadcast, tol): x, y = weights tape.trainable_params = {0, 1, 2, 4} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = -c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)) assert np.allclose(res, expected, atol=tol, rtol=0) @@ -2194,7 +2205,7 @@ def test_trainable_coeffs(self, mocker, broadcast, tol): assert [t.batch_size for t in tapes] == ([2, 2, None, None] if broadcast else [None] * 6) spy.assert_called() - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 4 assert res[0].shape == () @@ -2243,7 +2254,7 @@ def test_multiple_hamiltonians(self, mocker, broadcast, tol): tape = qml.tape.QuantumScript.from_queue(q, shots=shot_vec) tape.trainable_params = {0, 1, 2, 4, 5} - res = dev.batch_execute([tape]) + res = dev.execute([tape]) expected = [-c * np.sin(x) * np.sin(y) + np.cos(x) * (a + b * np.sin(y)), d * np.cos(x)] assert np.allclose(res, expected, atol=tol, rtol=0) @@ -2258,7 +2269,7 @@ def test_multiple_hamiltonians(self, mocker, broadcast, tol): assert len(tapes) == 2 * 2 + 3 spy.assert_called() - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert isinstance(res, tuple) assert len(res) == 2 assert len(res[0]) == 5 @@ -2296,7 +2307,8 @@ def cost_fn(weights, coeffs1, coeffs2, dev=None, broadcast=False): tape = qml.tape.QuantumScript.from_queue(q, shots=dev.shots) tape.trainable_params = {0, 1, 2, 3, 4, 5} tapes, fn = qml.gradients.param_shift(tape, broadcast=broadcast) - return fn(dev.batch_execute(tapes)) + execute_fn = dev.batch_execute if isinstance(dev, qml.Device) else dev.execute + return fn(execute_fn(tapes)) @staticmethod def cost_fn_expected(weights, coeffs1, coeffs2): @@ -2318,14 +2330,15 @@ def cost_fn_expected(weights, coeffs1, coeffs2): @pytest.mark.xfail(reason="TODO") @pytest.mark.autograd - def test_autograd(self, broadcast, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd(self, dev_name, broadcast, tol): """Test gradient of multiple trainable Hamiltonian coefficients using autograd""" coeffs1 = np.array([0.1, 0.2, 0.3], requires_grad=True) coeffs2 = np.array([0.7], requires_grad=True) weights = np.array([0.4, 0.5], requires_grad=True) shot_vec = many_shots_shot_vector - dev = qml.device("default.qubit.autograd", wires=2, shots=shot_vec) + dev = qml.device(dev_name, wires=2, shots=shot_vec) if broadcast: with pytest.raises( @@ -2346,7 +2359,8 @@ def test_autograd(self, broadcast, tol): @pytest.mark.xfail(reason="TODO") @pytest.mark.tf - def test_tf(self, broadcast, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_tf(self, dev_name, broadcast, tol): """Test gradient of multiple trainable Hamiltonian coefficients using tf""" import tensorflow as tf @@ -2356,7 +2370,7 @@ def test_tf(self, broadcast, tol): weights = tf.Variable([0.4, 0.5], dtype=tf.float64) shot_vec = many_shots_shot_vector - dev = qml.device("default.qubit.tf", wires=2, shots=shot_vec) + dev = qml.device(dev_name, wires=2, shots=shot_vec) if broadcast: with pytest.raises( @@ -2383,7 +2397,8 @@ def test_tf(self, broadcast, tol): # TODO: Torch support for param-shift @pytest.mark.torch @pytest.mark.xfail - def test_torch(self, broadcast, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_torch(self, dev_name, broadcast, tol): """Test gradient of multiple trainable Hamiltonian coefficients using torch""" import torch @@ -2392,7 +2407,7 @@ def test_torch(self, broadcast, tol): coeffs2 = torch.tensor([0.7], dtype=torch.float64, requires_grad=True) weights = torch.tensor([0.4, 0.5], dtype=torch.float64, requires_grad=True) - dev = qml.device("default.qubit.torch", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( @@ -2413,9 +2428,9 @@ def test_torch(self, broadcast, tol): assert np.allclose(hess[1][:, 2:5], np.zeros([2, 3, 3]), atol=tol, rtol=0) assert np.allclose(hess[2][:, -1], np.zeros([2, 1, 1]), atol=tol, rtol=0) - @pytest.mark.xfail(reason="TODO") @pytest.mark.jax - def test_jax(self, broadcast, tol): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_jax(self, dev_name, broadcast, tol): """Test gradient of multiple trainable Hamiltonian coefficients using JAX""" import jax @@ -2425,7 +2440,7 @@ def test_jax(self, broadcast, tol): coeffs1 = jnp.array([0.1, 0.2, 0.3]) coeffs2 = jnp.array([0.7]) weights = jnp.array([0.4, 0.5]) - dev = qml.device("default.qubit.jax", wires=2) + dev = qml.device(dev_name, wires=2) if broadcast: with pytest.raises( @@ -2516,7 +2531,7 @@ def test_1_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0} tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -2550,7 +2565,7 @@ def test_1_N(self, shot_vec, op_wire): tape.trainable_params = {0} tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -2584,7 +2599,7 @@ def test_N_1(self, shot_vec, meas, shape, op_wires): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) @@ -2624,7 +2639,7 @@ def test_N_N(self, shot_vec, op_wires): tape.trainable_params = {0, 1, 2, 3, 4} tapes, fn = qml.gradients.param_shift(tape) - all_res = fn(dev.batch_execute(tapes)) + all_res = fn(dev.execute(tapes)) assert len(all_res) == grad_transform_shots.num_copies assert isinstance(all_res, tuple) diff --git a/tests/logging/test_logging_autograd.py b/tests/logging/test_logging_autograd.py index e278e674c1b..6dcafffb439 100644 --- a/tests/logging/test_logging_autograd.py +++ b/tests/logging/test_logging_autograd.py @@ -21,7 +21,7 @@ _grad_log_map = { - "adjoint": "gradient_fn=device, interface=autograd, grad_on_execution=best, gradient_kwargs={'use_device_state': True, 'method': 'adjoint_jacobian'}", + "adjoint": "gradient_fn=adjoint, interface=autograd, grad_on_execution=best, gradient_kwargs={}", "backprop": "gradient_fn=backprop, interface=autograd, grad_on_execution=best, gradient_kwargs={}", "parameter-shift": "gradient_fn=,)", - _grad_log_map[diff_method[0]], + _grad_log_map[diff_method], ], ), ] - for idx, r in enumerate(caplog.records[0:2]): - assert log_records_expected[idx][0] in r.name - for msg in log_records_expected[idx][1]: - assert msg in r.getMessage() + for expected, actual in zip(log_records_expected, caplog.records[:2]): + assert expected[0] in actual.name + assert all(msg in actual.getMessage() for msg in expected[1]) diff --git a/tests/math/test_functions.py b/tests/math/test_functions.py index 5dceb524562..ddf8bffcc28 100644 --- a/tests/math/test_functions.py +++ b/tests/math/test_functions.py @@ -2569,11 +2569,17 @@ class TestSize: ([[0], [1], [2], [3], [4], [5]], 6), ] - @pytest.mark.torch + @pytest.mark.parametrize( + "interface", + [ + pytest.param("torch", marks=pytest.mark.torch), + pytest.param("tensorflow", marks=pytest.mark.tf), + ], + ) @pytest.mark.parametrize(("array", "size"), array_and_size) - def test_size_torch(self, array, size): - """Test size function with the torch interface.""" - r = fn.size(torch.tensor(array)) + def test_size_torch_and_tf(self, array, size, interface): + """Test size function with the torch and tf interfaces.""" + r = fn.size(fn.asarray(array, like=interface)) assert r == size diff --git a/tests/measurements/test_classical_shadow.py b/tests/measurements/test_classical_shadow.py index d67967c2ff9..47fb06f2b02 100644 --- a/tests/measurements/test_classical_shadow.py +++ b/tests/measurements/test_classical_shadow.py @@ -340,7 +340,6 @@ def test_return_distribution(self, wires, interface, circuit_fn, basis_recipe): ratios2 = np.unique(bits2, return_counts=True)[1] / bits2.shape[0] assert np.allclose(ratios2, 1 / 2, atol=1e-1) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("seed", seed_recipes_list) def test_shots_none_error(self, wires, seed): """Test that an error is raised when a device with shots=None is used @@ -351,7 +350,6 @@ def test_shots_none_error(self, wires, seed): with pytest.raises(qml.DeviceError, match=msg): circuit() - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("shots", shots_list) def test_multi_measurement_error(self, wires, shots): """Test that an error is raised when classical shadows is returned @@ -458,7 +456,6 @@ def test_measurement_process_copy(self): assert copied_res.k == res.k assert copied_res.seed == res.seed - @pytest.mark.xfail(reason="until DQ2 port") def test_shots_none_error(self): """Test that an error is raised when a device with shots=None is used to obtain classical shadows""" @@ -469,7 +466,6 @@ def test_shots_none_error(self): with pytest.raises(qml.DeviceError, match=msg): _ = circuit(H, k=10) - @pytest.mark.xfail(reason="until DQ2 port") def test_multi_measurement_allowed(self): """Test that no error is raised when classical shadows is returned with other measurement processes""" diff --git a/tests/measurements/test_measurements.py b/tests/measurements/test_measurements.py index 358a72fb2ab..945ace9dd5a 100644 --- a/tests/measurements/test_measurements.py +++ b/tests/measurements/test_measurements.py @@ -492,7 +492,6 @@ def circuit(): assert qml.math.allequal(circuit(), [1000, 0]) - @pytest.mark.xfail(reason="until DQ2 port") def test_sample_measurement_without_shots(self): """Test that executing a sampled measurement with ``shots=None`` raises an error.""" @@ -537,7 +536,6 @@ def circuit(): assert circuit() == 1 - @pytest.mark.xfail(reason="until DQ2 port") def test_state_measurement_with_shots(self): """Test that executing a state measurement with shots raises an error.""" @@ -562,13 +560,13 @@ def circuit(): class TestMeasurementTransform: """Tests for the MeasurementTransform class.""" - @pytest.mark.xfail(reason="until DQ2 port") def test_custom_measurement(self): """Test the execution of a custom measurement.""" class CountTapesMP(MeasurementTransform, SampleMeasurement): def process(self, tape, device): - tapes, _, _ = device.preprocess(tape) + program, _ = device.preprocess() + tapes, _ = program([tape]) return len(tapes) def process_samples(self, samples, wire_order, shot_range=None, bin_size=None): diff --git a/tests/measurements/test_mutual_info.py b/tests/measurements/test_mutual_info.py index e266d1e9df4..0424b97fd8a 100644 --- a/tests/measurements/test_mutual_info.py +++ b/tests/measurements/test_mutual_info.py @@ -109,7 +109,6 @@ def circuit(): res = circuit() assert np.allclose(res, expected, atol=1e-6) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("shots", [1000, [1, 10, 10, 1000]]) def test_finite_shots_error(self, shots): """Test an error is raised when using shot vectors with mutual_info.""" @@ -491,7 +490,6 @@ def circuit(params): with pytest.raises(qml.QuantumFunctionError, match=msg): circuit(params) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize("params", [np.array([0.0, 0.0]), np.array([0.3, 0.4])]) diff --git a/tests/measurements/test_probs.py b/tests/measurements/test_probs.py index 8365de213eb..8ad640b3efd 100644 --- a/tests/measurements/test_probs.py +++ b/tests/measurements/test_probs.py @@ -618,7 +618,6 @@ def test_estimate_probability_with_binsize_with_broadcasting(self, wires, expect assert np.allclose(res, expected) - @pytest.mark.xfail(reason="until DQ2 port") def test_non_commuting_probs_does_not_raises_error(self): """Tests that non-commuting probs with expval does not raise an error.""" dev = qml.device("default.qubit", wires=5) diff --git a/tests/measurements/test_sample.py b/tests/measurements/test_sample.py index 7a5a01ac713..ef40ca86b4b 100644 --- a/tests/measurements/test_sample.py +++ b/tests/measurements/test_sample.py @@ -46,7 +46,6 @@ def circuit(): (n_sample,) if not n_sample == 1 else () ) - @pytest.mark.xfail(reason="until DQ2 port") def test_sample_combination(self): """Test the output of combining expval, var and sample""" n_sample = 10 diff --git a/tests/measurements/test_state.py b/tests/measurements/test_state.py index a24c648052e..ab306b5b01e 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -250,22 +250,19 @@ def test_process_state_matrix_from_matrix(self, mat, wires): class TestState: """Tests for the state function""" - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("wires", range(2, 5)) - @pytest.mark.parametrize("op,dtype", [(qml.PauliX, np.float64), (qml.PauliY, np.complex128)]) - def test_state_shape_and_dtype(self, op, dtype, wires): + def test_state_shape_and_dtype(self, wires): """Test that the state is of correct size and dtype for a trivial circuit""" dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def func(): - op(0) return state() state_val = func() assert state_val.shape == (2**wires,) - assert state_val.dtype == dtype + assert state_val.dtype == np.complex128 def test_return_type_is_state(self): """Test that the return type of the observable is State""" @@ -300,7 +297,6 @@ def func(): assert np.allclose(state_val[0], 1 / np.sqrt(2)) assert np.allclose(state_val[-1], 1 / np.sqrt(2)) - @pytest.mark.xfail(reason="until DQ2 port") def test_return_with_other_types_works(self): """Test that no exception is raised when a state is returned along with another return type""" @@ -317,7 +313,6 @@ def func(): assert np.allclose(res[0], np.array([1, 0, 1, 0]) / np.sqrt(2)) assert np.isclose(res[1], 1) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("wires", range(2, 5)) def test_state_equal_to_expected_state(self, wires): """Test that the returned state is equal to the expected state for a template circuit""" @@ -334,14 +329,14 @@ def func(): return state() state_val = func() - scripts, _, _ = dev.preprocess(func.tape) + program, _ = dev.preprocess() + scripts, _ = program([func.tape]) assert len(scripts) == 1 expected_state, _ = qml.devices.qubit.get_final_state(scripts[0]) assert np.allclose(state_val, expected_state.flatten()) @pytest.mark.tf - @pytest.mark.parametrize("op", [qml.PauliX, qml.PauliY]) - def test_interface_tf(self, op): + def test_interface_tf(self): """Test that the state correctly outputs in the tensorflow interface""" import tensorflow as tf @@ -349,8 +344,6 @@ def test_interface_tf(self, op): @qml.qnode(dev, interface="tf") def func(): - op(0) - op(0) for i in range(4): qml.Hadamard(i) return state() @@ -359,14 +352,12 @@ def func(): state_val = func() assert isinstance(state_val, tf.Tensor) - assert state_val.dtype == tf.complex128 if op is qml.PauliY else tf.float64 + assert state_val.dtype == tf.complex128 assert np.allclose(state_expected, state_val.numpy()) assert state_val.shape == (16,) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.torch - @pytest.mark.parametrize("op", [qml.PauliX, qml.PauliY]) - def test_interface_torch(self, op): + def test_interface_torch(self): """Test that the state correctly outputs in the torch interface""" import torch @@ -374,13 +365,11 @@ def test_interface_torch(self, op): @qml.qnode(dev, interface="torch") def func(): - op(0) - op(0) for i in range(4): qml.Hadamard(i) return state() - dtype = torch.complex128 if op is qml.PauliY else torch.float64 + dtype = torch.complex128 state_expected = 0.25 * torch.ones(16, dtype=dtype) state_val = func() @@ -596,11 +585,9 @@ class TestDensityMatrix: # pylint: disable=too-many-public-methods - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("wires", range(2, 5)) @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - @pytest.mark.parametrize("op,dtype", [(qml.PauliX, np.float64), (qml.PauliY, np.complex128)]) - def test_density_matrix_shape_and_dtype(self, dev_name, op, dtype, wires): + def test_density_matrix_shape_and_dtype(self, dev_name, wires): """Test that the density matrix is of correct size and dtype for a trivial circuit""" @@ -608,13 +595,12 @@ def test_density_matrix_shape_and_dtype(self, dev_name, op, dtype, wires): @qml.qnode(dev) def circuit(): - op(0) return density_matrix([0]) state_val = circuit() assert state_val.shape == (2, 2) - assert state_val.dtype == dtype if dev_name == "default.qubit" else np.complex128 + assert state_val.dtype == np.complex128 @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) def test_return_type_is_state(self, dev_name): @@ -681,7 +667,6 @@ def func(): assert np.allclose(expected, density_mat) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.tf @pytest.mark.parametrize("diff_method", [None, "backprop"]) def test_correct_density_matrix_tf_default_qubit(self, diff_method): @@ -720,7 +705,6 @@ def func(): assert np.allclose(expected, density_first) - @pytest.mark.xfail(reason="until DQ2 port") def test_correct_density_matrix_product_state_first_default_qubit(self): """Test that the correct density matrix is returned when tracing out a product state""" @@ -758,7 +742,6 @@ def func(): expected = np.array([[0.5 + 0.0j, 0.5 + 0.0j], [0.5 + 0.0j, 0.5 + 0.0j]]) assert np.allclose(expected, density_second) - @pytest.mark.xfail(reason="until DQ2 port") def test_correct_density_matrix_product_state_second_default_qubit(self): """Test that the correct density matrix is returned when tracing out a product state""" @@ -800,7 +783,6 @@ def func(): assert np.allclose(expected, density_both) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("return_wire_order", ([0, 1], [1, 0])) def test_correct_density_matrix_product_state_both_default_qubit(self, return_wire_order): """Test that the correct density matrix is returned @@ -851,7 +833,6 @@ def func(): ) assert np.allclose(expected, density_full) - @pytest.mark.xfail(reason="until DQ2 port") def test_correct_density_matrix_three_wires_first_two_default_qubit(self): """Test that the correct density matrix is returned for an example with three wires, and tracing out the third wire.""" @@ -938,7 +919,6 @@ def func(): expected = np.outer(exp_statevector.conj(), exp_statevector) assert np.allclose(expected, density_full) - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize( "return_wire_order", ([0], [1], [2], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2, 0], [2, 1, 0]) ) @@ -1016,7 +996,6 @@ def func(): assert np.allclose(expected, density) - @pytest.mark.xfail(reason="until DQ2 port") def test_correct_density_matrix_all_wires_default_qubit(self): """Test that the correct density matrix is returned when all wires are given""" @@ -1044,7 +1023,6 @@ def func(): qml.density_matrix(wires=[0, 1]).process_state(state=dev_state, wire_order=dev.wires), ) - @pytest.mark.xfail(reason="until DQ2 port") def test_return_with_other_types_works(self): """Test that no exception is raised when a state is returned along with another return type""" diff --git a/tests/measurements/test_vn_entropy.py b/tests/measurements/test_vn_entropy.py index 432447227fe..b8dc7830ccf 100644 --- a/tests/measurements/test_vn_entropy.py +++ b/tests/measurements/test_vn_entropy.py @@ -136,7 +136,6 @@ class TestIntegration: diff_methods = ["backprop", "finite-diff"] - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("shots", [1000, [1, 10, 10, 1000]]) def test_finite_shots_error(self, shots): """Test an error is raised when using shot vectors with vn_entropy.""" @@ -392,7 +391,6 @@ def circuit_entropy(x): assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=1e-05) - @pytest.mark.xfail(reason="until DQ2 port") def test_qnode_entropy_custom_wires(self): """Test that entropy can be returned with custom wires.""" diff --git a/tests/ops/functions/test_map_wires.py b/tests/ops/functions/test_map_wires.py index 90115b50b7e..785364faf2e 100644 --- a/tests/ops/functions/test_map_wires.py +++ b/tests/ops/functions/test_map_wires.py @@ -54,7 +54,7 @@ def test_map_wires_with_operator(self): op = build_op() m_op = qml.map_wires(op, wire_map=wire_map) - assert isinstance(m_op, qml.ops.Prod) + assert isinstance(m_op, qml.ops.Prod) # pylint:disable=no-member assert m_op.data == mapped_op.data assert m_op.wires == mapped_op.wires assert m_op.arithmetic_depth == mapped_op.arithmetic_depth @@ -112,13 +112,13 @@ def test_map_wires_tape(self, shots): assert len(s_tape) == 1 assert s_tape.trainable_params == [0, 2] s_op = s_tape[0] - assert isinstance(s_op, qml.ops.Prod) + assert isinstance(s_op, qml.ops.Prod) # pylint:disable=no-member assert s_op.data == mapped_op.data assert s_op.wires == mapped_op.wires assert s_op.arithmetic_depth == mapped_op.arithmetic_depth assert tape.shots == s_tape.shots - @pytest.mark.parametrize("shots", [None, 100]) + @pytest.mark.parametrize("shots", [None, 5000]) def test_execute_mapped_tape(self, shots): """Test the execution of a mapped tape.""" dev = qml.device("default.qubit", wires=5) @@ -134,13 +134,10 @@ def test_execute_mapped_tape(self, shots): assert m_tape._qfunc_output is tape._qfunc_output # pylint: disable=protected-access m_op = m_tape.operations[0] m_obs = m_tape.observables[0] - assert isinstance(m_op, qml.ops.Prod) - assert m_op.data == mapped_op.data - assert m_op.wires == mapped_op.wires - assert m_op.arithmetic_depth == mapped_op.arithmetic_depth + assert qml.equal(m_op, mapped_op) assert tape.shots == m_tape.shots assert m_obs.wires == Wires(wire_map[1]) - assert qml.math.allclose(dev.execute(tape), dev.execute(m_tape)) + assert qml.math.allclose(dev.execute(tape), dev.execute(m_tape), atol=0.05) class TestMapWiresQNodes: @@ -153,23 +150,18 @@ def test_map_wires_qnode(self): @qml.qnode(dev) def qnode(): build_op() - return qml.expval(op=build_op()) + return qml.expval(qml.prod(qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2))) # TODO: Use qml.equal when supported + mapped_obs = qml.prod(qml.PauliX(4), qml.PauliY(3), qml.PauliZ(2)) m_qnode = qml.map_wires(qnode, wire_map=wire_map) assert m_qnode() == qnode() assert len(m_qnode.tape) == 2 m_op = m_qnode.tape.operations[0] m_obs = m_qnode.tape.observables[0] - assert isinstance(m_op, qml.ops.Prod) - assert m_op.data == mapped_op.data - assert m_op.wires == mapped_op.wires - assert m_op.arithmetic_depth == mapped_op.arithmetic_depth - assert isinstance(m_obs, qml.ops.Prod) - assert m_obs.data == mapped_op.data - assert m_obs.wires == mapped_op.wires - assert m_obs.arithmetic_depth == mapped_op.arithmetic_depth + assert qml.equal(m_op, mapped_op) + assert qml.equal(m_obs, mapped_obs) class TestMapWiresCallables: diff --git a/tests/ops/op_math/test_exp.py b/tests/ops/op_math/test_exp.py index 2e2848b8987..9e24dcebfca 100644 --- a/tests/ops/op_math/test_exp.py +++ b/tests/ops/op_math/test_exp.py @@ -647,7 +647,7 @@ def test_repr_tensor(self): def test_repr_deep_operator(self): """Test the __repr__ method when the base is any operator with arithmetic depth > 0.""" base = qml.S(0) @ qml.PauliX(0) - op = qml.ops.Exp(base, 3) + op = qml.ops.Exp(base, 3) # pylint:disable=no-member assert repr(op) == "Exp(3 S(wires=[0]) @ PauliX(wires=[0]))" @@ -797,7 +797,7 @@ def circuit(phi): res = circuit(phi) assert qml.math.allclose(res, torch.cos(phi)) - res.backward() + res.backward() # pylint:disable=no-member assert qml.math.allclose(phi.grad, -torch.sin(phi)) @pytest.mark.autograd @@ -872,7 +872,7 @@ def circuit(x): expected = 0.5 * (torch.exp(x) + torch.exp(-x)) assert qml.math.allclose(res, expected) - res.backward() + res.backward() # pylint:disable=no-member expected_grad = 0.5 * (torch.exp(x) - torch.exp(-x)) assert qml.math.allclose(x.grad, expected_grad) @@ -901,9 +901,10 @@ def circuit(x): @pytest.mark.tf def test_tf_measurement(self): """Test Exp in a measurement with gradient and tensorflow.""" + # pylint:disable=invalid-unary-operand-type import tensorflow as tf - x = tf.Variable(2.0) + x = tf.Variable(2.0, dtype=tf.float64) @qml.qnode(qml.device("default.qubit", wires=1)) def circuit(x): @@ -1011,7 +1012,7 @@ def test_parameter_frequency_with_parameters_in_base_operator(self): op2 = Evolution(base_op, 1) with pytest.raises(ParameterFrequenciesUndefinedError): - op1.parameter_frequencies() + _ = op1.parameter_frequencies assert op2.parameter_frequencies == [(4.0,)] diff --git a/tests/ops/op_math/test_prod.py b/tests/ops/op_math/test_prod.py index 6db76b23dab..07a5bd4644a 100644 --- a/tests/ops/op_math/test_prod.py +++ b/tests/ops/op_math/test_prod.py @@ -758,6 +758,7 @@ def test_is_hermitian(self, ops_lst, hermitian_status): @pytest.mark.tf def test_is_hermitian_tf(self): """Test that is_hermitian works when a tf type scalar is provided.""" + # pylint:disable=invalid-unary-operand-type import tensorflow as tf theta = tf.Variable(1.23) @@ -965,7 +966,7 @@ def test_simplify_method_product_of_sums(self): qml.RX(1, 0) @ qml.RX(1, 1), ) simplified_op = prod_op.simplify() - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert s1.name == s2.name assert s1.wires == s2.wires @@ -1016,7 +1017,7 @@ def test_simplify_method_with_nested_ops(self): qml.s_prod(5, qml.PauliX(1)), ) simplified_op = prod_op.simplify() - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert s1.name == s2.name assert s1.wires.toset() == s2.wires.toset() @@ -1050,7 +1051,7 @@ def test_simplify_method_with_pauli_words(self): # TODO: Use qml.equal when supported for nested operators - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert repr(s1) == repr(s2) assert s1.name == s2.name @@ -1100,7 +1101,7 @@ def test_grouping_with_product_of_sum(self): final_op = qml.sum(qml.s_prod(1j, qml.PauliX(0)), qml.s_prod(-1, qml.PauliZ(0))) simplified_op = prod_op.simplify() - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert s1.name == s2.name assert s1.wires == s2.wires @@ -1116,7 +1117,7 @@ def test_grouping_with_product_of_sums(self): qml.S(wires=[1]), ) simplified_op = prod_op.simplify() - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert s1.name == s2.name assert s1.wires == s2.wires @@ -1128,7 +1129,7 @@ def test_grouping_with_barriers(self): prod_op = qml.prod(qml.S(0), qml.Barrier(0), qml.S(0)).simplify() simplified_op = prod_op.simplify() assert isinstance(simplified_op, Prod) - for s1, s2 in zip(prod_op.operands, simplified_op.operands): + for s1, s2 in zip(prod_op.operands, simplified_op.operands): # pylint:disable=no-member assert s1.name == s2.name assert s1.wires == s2.wires assert s1.data == s2.data @@ -1321,7 +1322,7 @@ def circuit(weights): true_grad = -qnp.sqrt(2) * qnp.cos(weights[0] / 2) * qnp.sin(weights[0] / 2) assert qnp.allclose(grad, true_grad) - def test_non_hermitian_op_in_measurement_process(self): + def test_non_hermitian_obs_not_supported(self): """Test that non-hermitian ops in a measurement process will raise a warning.""" wires = [0, 1] dev = qml.device("default.qubit", wires=wires) @@ -1332,7 +1333,7 @@ def my_circ(): qml.PauliX(0) return qml.expval(prod_op) - with pytest.warns(UserWarning, match="Prod might not be hermitian."): + with pytest.raises(NotImplementedError): my_circ() def test_operation_integration(self): @@ -1387,11 +1388,14 @@ def test_params_can_be_considered_trainable(self): dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) - def circuit(): - return qml.expval(qml.prod(qml.RX(1.1, 0), qml.RY(qnp.array(2.2), 1))) + def circuit(x, U): + qml.RX(x, 0) + return qml.expval(qml.prod(qml.Hermitian(U, 0), qml.PauliX(1))) + + x = qnp.array(0.1, requires_grad=False) + U = qnp.array([[1.0, 0.0], [0.0, -1.0]], requires_grad=True) - with pytest.warns(UserWarning): - circuit() + circuit(x, U) assert circuit.tape.trainable_params == [1] diff --git a/tests/ops/op_math/test_sprod.py b/tests/ops/op_math/test_sprod.py index bc25513af3e..014cde358da 100644 --- a/tests/ops/op_math/test_sprod.py +++ b/tests/ops/op_math/test_sprod.py @@ -790,7 +790,7 @@ def test_simplify_method(self): sprod_op = SProd( 2, SProd(2, qml.RZ(1.32, wires=0)) + qml.Identity(wires=0) + qml.RX(1.9, wires=1) ) - final_op = qml.ops.Sum( + final_op = qml.ops.Sum( # pylint:disable=no-member SProd(4, qml.RZ(1.32, wires=0)), SProd(2, qml.Identity(wires=0)), SProd(2, qml.RX(1.9, wires=1)), @@ -799,7 +799,7 @@ def test_simplify_method(self): # TODO: Use qml.equal when supported for nested operators - assert isinstance(simplified_op, qml.ops.Sum) + assert isinstance(simplified_op, qml.ops.Sum) # pylint:disable=no-member for s1, s2 in zip(final_op.operands, simplified_op.operands): assert isinstance(s2, SProd) assert s1.name == s2.name @@ -837,7 +837,7 @@ def test_simplify_with_sum_operator(self): final_op = s_prod(0 - 6j, qml.PauliX(0)) simplified_op = sprod_op.simplify() - assert isinstance(simplified_op, qml.ops.SProd) + assert isinstance(simplified_op, qml.ops.SProd) # pylint:disable=no-member assert simplified_op.name == final_op.name assert repr(simplified_op) == repr(final_op) assert simplified_op.wires == final_op.wires @@ -1045,7 +1045,7 @@ def circuit(weights): true_grad = 100 * -qnp.sqrt(2) * qnp.cos(weights[0] / 2) * qnp.sin(weights[0] / 2) assert qnp.allclose(grad, true_grad) - def test_non_hermitian_op_in_measurement_process(self): + def test_non_hermitian_obs_not_supported(self): """Test that non-hermitian ops in a measurement process will raise a warning.""" wires = [0, 1] dev = qml.device("default.qubit", wires=wires) @@ -1056,7 +1056,7 @@ def my_circ(): qml.PauliX(0) return qml.expval(sprod_op) - with pytest.warns(UserWarning, match="SProd might not be hermitian."): + with pytest.raises(NotImplementedError): my_circ() @pytest.mark.torch @@ -1106,7 +1106,7 @@ def test_tensorflow_qnode(self, diff_method): def circuit(s): return qml.expval(qml.s_prod(s, qml.PauliZ(0))) - res = circuit(tf.Variable(2)) + res = circuit(tf.Variable(2, dtype=tf.float64)) assert qml.math.allclose(res, 2) diff --git a/tests/ops/qubit/test_hamiltonian.py b/tests/ops/qubit/test_hamiltonian.py index fe1961f71a6..3a9ede92715 100644 --- a/tests/ops/qubit/test_hamiltonian.py +++ b/tests/ops/qubit/test_hamiltonian.py @@ -1704,7 +1704,7 @@ def combine(coeffs, param): def test_nontrainable_coeffs_paramshift(self): """Test the parameter-shift method if the coefficients are explicitly set non-trainable by not passing them to the qnode.""" - coeffs = pnp.array([-0.05, 0.17], requires_grad=False) + coeffs = np.array([-0.05, 0.17]) param = pnp.array(1.7, requires_grad=True) # differentiating a circuit with measurement expval(H) @@ -1898,7 +1898,7 @@ def circuit(coeffs, param): ) res = circuit(coeffs, param) - res.backward() + res.backward() # pylint:disable=no-member grad = (coeffs.grad, param.grad) # differentiating a cost that combines circuits with @@ -1940,7 +1940,7 @@ def circuit(coeffs, param): ) res = circuit(coeffs, param) - res.backward() + res.backward() # pylint:disable=no-member # differentiating a cost that combines circuits with # measurements expval(Pauli) @@ -2069,7 +2069,7 @@ def circuit(coeffs, param): grad_fn = qml.grad(circuit) with pytest.raises( - qml.QuantumFunctionError, - match="Adjoint differentiation method does not support Hamiltonian observables", + qml.DeviceError, + match="Adjoint differentiation method does not support observable Hamiltonian", ): grad_fn(coeffs, param) diff --git a/tests/ops/qubit/test_parametric_ops.py b/tests/ops/qubit/test_parametric_ops.py index ba71bd3208e..7e874328911 100644 --- a/tests/ops/qubit/test_parametric_ops.py +++ b/tests/ops/qubit/test_parametric_ops.py @@ -2554,6 +2554,7 @@ def test_globalphase_autograd_grad(self, tol, dev_name, diff_method): @qml.qnode(dev, diff_method=diff_method) def circuit(x): + qml.Identity(0) qml.Hadamard(1) qml.ctrl(qml.GlobalPhase(x), 1) qml.Hadamard(1) @@ -2899,6 +2900,7 @@ def test_globalphase_tf_grad(self, tol, dev_name, diff_method): @qml.qnode(dev, diff_method=diff_method) def circuit(x): + qml.Identity(0) qml.Hadamard(1) qml.ctrl(qml.GlobalPhase(x), 1) qml.Hadamard(1) @@ -3055,6 +3057,7 @@ def test_globalphase_jax_grad(self, tol, dev_name, diff_method): @qml.qnode(dev, diff_method=diff_method) def circuit(x): + qml.Identity(0) qml.Hadamard(1) qml.ctrl(qml.GlobalPhase(x), 1) qml.Hadamard(1) @@ -3078,6 +3081,7 @@ def test_globalphase_torch_grad(self, tol, dev_name, diff_method): @qml.qnode(dev, diff_method=diff_method) def circuit(x): + qml.Identity(0) qml.Hadamard(1) qml.ctrl(qml.GlobalPhase(x), 1) qml.Hadamard(1) diff --git a/tests/ops/qubit/test_sparse.py b/tests/ops/qubit/test_sparse.py index 30039971588..883c96cec32 100644 --- a/tests/ops/qubit/test_sparse.py +++ b/tests/ops/qubit/test_sparse.py @@ -193,8 +193,10 @@ def test_sparse_hamiltonian_expval(self, qubits, operations, hamiltonian, expect hamiltonian = csr_matrix(hamiltonian) dev = qml.device("default.qubit", wires=qubits, shots=None) - dev.apply(operations) - expval = dev.expval(qml.SparseHamiltonian(hamiltonian, range(qubits)))[0] + qs = qml.tape.QuantumScript( + operations, [qml.expval((qml.SparseHamiltonian(hamiltonian, range(qubits))))] + ) + expval = dev.execute(qs) assert np.allclose(expval, expected_output, atol=tol, rtol=0) @@ -203,7 +205,10 @@ def test_sparse_expval_error(self): shots is requested.""" hamiltonian = csr_matrix(np.array([[1.0, 0.0], [0.0, 1.0]])) - dev = qml.device("default.qubit", wires=1, shots=1) + dev = qml.device("default.qubit", wires=1) + qs = qml.tape.QuantumScript( + measurements=[qml.expval(qml.SparseHamiltonian(hamiltonian, [0]))], shots=1 + ) - with pytest.raises(AssertionError, match="SparseHamiltonian must be used with shots=None"): - dev.expval(qml.SparseHamiltonian(hamiltonian, [0])) + with pytest.raises(qml.operation.DiagGatesUndefinedError): + dev.execute(qs) diff --git a/tests/pulse/test_hardware_hamiltonian.py b/tests/pulse/test_hardware_hamiltonian.py index 566c3c22e13..09933ba2ccf 100644 --- a/tests/pulse/test_hardware_hamiltonian.py +++ b/tests/pulse/test_hardware_hamiltonian.py @@ -662,7 +662,7 @@ def qnode_jit(params): res_jit = qnode_jit(params) assert isinstance(res, jax.Array) - assert res == res_jit + assert qml.math.allclose(res, res_jit) @pytest.mark.jax def test_jitted_qnode_multidrive(self): @@ -747,4 +747,4 @@ def qnode_jit(params): res_jit = qnode_jit(params) assert isinstance(res, jax.Array) - assert res == res_jit + assert qml.math.allclose(res, res_jit) diff --git a/tests/qchem/test_dipole.py b/tests/qchem/test_dipole.py index e19db8fe3f3..23554cf3518 100644 --- a/tests/qchem/test_dipole.py +++ b/tests/qchem/test_dipole.py @@ -285,7 +285,9 @@ def test_gradient_expvalD(): mol = qchem.Molecule(symbols, geometry, charge=1, alpha=alpha) args = [mol.alpha] - dev = qml.device("default.qubit", wires=6) + # TODO: `d_qubit[0]` has coeff dtype complex, but is actually a real-valued Hamiltonian + # default.qubit.legacy casts Hamiltonian expectations to real, but default.qubit does not + dev = qml.device("default.qubit.legacy", wires=6) def dipole(mol): @qml.qnode(dev) diff --git a/tests/qchem/test_hamiltonians.py b/tests/qchem/test_hamiltonians.py index c6c9f3c091a..78caa5bf68a 100644 --- a/tests/qchem/test_hamiltonians.py +++ b/tests/qchem/test_hamiltonians.py @@ -284,7 +284,7 @@ def test_gradient_expvalH(): mol = qchem.Molecule(symbols, geometry, alpha=alpha) args = [alpha] - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) def energy(mol): @qml.qnode(dev) @@ -336,7 +336,7 @@ def test_gradient_expvalH(self): mol = qchem.Molecule(symbols, geometry, alpha=alpha) args = [jax.numpy.array(alpha)] - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) def energy(mol): @qml.qnode(dev, interface="jax") diff --git a/tests/qinfo/test_fisher.py b/tests/qinfo/test_fisher.py index 26a5456631d..7ccae1e9e29 100644 --- a/tests/qinfo/test_fisher.py +++ b/tests/qinfo/test_fisher.py @@ -157,7 +157,7 @@ def qfunc(params): qml.RX(params[0], wires=0) qml.RX(params[1], wires=0) qml.CNOT(wires=(0, 1)) - return qml.state() + return qml.probs() params = pnp.random.random(2) diff --git a/tests/qnn/test_keras.py b/tests/qnn/test_keras.py index f8261f3af8f..34566606cf9 100644 --- a/tests/qnn/test_keras.py +++ b/tests/qnn/test_keras.py @@ -915,7 +915,7 @@ def circuit(inputs, w1, w2): assert info["num_observables"] == 2 assert info["num_diagonalizing_gates"] == 0 - assert info["num_device_wires"] == 3 + assert info["num_device_wires"] == 2 assert info["num_trainable_params"] == 2 assert info["interface"] == "tf" - assert info["device_name"] == "default.qubit.tf" + assert info["device_name"] == "default.qubit" diff --git a/tests/qnn/test_qnn_torch.py b/tests/qnn/test_qnn_torch.py index d1a4b385800..ba2701063a9 100644 --- a/tests/qnn/test_qnn_torch.py +++ b/tests/qnn/test_qnn_torch.py @@ -666,8 +666,6 @@ def compute_matrix( z = params[0] return np.diag([z, z]) - device.operations.add("DummyOp") - @qml.qnode(device=device, interface="torch", diff_method="parameter-shift") def circ(inputs, w0): # pylint: disable=unused-argument DummyOp(inputs[0], wires=0) @@ -849,7 +847,7 @@ def circuit(inputs, w1, w2): assert info["num_observables"] == 2 assert info["num_diagonalizing_gates"] == 0 - assert info["num_device_wires"] == 3 + assert info["num_device_wires"] == 2 assert info["num_trainable_params"] == 0 assert info["interface"] == "torch" - assert info["device_name"] == "default.qubit.torch" + assert info["device_name"] == "default.qubit" diff --git a/tests/shadow/test_shadow_entropies.py b/tests/shadow/test_shadow_entropies.py index 5987723c418..1de2af20454 100644 --- a/tests/shadow/test_shadow_entropies.py +++ b/tests/shadow/test_shadow_entropies.py @@ -77,9 +77,10 @@ def test_non_constant_distribution( """Test entropies match roughly with exact solution for a non-constant distribution using other PennyLane functionalities""" n_wires = 4 # exact solution + dev_exact = qml.device("default.qubit", wires=range(n_wires), shots=None) dev = qml.device("default.qubit", wires=range(n_wires), shots=100000) - @qml.qnode(dev) + @qml.qnode(dev_exact) def qnode_exact(x): for i in range(n_wires): qml.RY(x[i], wires=i) diff --git a/tests/shadow/test_shadow_transforms.py b/tests/shadow/test_shadow_transforms.py index c924a2dc65d..ef91d5956cf 100644 --- a/tests/shadow/test_shadow_transforms.py +++ b/tests/shadow/test_shadow_transforms.py @@ -197,9 +197,8 @@ def circuit_shadow(): qml.CNOT(wires=[0, 1]) return qml.classical_shadow(wires=[0, 1]), qml.expval(qml.PauliZ(0)) - msg = "Classical shadows cannot be returned in combination with other return types" - with pytest.raises(qml.QuantumFunctionError, match=msg): - circuit_shadow() + res = circuit_shadow() + assert isinstance(res, tuple) and len(res) == 2 @qml.qnode(dev) def circuit_expval(): @@ -207,8 +206,8 @@ def circuit_expval(): qml.CNOT(wires=[0, 1]) return qml.shadow_expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(0)) - with pytest.raises(qml.QuantumFunctionError, match=msg): - circuit_expval() + res = circuit_expval() + assert isinstance(res, tuple) and len(res) == 2 @pytest.mark.all_interfaces diff --git a/tests/tape/test_qscript.py b/tests/tape/test_qscript.py index b8618d5afc5..9e5dbca64bc 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -925,12 +925,6 @@ def test_diagonalizing_gates_not_queued(self): ), ] -warnings_matches = { - State: "Requested state or density matrix with finite shots", - VnEntropy: "Requested Von Neumann entropy with finite shots", - MutualInfo: "Requested mutual information with finite shots", -} - class TestMeasurementProcess: """Tests for the shape and numeric type of a measurement process""" @@ -1027,7 +1021,7 @@ def test_output_shapes_single(self, measurement, expected_shape, shots): b = np.array(0.2) ops = [qml.RY(a, 0), qml.RX(b, 0)] - qs = QuantumScript(ops, [measurement]) + qs = QuantumScript(ops, [measurement], shots=shots) shot_dim = len(shots) if isinstance(shots, tuple) else shots if expected_shape is None: @@ -1048,10 +1042,8 @@ def test_output_shapes_single_qnode_check(self, measurement, expected_shape, sho shape of a QNode for a single measurement.""" if shots is None and measurement.return_type is qml.measurements.Sample: pytest.skip("Sample doesn't support analytic computations.") - if isinstance(shots, tuple) and isinstance( - measurement, (qml.measurements.MutualInfoMP, qml.measurements.VnEntropyMP) - ): - pytest.skip("Shot vectors and entropies not supported.") + if shots and isinstance(measurement, qml.measurements.StateMeasurement): + pytest.skip("State measurements with finite shots not supported.") dev = qml.device("default.qubit", wires=3, shots=shots) @@ -1059,15 +1051,10 @@ def test_output_shapes_single_qnode_check(self, measurement, expected_shape, sho b = np.array(0.2) ops = [qml.RY(a, 0), qml.RX(b, 0)] - qs = QuantumScript(ops, [measurement]) + qs = QuantumScript(ops, [measurement], shots=shots) - w_match = warnings_matches.get(measurement.return_type, None) - if shots is not None and w_match is not None: - with pytest.warns(UserWarning, match=w_match): - res = qml.execute([qs], dev, gradient_fn=None)[0] - else: - # TODO: test gradient_fn is not None when the interface `execute` functions are implemented - res = qml.execute([qs], dev, gradient_fn=None)[0] + # TODO: test gradient_fn is not None when the interface `execute` functions are implemented + res = qml.execute([qs], dev, gradient_fn=None)[0] if isinstance(shots, tuple): res_shape = tuple(r.shape for r in res) @@ -1129,7 +1116,7 @@ def test_multi_measure(self, measurements, expected, shots): expectation value, variance and probability measurements.""" dev = qml.device("default.qubit", wires=3, shots=shots) - qs = QuantumScript(measurements=measurements) + qs = QuantumScript(measurements=measurements, shots=shots) if measurements[0].return_type is qml.measurements.Sample: expected[1] = shots @@ -1163,7 +1150,7 @@ def test_multi_measure_shot_vector(self, measurements, expected): a = np.array(0.1) b = np.array(0.2) ops = [qml.RY(a, 0), qml.RX(b, 0)] - qs = QuantumScript(ops, measurements) + qs = QuantumScript(ops, measurements, shots=shots) # Update expected as we're using a shotvector expected = tuple(expected for _ in shots) @@ -1188,7 +1175,9 @@ def test_multi_measure_sample(self, shots): num_samples = 3 ops = [qml.RY(a, 0), qml.RX(b, 0)] - qs = QuantumScript(ops, [qml.sample(qml.PauliZ(i)) for i in range(num_samples)]) + qs = QuantumScript( + ops, [qml.sample(qml.PauliZ(i)) for i in range(num_samples)], shots=shots + ) expected = tuple(() if shots == 1 else (shots,) for _ in range(num_samples)) @@ -1226,7 +1215,7 @@ def test_broadcasting_single(self, measurement, expected_shape, shots): qml.RX(b, wires=0) qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) expected_shape = qml.execute([tape], dev, gradient_fn=None)[0].shape assert tape.shape(dev) == expected_shape @@ -1254,7 +1243,7 @@ def test_broadcasting_multi(self, measurement, expected, shots): for _ in range(2): qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) expected = qml.execute([tape], dev, gradient_fn=None)[0] actual = tape.shape(dev) @@ -1273,7 +1262,9 @@ def test_multi_measure_sample_obs_shot_vector(self): num_samples = 3 ops = [qml.RY(a, 0), qml.RX(b, 0)] - qs = QuantumScript(ops, [qml.sample(qml.PauliZ(i)) for i in range(num_samples)]) + qs = QuantumScript( + ops, [qml.sample(qml.PauliZ(i)) for i in range(num_samples)], shots=shots + ) expected = tuple(tuple(() if s == 1 else (s,) for _ in range(num_samples)) for s in shots) @@ -1294,7 +1285,7 @@ def test_multi_measure_sample_wires_shot_vector(self): num_samples = 3 ops = [qml.RY(0.3, 0), qml.RX(0.2, 0)] - qs = QuantumScript(ops, [qml.sample()] * num_samples) + qs = QuantumScript(ops, [qml.sample()] * num_samples, shots=shots) expected = tuple( tuple((3,) if s == 1 else (s, 3) for _ in range(num_samples)) for s in shots @@ -1318,7 +1309,7 @@ def test_raises_broadcasting_shot_vector(self): qml.RX(np.array([0.3, 0.4]), wires=0) qml.expval(qml.PauliZ(0)) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=(1, 2, 3)) msg = "Parameter broadcasting when using a shot vector is not supported yet" with pytest.raises(NotImplementedError, match=msg): @@ -1343,21 +1334,13 @@ def test_float_measures(self, ret, shots): """Test that most measurements output floating point values and that the tape output domain correctly identifies this.""" dev = qml.device("default.qubit", wires=3, shots=shots) - if isinstance(shots, tuple) and isinstance( - ret, (qml.measurements.MutualInfoMP, qml.measurements.VnEntropyMP) - ): - pytest.skip("Shot vectors and entropies not supported.") + if shots and isinstance(ret, (qml.measurements.MutualInfoMP, qml.measurements.VnEntropyMP)): + pytest.skip("Shots and entropies not supported.") a, b = 0.3, 0.2 ops = [qml.RY(a, 0), qml.RZ(b, 0)] - qs = QuantumScript(ops, [ret]) - - w_match = warnings_matches.get(ret.return_type, None) - if shots is not None and w_match is not None: - with pytest.warns(UserWarning, match=w_match): - result = qml.execute([qs], dev, gradient_fn=None)[0] - else: - result = qml.execute([qs], dev, gradient_fn=None)[0] + qs = QuantumScript(ops, [ret], shots=shots) + result = qml.execute([qs], dev, gradient_fn=None)[0] if not isinstance(result, tuple): result = (result,) @@ -1390,7 +1373,7 @@ def test_sample_int_eigvals(self, ret): sampling measurement with a Hermitian observable with integer eigenvalues.""" dev = qml.device("default.qubit", wires=3, shots=5) - qs = QuantumScript([qml.RY(0.4, 0)], [ret]) + qs = QuantumScript([qml.RY(0.4, 0)], [ret], shots=5) result = qml.execute([qs], dev, gradient_fn=None)[0] @@ -1413,7 +1396,7 @@ def test_sample_real_eigvals(self): ) herm = np.outer(arr, arr) - qs = QuantumScript([qml.RY(0.4, 0)], [qml.sample(qml.Hermitian(herm, wires=0))]) + qs = QuantumScript([qml.RY(0.4, 0)], [qml.sample(qml.Hermitian(herm, wires=0))], shots=5) result = qml.execute([qs], dev, gradient_fn=None)[0] @@ -1439,7 +1422,7 @@ def test_sample_real_and_int_eigvals(self): a, b = 0, 3 ops = [qml.RY(a, 0), qml.RX(b, 0)] m = [qml.sample(qml.Hermitian(herm, wires=0)), qml.sample(qml.PauliZ(1))] - qs = QuantumScript(ops, m) + qs = QuantumScript(ops, m, shots=5) result = qml.execute([qs], dev, gradient_fn=None)[0] diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index a8c33a9d73f..e509694f117 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -1234,31 +1234,26 @@ def test_expand_does_not_affect_original_tape(self): assert qml.equal(expanded.measurements[1], qml.expval(qml.PauliZ(0))) assert expanded.shots is tape.shots - def test_is_sampled_reserved_after_expansion(self, monkeypatch): + def test_is_sampled_reserved_after_expansion(self): """Test that the is_sampled property is correctly set when tape expansion happens.""" dev = qml.device("default.qubit", wires=1, shots=10) - # Remove support for an op to enforce decomposition & tape expansion - mock_ops = copy.copy(dev.operations) - mock_ops.remove("T") + class UnsupportedT(qml.operation.Operation): + """A T gate that provides a decomposition, but no matrix.""" - with monkeypatch.context() as m: - m.setattr(dev, "operations", mock_ops) + @staticmethod + def compute_decomposition(wires): # pylint:disable=arguments-differ + return [qml.PhaseShift(np.pi / 4, wires=wires)] - def circuit(): - qml.T(wires=0) - return sample(qml.PauliZ(0)) - - # Choosing parameter-shift not to swap the device under the hood - qnode = qml.QNode(circuit, dev, diff_method="parameter-shift") - qnode() + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + UnsupportedT(wires=0) + return sample(qml.PauliZ(0)) - # Double-checking that the T gate is not supported - assert "T" not in qnode.device.operations - assert "T" not in qnode._original_device.operations + circuit() - assert qnode.qtape.is_sampled + assert circuit.qtape.is_sampled class TestExecution: @@ -1390,11 +1385,12 @@ def test_prob_expectation_values(self, tol): assert isinstance(res, tuple) assert len(res) == 2 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], np.float64) assert np.allclose(res[0], np.cos(x), atol=tol, rtol=0) assert isinstance(res[1], np.ndarray) - assert np.allclose(res[1], np.abs(dev.state) ** 2, atol=tol, rtol=0) + final_state, _ = qml.devices.qubit.get_final_state(tape) + assert np.allclose(res[1], np.abs(final_state.flatten()) ** 2, atol=tol, rtol=0) def test_single_mode_sample(self): """Test that there is only one array of values returned @@ -1409,6 +1405,7 @@ def test_single_mode_sample(self): qml.CNOT(wires=[0, 1]) qml.sample(qml.PauliZ(0) @ qml.PauliX(1)) + tape._shots = qml.measurements.Shots(10) res = dev.execute(tape) assert res.shape == (10,) @@ -1426,6 +1423,7 @@ def test_multiple_samples(self): qml.sample(qml.PauliZ(0)) qml.sample(qml.PauliZ(1)) + tape._shots = qml.measurements.Shots(10) res = dev.execute(tape) assert isinstance(res, tuple) assert isinstance(res[0], np.ndarray) @@ -1447,22 +1445,27 @@ def test_samples_expval(self): qml.sample(qml.PauliZ(0)) qml.expval(qml.PauliZ(1)) + tape._shots = qml.measurements.Shots(10) res = dev.execute(tape) assert isinstance(res, tuple) assert isinstance(res[0], np.ndarray) assert res[0].shape == (10,) - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], np.float64) assert res[1].shape == () def test_decomposition(self, tol): """Test decomposition onto a device's supported gate set""" dev = qml.device("default.qubit", wires=1) + from pennylane.devices.qubit.preprocess import _accepted_operator with QuantumTape() as tape: qml.U3(0.1, 0.2, 0.3, wires=[0]) qml.expval(qml.PauliZ(0)) - tape = tape.expand(stop_at=lambda obj: obj.name in dev.operations) + def stop_fn(op): + return isinstance(op, qml.measurements.MeasurementProcess) or _accepted_operator(op) + + tape = tape.expand(stop_at=stop_fn) res = dev.execute(tape) assert np.allclose(res, np.cos(0.1), atol=tol, rtol=0) @@ -1856,7 +1859,7 @@ def test_output_shapes_single(self, measurement, expected_shape, shots): qml.RX(b, wires=0) qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) shot_dim = shots if not isinstance(shots, tuple) else len(shots) if expected_shape is None: expected_shape = shot_dim if shot_dim == 1 else (shot_dim,) @@ -1900,7 +1903,7 @@ def test_output_shapes_single_qnode_check(self, measurement, _, shots): qml.RX(b, wires=0) qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) res = qml.execute([tape], dev, gradient_fn=qml.gradients.param_shift)[0] if isinstance(res, tuple): @@ -1976,7 +1979,7 @@ def test_multi_measure(self, measurements, expected, shots): for m in measurements: qml.apply(m) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) if measurements[0].return_type is qml.measurements.Sample: expected[1] = shots expected = tuple(expected) @@ -2015,7 +2018,7 @@ def test_multi_measure_shot_vector(self, measurements, expected): for m in measurements: qml.apply(m) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) # Modify expected to account for shot vector expected = tuple(expected for _ in shots) res = tape.shape(dev) @@ -2038,7 +2041,7 @@ def test_multi_measure_sample(self, shots): for i in range(num_samples): qml.sample(qml.PauliZ(i)) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) if shots == 1: expected = tuple(() for _ in range(num_samples)) else: @@ -2064,7 +2067,7 @@ def test_multi_measure_sample_shot_vector(self): for i in range(num_samples): qml.sample(qml.PauliZ(i)) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) expected = [] for s in shots: if s == 1: @@ -2101,7 +2104,7 @@ def test_broadcasting_single(self, measurement, _, shots): qml.RX(b, wires=0) qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) expected = qml.execute([tape], dev, gradient_fn=None)[0] assert tape.shape(dev) == expected.shape @@ -2128,7 +2131,7 @@ def test_broadcasting_multi(self, measurement, expected, shots): for _ in range(2): qml.apply(measurement) - tape = qml.tape.QuantumScript.from_queue(q) + tape = qml.tape.QuantumScript.from_queue(q, shots=shots) expected = qml.execute([tape], dev, gradient_fn=None)[0] expected = tuple(i.shape for i in expected) assert tape.shape(dev) == expected @@ -2231,7 +2234,7 @@ def test_sample_real_and_int_eigvals(self): """Test that the tape can correctly determine the output domain for multiple sampling measurements with a Hermitian observable with real eigenvalues and another one with integer eigenvalues.""" - dev = qml.device("default.qubit", wires=3, shots=5, r_dtype=np.float64) + dev = qml.device("default.qubit", wires=3, shots=5) arr = np.array( [ diff --git a/tests/templates/test_embeddings/test_amplitude.py b/tests/templates/test_embeddings/test_amplitude.py index 8b8d79ba1ab..64bdd9a6783 100644 --- a/tests/templates/test_embeddings/test_amplitude.py +++ b/tests/templates/test_embeddings/test_amplitude.py @@ -79,10 +79,9 @@ def test_prepares_correct_state(self, inpt, normalize): @qml.qnode(dev) def circuit(x=None): qml.AmplitudeEmbedding(features=x, wires=range(n_qubits), normalize=normalize) - return [qml.expval(qml.PauliZ(i)) for i in range(n_qubits)] + return qml.state() - circuit(x=inpt) - state = circuit.device.state.ravel() + state = circuit(x=inpt).ravel() assert np.allclose(state, inpt) @pytest.mark.parametrize("normalize", (True, False)) @@ -112,10 +111,9 @@ def test_prepares_padded_state(self, inpt, pad): @qml.qnode(dev) def circuit(x=None): qml.AmplitudeEmbedding(features=x, wires=range(n_qubits), pad_with=pad, normalize=False) - return [qml.expval(qml.PauliZ(i)) for i in range(n_qubits)] + return qml.state() - circuit(x=inpt) - state = circuit.device.state.ravel() + state = circuit(x=inpt).ravel() # Make sure all padded values are the same constant # by checking how many different values there are assert len(set(state[len(inpt) :])) == 1 @@ -148,17 +146,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.AmplitudeEmbedding(features, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.AmplitudeEmbedding(features, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_embeddings/test_angle.py b/tests/templates/test_embeddings/test_angle.py index ef531695f3d..2cb3677269e 100644 --- a/tests/templates/test_embeddings/test_angle.py +++ b/tests/templates/test_embeddings/test_angle.py @@ -130,17 +130,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.AngleEmbedding(features, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.AngleEmbedding(features, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_embeddings/test_basis.py b/tests/templates/test_embeddings/test_basis.py index 974c2e2e335..158448338bc 100644 --- a/tests/templates/test_embeddings/test_basis.py +++ b/tests/templates/test_embeddings/test_basis.py @@ -78,17 +78,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.BasisEmbedding(features, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.BasisEmbedding(features, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_embeddings/test_iqp_emb.py b/tests/templates/test_embeddings/test_iqp_emb.py index 5eb25401b43..b0cc165f07e 100644 --- a/tests/templates/test_embeddings/test_iqp_emb.py +++ b/tests/templates/test_embeddings/test_iqp_emb.py @@ -119,17 +119,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.IQPEmbedding(features, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.IQPEmbedding(features, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_embeddings/test_qaoa_emb.py b/tests/templates/test_embeddings/test_qaoa_emb.py index de49c972d67..a33dbac9c01 100644 --- a/tests/templates/test_embeddings/test_qaoa_emb.py +++ b/tests/templates/test_embeddings/test_qaoa_emb.py @@ -215,17 +215,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.QAOAEmbedding(features, weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.QAOAEmbedding(features, weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_basic_entangler.py b/tests/templates/test_layers/test_basic_entangler.py index 4c2ca6a83bf..1e21703333d 100644 --- a/tests/templates/test_layers/test_basic_entangler.py +++ b/tests/templates/test_layers/test_basic_entangler.py @@ -92,17 +92,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.BasicEntanglerLayers(weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.BasicEntanglerLayers(weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_gate_fabric.py b/tests/templates/test_layers/test_gate_fabric.py index 260090f79d1..fedad87a0bc 100644 --- a/tests/templates/test_layers/test_gate_fabric.py +++ b/tests/templates/test_layers/test_gate_fabric.py @@ -484,11 +484,9 @@ def test_decomposition_q(self, init_state, exp_state, tol): @qml.qnode(dev) def circuit(weight): qml.GateFabric(weight, wires, init_state=init_state) - return qml.expval(qml.PauliZ(0)) - - circuit(weight) + return qml.state() - assert qml.math.allclose(circuit.device.state, exp_state, atol=tol) + assert qml.math.allclose(circuit(weight), exp_state, atol=tol) @pytest.mark.parametrize( ("num_qubits", "layers", "exp_state"), @@ -608,9 +606,7 @@ def circuit(weight): qml.GateFabric(weight, wires, init_state=init_state, include_pi=True) return qml.state() - circuit(weight) - - assert qml.math.allclose(circuit.device.state, exp_state, atol=tol) + assert qml.math.allclose(circuit(weight), exp_state, atol=tol) def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" @@ -623,17 +619,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.GateFabric(weights, wires=range(4), init_state=init_state) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.GateFabric(weights, wires=["z", "a", "k", "r"], init_state=init_state) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert qml.math.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_particle_conserving_u1.py b/tests/templates/test_layers/test_particle_conserving_u1.py index 15fd62056d3..9a5915ca886 100644 --- a/tests/templates/test_layers/test_particle_conserving_u1.py +++ b/tests/templates/test_layers/test_particle_conserving_u1.py @@ -134,17 +134,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.ParticleConservingU1(weights, wires=range(3), init_state=init_state) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.ParticleConservingU1(weights, wires=["z", "a", "k"], init_state=init_state) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) @pytest.mark.parametrize( ("init_state", "exp_state"), @@ -198,11 +199,9 @@ def test_decomposition_u1ex(self, init_state, exp_state, tol): @qml.qnode(dev) def circuit(weights): qml.ParticleConservingU1(weights, wires, init_state=init_state) - return qml.expval(qml.PauliZ(0)) - - circuit(weights) + return qml.state() - assert np.allclose(circuit.device.state, exp_state, atol=tol) + assert np.allclose(circuit(weights), exp_state, atol=tol) class TestInputs: diff --git a/tests/templates/test_layers/test_particle_conserving_u2.py b/tests/templates/test_layers/test_particle_conserving_u2.py index 163aa458484..55ffd0a27ba 100644 --- a/tests/templates/test_layers/test_particle_conserving_u2.py +++ b/tests/templates/test_layers/test_particle_conserving_u2.py @@ -111,11 +111,9 @@ def test_decomposition_u2ex(self, init_state, exp_state, tol): def circuit(weight): qml.BasisState(init_state, wires=wires) qml.particle_conserving_u2.u2_ex_gate(weight, wires) - return qml.expval(qml.PauliZ(0)) - - circuit(weight) + return qml.state() - assert np.allclose(circuit.device.state, exp_state, atol=tol) + assert np.allclose(circuit(weight), exp_state, atol=tol) def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" @@ -128,17 +126,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.ParticleConservingU2(weights, wires=range(3), init_state=init_state) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.ParticleConservingU2(weights, wires=["z", "a", "k"], init_state=init_state) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_random.py b/tests/templates/test_layers/test_random.py index c8e5a034f20..37014185720 100644 --- a/tests/templates/test_layers/test_random.py +++ b/tests/templates/test_layers/test_random.py @@ -136,17 +136,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.RandomLayers(weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.RandomLayers(weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_simplified_twodesign.py b/tests/templates/test_layers/test_simplified_twodesign.py index 7d0c8edb7eb..860d951f880 100644 --- a/tests/templates/test_layers/test_simplified_twodesign.py +++ b/tests/templates/test_layers/test_simplified_twodesign.py @@ -121,17 +121,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.SimplifiedTwoDesign(initial_layer, weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.SimplifiedTwoDesign(initial_layer, weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_layers/test_strongly_entangling.py b/tests/templates/test_layers/test_strongly_entangling.py index 4569a724a35..e75a203def4 100644 --- a/tests/templates/test_layers/test_strongly_entangling.py +++ b/tests/templates/test_layers/test_strongly_entangling.py @@ -76,17 +76,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.StronglyEntanglingLayers(weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.StronglyEntanglingLayers(weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) @pytest.mark.parametrize( "n_layers, n_wires, ranges", [(2, 2, [1, 1]), (1, 3, [2]), (4, 4, [2, 3, 1, 3])] diff --git a/tests/templates/test_state_preparations/test_arbitrary_state_prep.py b/tests/templates/test_state_preparations/test_arbitrary_state_prep.py index d96bf25f69a..ba3a88ef399 100644 --- a/tests/templates/test_state_preparations/test_arbitrary_state_prep.py +++ b/tests/templates/test_state_preparations/test_arbitrary_state_prep.py @@ -118,23 +118,23 @@ def test_correct_gates_two_wires(self): assert queue[5].hyperparameters["pauli_word"] == "XY" assert queue[5].wires.labels == (0, 1) - def test_GHZ_generation(self, qubit_device_3_wires, tol): + def test_GHZ_generation(self, tol): """Test that the template prepares a GHZ state.""" GHZ_state = np.array([1 / np.sqrt(2), 0, 0, 0, 0, 0, 0, 1 / np.sqrt(2)]) weights = np.zeros(14) weights[13] = np.pi / 2 - @qml.qnode(qubit_device_3_wires) + @qml.qnode(qml.device("default.qubit")) def circuit(weights): qml.ArbitraryStatePreparation(weights, [0, 1, 2]) - return qml.expval(qml.PauliZ(0)) + return qml.expval(qml.PauliZ(0)), qml.state() - circuit(weights) + _, state = circuit(weights) - assert np.allclose(circuit.device.state, GHZ_state, atol=tol, rtol=0) + assert np.allclose(state, GHZ_state, atol=tol, rtol=0) - def test_even_superposition_generation(self, qubit_device_3_wires, tol): + def test_even_superposition_generation(self, tol): """Test that the template prepares an even superposition state.""" even_superposition_state = np.ones(8) / np.sqrt(8) @@ -143,15 +143,15 @@ def test_even_superposition_generation(self, qubit_device_3_wires, tol): weights[3] = np.pi / 2 weights[5] = np.pi / 2 - @qml.qnode(qubit_device_3_wires) + @qml.qnode(qml.device("default.qubit")) def circuit(weights): qml.ArbitraryStatePreparation(weights, [0, 1, 2]) - return qml.expval(qml.PauliZ(0)) + return qml.expval(qml.PauliZ(0)), qml.state() - circuit(weights) + _, state = circuit(weights) - assert np.allclose(circuit.device.state, even_superposition_state, atol=tol, rtol=0) + assert np.allclose(state, even_superposition_state, atol=tol, rtol=0) def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" @@ -163,17 +163,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.ArbitraryStatePreparation(weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.ArbitraryStatePreparation(weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_state_preparations/test_basis_state_prep.py b/tests/templates/test_state_preparations/test_basis_state_prep.py index 5819f867e2c..b63b01a33f7 100644 --- a/tests/templates/test_state_preparations/test_basis_state_prep.py +++ b/tests/templates/test_state_preparations/test_basis_state_prep.py @@ -62,10 +62,10 @@ def test_correct_pl_gates(self, basis_state, wires, target_wires): ([1, 0, 1], [0, 1, 2], [1, 0, 1]), ]) # fmt: on - def test_state_preparation(self, tol, qubit_device_3_wires, basis_state, wires, target_state): + def test_state_preparation(self, tol, basis_state, wires, target_state): """Tests that the template produces the correct expectation values.""" - @qml.qnode(qubit_device_3_wires) + @qml.qnode(qml.device("default.qubit")) def circuit(): qml.BasisStatePreparation(basis_state, wires) @@ -86,13 +86,11 @@ def circuit(): ([1, 0, 1], [2, 0, 1], [0, 1, 1]), ], ) - def test_state_preparation_jax_jit( - self, tol, qubit_device_3_wires, basis_state, wires, target_state - ): + def test_state_preparation_jax_jit(self, tol, basis_state, wires, target_state): """Tests that the template produces the correct expectation values.""" import jax - @qml.qnode(qubit_device_3_wires, interface="jax") + @qml.qnode(qml.device("default.qubit"), interface="jax") def circuit(state): qml.BasisStatePreparation(state, wires) @@ -115,14 +113,12 @@ def circuit(state): ([1, 0, 1], [2, 0, 1], [0, 1, 1]), ], ) - def test_state_preparation_tf_autograph( - self, tol, qubit_device_3_wires, basis_state, wires, target_state - ): + def test_state_preparation_tf_autograph(self, tol, basis_state, wires, target_state): """Tests that the template produces the correct expectation values.""" import tensorflow as tf @tf.function - @qml.qnode(qubit_device_3_wires, interface="tf") + @qml.qnode(qml.device("default.qubit"), interface="tf") def circuit(state): qml.BasisStatePreparation(state, wires) @@ -144,17 +140,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.BasisStatePreparation(basis_state, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.BasisStatePreparation(basis_state, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_state_preparations/test_mottonen_state_prep.py b/tests/templates/test_state_preparations/test_mottonen_state_prep.py index 6548e44464e..f7ac7bb3844 100644 --- a/tests/templates/test_state_preparations/test_mottonen_state_prep.py +++ b/tests/templates/test_state_preparations/test_mottonen_state_prep.py @@ -122,19 +122,22 @@ class TestDecomposition: ([1 / 2, 0, 1j / 2, 1j / np.sqrt(2)], [0, 1], [1 / 2, 0, 0, 0, 1j / 2, 0, 1j / np.sqrt(2), 0]), ]) # fmt: on - def test_state_preparation_fidelity( - self, tol, qubit_device_3_wires, state_vector, wires, target_state - ): + def test_state_preparation_fidelity(self, tol, state_vector, wires, target_state): """Tests that the template produces correct states with high fidelity.""" - @qml.qnode(qubit_device_3_wires) + @qml.qnode(qml.device("default.qubit", wires=3)) def circuit(): qml.MottonenStatePreparation(state_vector, wires) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(qml.PauliZ(2)) + return ( + qml.expval(qml.PauliZ(0)), + qml.expval(qml.PauliZ(1)), + qml.expval(qml.PauliZ(2)), + qml.state(), + ) - circuit() + results = circuit() - state = circuit.device.state.ravel() + state = results[-1].ravel() fidelity = abs(np.vdot(state, target_state)) ** 2 # We test for fidelity here, because the vector themselves will hardly match @@ -207,18 +210,23 @@ def circuit(): ]) # fmt: on def test_state_preparation_probability_distribution( - self, tol, qubit_device_3_wires, state_vector, wires, target_state + self, tol, state_vector, wires, target_state ): """Tests that the template produces states with correct probability distribution.""" - @qml.qnode(qubit_device_3_wires) + @qml.qnode(qml.device("default.qubit", wires=3)) def circuit(): qml.MottonenStatePreparation(state_vector, wires) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(qml.PauliZ(2)) + return ( + qml.expval(qml.PauliZ(0)), + qml.expval(qml.PauliZ(1)), + qml.expval(qml.PauliZ(2)), + qml.state(), + ) - circuit() + results = circuit() - state = circuit.device.state.ravel() + state = results[-1].ravel() probabilities = np.abs(state) ** 2 target_probabilities = np.abs(target_state) ** 2 @@ -254,7 +262,7 @@ def circuit(state_vector): # when the RZ cascade is skipped, CNOT gates should only be those required for RY cascade spy = mocker.spy(circuit.device, "execute") circuit(state_vector) - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] assert tape.specs["resources"].gate_types["CNOT"] == n_CNOT @@ -268,17 +276,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.MottonenStatePreparation(state, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.MottonenStatePreparation(state, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_subroutines/test_all_singles_doubles.py b/tests/templates/test_subroutines/test_all_singles_doubles.py index cb37e63cd7a..a0e5413f521 100644 --- a/tests/templates/test_subroutines/test_all_singles_doubles.py +++ b/tests/templates/test_subroutines/test_all_singles_doubles.py @@ -120,7 +120,7 @@ def circuit(): singles=[[0, 1]], doubles=[[0, 1, 2, 3]], ) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): @@ -131,12 +131,13 @@ def circuit2(): singles=[["z", "a"]], doubles=[["z", "a", "k", "e"]], ) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: @@ -191,7 +192,7 @@ class TestInputs: [[0, 2]], [[0, 1, 2, 3]], np.array([1, 1, 0, 0, 0]), - "BasisState parameter and wires", + "Basis states must be of length 4", ), ( np.array([-2.8, 1.6]), diff --git a/tests/templates/test_subroutines/test_approx_time_evolution.py b/tests/templates/test_subroutines/test_approx_time_evolution.py index 18e2c585f8a..82203dbd926 100644 --- a/tests/templates/test_subroutines/test_approx_time_evolution.py +++ b/tests/templates/test_subroutines/test_approx_time_evolution.py @@ -166,17 +166,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.ApproxTimeEvolution(hamiltonian, 0.5, 2) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.ApproxTimeEvolution(hamiltonian2, 0.5, 2) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: @@ -410,7 +411,7 @@ def create_tape(coeffs, t): def cost(coeffs, t): tape = create_tape(coeffs, t) - if diff_method is qml.gradients.param_shift: + if diff_method is qml.gradients.param_shift and dev_name != "default.qubit": tape = dev.expand_fn(tape) return qml.execute([tape], dev, diff_method)[0] diff --git a/tests/templates/test_subroutines/test_arbitrary_unitary.py b/tests/templates/test_subroutines/test_arbitrary_unitary.py index afb45087a42..7f6ac28cd6a 100644 --- a/tests/templates/test_subroutines/test_arbitrary_unitary.py +++ b/tests/templates/test_subroutines/test_arbitrary_unitary.py @@ -158,17 +158,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.ArbitraryUnitary(weights, wires=range(3)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.ArbitraryUnitary(weights, wires=["z", "a", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_subroutines/test_basis_rotation.py b/tests/templates/test_subroutines/test_basis_rotation.py index 7767dd763c6..f969e001ba7 100644 --- a/tests/templates/test_subroutines/test_basis_rotation.py +++ b/tests/templates/test_subroutines/test_basis_rotation.py @@ -101,7 +101,7 @@ def circuit(): wires=range(2), unitary_matrix=weights, ) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): @@ -110,12 +110,13 @@ def circuit2(): wires=["z", "a"], unitary_matrix=weights, ) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) @pytest.mark.parametrize( ("unitary_matrix", "eigen_values", "exp_state"), diff --git a/tests/templates/test_subroutines/test_commuting_evolution.py b/tests/templates/test_subroutines/test_commuting_evolution.py index 7cb8c22c02a..e36ad81c76a 100644 --- a/tests/templates/test_subroutines/test_commuting_evolution.py +++ b/tests/templates/test_subroutines/test_commuting_evolution.py @@ -47,32 +47,32 @@ def test_adjoint(): """Tests the CommutingEvolution.adjoint method provides the correct adjoint operation.""" n_wires = 2 - dev1 = qml.device("default.qubit", wires=n_wires) - dev2 = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] coeffs = [1, -1] hamiltonian = qml.Hamiltonian(coeffs, obs) frequencies = (2,) - @qml.qnode(dev1) + @qml.qnode(dev) def adjoint_evolution_circuit(time): for i in range(n_wires): qml.Hadamard(i) qml.adjoint(qml.CommutingEvolution)(hamiltonian, time, frequencies) - return qml.expval(qml.PauliZ(1)) + return qml.expval(qml.PauliZ(1)), qml.state() - @qml.qnode(dev2) + @qml.qnode(dev) def evolution_circuit(time): for i in range(n_wires): qml.Hadamard(i) qml.CommutingEvolution(hamiltonian, time, frequencies) - return qml.expval(qml.PauliZ(1)) + return qml.expval(qml.PauliZ(1)), qml.state() - evolution_circuit(0.13) - adjoint_evolution_circuit(-0.13) + res1, state1 = evolution_circuit(0.13) + res2, state2 = adjoint_evolution_circuit(-0.13) - assert all(np.isclose(dev1.state, dev2.state)) + assert res1 == res2 + assert all(np.isclose(state1, state2)) def test_decomposition_expand(): diff --git a/tests/templates/test_subroutines/test_double_excitation.py b/tests/templates/test_subroutines/test_double_excitation.py index 76768b9a1fe..39b7c317428 100644 --- a/tests/templates/test_subroutines/test_double_excitation.py +++ b/tests/templates/test_subroutines/test_double_excitation.py @@ -242,17 +242,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.FermionicDoubleExcitation(0.4, wires1=[0, 2], wires2=[1, 4, 3]) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.FermionicDoubleExcitation(0.4, wires1=["z", "k"], wires2=["a", "s", "t"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_subroutines/test_kupccgsd.py b/tests/templates/test_subroutines/test_kupccgsd.py index 0343cb4d34f..4a1801985ae 100644 --- a/tests/templates/test_subroutines/test_kupccgsd.py +++ b/tests/templates/test_subroutines/test_kupccgsd.py @@ -137,7 +137,7 @@ def circuit(): delta_sz=0, init_state=np.array([0, 1, 0, 1]), ) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): @@ -148,12 +148,13 @@ def circuit2(): delta_sz=0, init_state=np.array([0, 1, 0, 1]), ) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) @pytest.mark.parametrize( ("num_qubits", "k", "exp_state"), @@ -256,9 +257,9 @@ def circuit(weight): qml.kUpCCGSD(weight, wires=wires, k=k, delta_sz=0, init_state=init_state) return qml.state() - circuit(weight) + res = circuit(weight) - assert qml.math.allclose(circuit.device.state, exp_state, atol=tol) + assert qml.math.allclose(res, exp_state, atol=tol) @pytest.mark.parametrize( ("wires", "delta_sz", "generalized_singles_wires", "generalized_pair_doubles_wires"), diff --git a/tests/templates/test_subroutines/test_permute.py b/tests/templates/test_subroutines/test_permute.py index e2d61e75308..08f240d82e3 100644 --- a/tests/templates/test_subroutines/test_permute.py +++ b/tests/templates/test_subroutines/test_permute.py @@ -37,7 +37,7 @@ def identity_permutation(): identity_permutation() # expand the Permute operation - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] assert len(tape.operations) == 0 @@ -76,7 +76,7 @@ def two_cycle(): spy = mocker.spy(two_cycle.device, "execute") two_cycle() - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -130,7 +130,7 @@ def cycle(): spy = mocker.spy(cycle.device, "execute") cycle() - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -180,7 +180,7 @@ def arbitrary_perm(): spy = mocker.spy(arbitrary_perm.device, "execute") arbitrary_perm() - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -240,7 +240,7 @@ def subset_perm(): spy = mocker.spy(subset_perm.device, "execute") subset_perm() - tape = spy.call_args[0][0] + tape = spy.call_args[0][0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -290,17 +290,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.Permute(permutation, wires=range(4)) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.Permute(permutation2, wires=["z", "a", "k", "o"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_subroutines/test_qft.py b/tests/templates/test_subroutines/test_qft.py index 08ddec4bb29..9e17377f215 100644 --- a/tests/templates/test_subroutines/test_qft.py +++ b/tests/templates/test_subroutines/test_qft.py @@ -42,10 +42,9 @@ def test_QFT_decomposition(self, n_qubits): out_states = [] for state in np.eye(2**n_qubits): - dev.reset() ops = [qml.StatePrep(state, wires=range(n_qubits))] + decomp - dev.apply(ops) - out_states.append(dev.state) + 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() diff --git a/tests/templates/test_subroutines/test_qpe.py b/tests/templates/test_subroutines/test_qpe.py index e3bd15d8b09..8037ae9c7b3 100644 --- a/tests/templates/test_subroutines/test_qpe.py +++ b/tests/templates/test_subroutines/test_qpe.py @@ -99,9 +99,10 @@ def test_phase_estimated(self, phase): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) + tapes, _ = dev.preprocess()[0]([tape]) + assert len(tapes) == 1 - res = dev.execute(tape).flatten() + res = dev.execute(tapes)[0].flatten() initial_estimate = np.argmax(res) / 2 ** (wires - 1) # We need to rescale because RX is exp(- i theta X / 2) and we expect a unitary of the @@ -150,8 +151,9 @@ def test_phase_estimated_two_qubit(self): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) - res = dev.execute(tape).flatten() + tapes, _ = dev.preprocess()[0]([tape]) + assert len(tapes) == 1 + res = dev.execute(tapes)[0].flatten() if phase < 0: estimate = np.argmax(res) / 2 ** (wires - 2) - 1 @@ -195,8 +197,9 @@ def test_phase_estimated_single_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) - res = dev.execute(tape).flatten() + tapes, _ = dev.preprocess()[0]([tape]) + res = dev.execute(tapes)[0].flatten() + assert len(tapes) == 1 estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) @@ -237,8 +240,9 @@ def test_phase_estimated_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) - res = dev.execute(tape).flatten() + tapes, _ = dev.preprocess()[0]([tape]) + assert len(tapes) == 1 + res = dev.execute(tapes)[0].flatten() estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) diff --git a/tests/templates/test_subroutines/test_single_excitation.py b/tests/templates/test_subroutines/test_single_excitation.py index 69bf98d5719..76eda25a2b8 100644 --- a/tests/templates/test_subroutines/test_single_excitation.py +++ b/tests/templates/test_subroutines/test_single_excitation.py @@ -118,17 +118,18 @@ def test_custom_wire_labels(self, tol): @qml.qnode(dev) def circuit(): qml.FermionicSingleExcitation(0.4, wires=[1, 0, 2]) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): qml.FermionicSingleExcitation(0.4, wires=["a", "z", "k"]) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: diff --git a/tests/templates/test_subroutines/test_uccsd.py b/tests/templates/test_subroutines/test_uccsd.py index 5aab270d5d6..22ed28965b3 100644 --- a/tests/templates/test_subroutines/test_uccsd.py +++ b/tests/templates/test_subroutines/test_uccsd.py @@ -162,7 +162,7 @@ def circuit(): d_wires=[[[0, 1], [2, 3]]], init_state=np.array([0, 1, 0, 1]), ) - return qml.expval(qml.Identity(0)) + return qml.expval(qml.Identity(0)), qml.state() @qml.qnode(dev2) def circuit2(): @@ -173,12 +173,13 @@ def circuit2(): d_wires=[[["z", "a"], ["k", "e"]]], init_state=np.array([0, 1, 0, 1]), ) - return qml.expval(qml.Identity("z")) + return qml.expval(qml.Identity("z")), qml.state() - circuit() - circuit2() + res1, state1 = circuit() + res2, state2 = circuit2() - assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) + assert np.allclose(res1, res2, atol=tol, rtol=0) + assert np.allclose(state1, state2, atol=tol, rtol=0) class TestInputs: @@ -213,7 +214,7 @@ class TestInputs: [[0, 2]], [], np.array([1, 1, 0, 0, 0]), - "BasisState parameter and wires", + "Basis states must be of length 4", ), ( np.array([-2.8, 1.6]), diff --git a/tests/test_debugging.py b/tests/test_debugging.py index 38769399e42..1f95d33e3ee 100644 --- a/tests/test_debugging.py +++ b/tests/test_debugging.py @@ -54,30 +54,29 @@ def circuit(): assert all(np.allclose(v1, v2) for v1, v2 in zip(result.values(), expected.values())) # pylint: disable=protected-access - def test_default_qubit2(self): + @pytest.mark.parametrize("method", [None, "backprop", "parameter-shift", "adjoint"]) + def test_default_qubit2(self, method): """Test that multiple snapshots are returned correctly on the new state-vector simulator.""" - dev = qml.devices.DefaultQubit() + dev = qml.device("default.qubit") # TODO: add additional QNode test once the new device supports it - ops = [ - qml.Snapshot(), - qml.Hadamard(wires=0), - qml.Snapshot("very_important_state"), - qml.CNOT(wires=[0, 1]), - qml.Snapshot(), - ] - qs = qml.tape.QuantumScript(ops, [qml.expval(qml.PauliX(0))]) + @qml.qnode(dev, diff_method=method) + def circuit(): + qml.Snapshot() + qml.Hadamard(wires=0) + qml.Snapshot("very_important_state") + qml.CNOT(wires=[0, 1]) + qml.Snapshot() + return qml.expval(qml.PauliX(0)) - dev.execute(qs) + circuit() assert dev._debugger is None + if method is not None: + assert circuit.interface == "auto" - with qml.debugging._Debugger(dev) as dbg: - dev.execute(qs) - - result = dbg.snapshots - + result = qml.snapshots(circuit)() expected = { 0: np.array([1, 0, 0, 0]), "very_important_state": np.array([1 / np.sqrt(2), 0, 1 / np.sqrt(2), 0]), diff --git a/tests/test_qnode.py b/tests/test_qnode.py index 2e5cb755128..3934b9ee9cf 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -43,7 +43,7 @@ class TestValidation: def test_invalid_interface(self): """Test that an exception is raised for an invalid interface""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" expected_error = rf"Unknown interface {test_interface}\. Interface must be one of" @@ -53,7 +53,7 @@ def test_invalid_interface(self): def test_changing_invalid_interface(self): """Test that an exception is raised for an invalid interface on a pre-existing QNode""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" @qnode(dev) @@ -72,7 +72,7 @@ def test_valid_interface(self): """Test that changing to a valid interface works as expected, and the diff method is updated as required.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, interface="autograd", diff_method="best") def circuit(x): @@ -95,7 +95,7 @@ def test_invalid_device(self): def test_validate_device_method(self, monkeypatch): """Test that the method for validating the device diff method tape works as expected""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -124,7 +124,7 @@ def test_validate_backprop_method_invalid_device(self): def test_validate_backprop_method_invalid_interface(self, monkeypatch): """Test that the method for validating the backprop diff method tape raises an exception if the wrong interface is provided""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -136,7 +136,7 @@ def test_validate_backprop_method_invalid_interface(self, monkeypatch): def test_validate_backprop_method(self, monkeypatch): """Test that the method for validating the backprop diff method tape works as expected""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -154,7 +154,7 @@ def test_validate_backprop_method_all_interface_names(self, accepted_name, offic if accepted_name in {None, "auto", "scipy"}: pytest.skip("None is not a backprop interface.") - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) diff_method, _, new_dev = QNode._validate_backprop_method(dev, accepted_name) @@ -165,7 +165,7 @@ def test_validate_backprop_method_all_interface_names(self, accepted_name, offic def test_validate_backprop_child_method(self, monkeypatch): """Test that the method for validating the backprop diff method tape works as expected if a child device supports backprop""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -182,7 +182,7 @@ def test_validate_backprop_child_method(self, monkeypatch): def test_validate_backprop_child_method_wrong_interface(self, monkeypatch): """Test that the method for validating the backprop diff method tape raises an error if a child device supports backprop but using a different interface""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -196,7 +196,7 @@ def test_validate_backprop_child_method_wrong_interface(self, monkeypatch): # pylint: disable=protected-access @pytest.mark.autograd - @pytest.mark.parametrize("device_string", ("default.qubit", "default.qubit.autograd")) + @pytest.mark.parametrize("device_string", ("default.qubit.legacy", "default.qubit.autograd")) def test_validate_backprop_finite_shots(self, device_string): """Test that a device with finite shots cannot be used with backpropagation.""" dev = qml.device(device_string, wires=1, shots=100) @@ -209,7 +209,7 @@ def test_validate_backprop_finite_shots(self, device_string): def test_parameter_shift_qubit_device(self): """Test that the _validate_parameter_shift method returns the correct gradient transform for qubit devices.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) gradient_fn = QNode._validate_parameter_shift(dev) assert gradient_fn[0] is qml.gradients.param_shift @@ -242,7 +242,7 @@ def capabilities(cls): return capabilities monkeypatch.setattr(qml.devices.DefaultQubitLegacy, "capabilities", capabilities) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, match="does not support the parameter-shift rule" @@ -254,7 +254,7 @@ def capabilities(cls): def test_best_method_is_device(self, monkeypatch): """Test that the method for determining the best diff method for a given device and interface returns the device""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", True) @@ -270,7 +270,7 @@ def test_best_method_is_device(self, monkeypatch): def test_best_method_is_backprop(self, monkeypatch): """Test that the method for determining the best diff method for a given device and interface returns backpropagation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -282,7 +282,7 @@ def test_best_method_is_backprop(self, monkeypatch): def test_best_method_is_param_shift(self, monkeypatch): """Test that the method for determining the best diff method for a given device and interface returns the parameter shift rule""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -295,7 +295,7 @@ def test_best_method_is_param_shift(self, monkeypatch): def test_best_method_is_finite_diff(self, monkeypatch): """Test that the method for determining the best diff method for a given device and interface returns finite differences""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -313,7 +313,7 @@ def capabilities(cls): def test_best_method_str_is_device(self, monkeypatch): """Test that the method for determining the best diff method string for a given device and interface returns 'device'""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", True) @@ -329,7 +329,7 @@ def test_best_method_str_is_device(self, monkeypatch): def test_best_method_str_is_backprop(self, monkeypatch): """Test that the method for determining the best diff method string for a given device and interface returns 'backprop'""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -341,7 +341,7 @@ def test_best_method_str_is_backprop(self, monkeypatch): def test_best_method_str_is_param_shift(self, monkeypatch): """Test that the method for determining the best diff method string for a given device and interface returns 'parameter-shift'""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -354,7 +354,7 @@ def test_best_method_str_is_param_shift(self, monkeypatch): def test_best_method_str_is_finite_diff(self, monkeypatch): """Test that the method for determining the best diff method string for a given device and interface returns 'finite-diff'""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -372,7 +372,7 @@ def capabilities(cls): def test_diff_method(self, mocker): """Test that a user-supplied diff method correctly returns the right diff method.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) mock_best = mocker.patch("pennylane.QNode.get_best_method") mock_best.return_value = ("best", {}, dev) @@ -437,7 +437,7 @@ def test_diff_method(self, mocker): @pytest.mark.autograd def test_gradient_transform(self, mocker): """Test passing a gradient transform directly to a QNode""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.gradients.finite_difference, "finite_diff_coeffs") @qnode(dev, diff_method=qml.gradients.finite_diff) @@ -451,7 +451,7 @@ def circuit(x): def test_unknown_diff_method_string(self): """Test that an exception is raised for an unknown differentiation method string""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, match="Differentiation method hello not recognized" @@ -460,7 +460,7 @@ def test_unknown_diff_method_string(self): def test_unknown_diff_method_type(self): """Test that an exception is raised for an unknown differentiation method type""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -480,7 +480,7 @@ def test_validate_adjoint_invalid_device(self): def test_validate_adjoint_finite_shots(self): """Test that a UserWarning is raised when device has finite shots""" - dev = qml.device("default.qubit", wires=1, shots=1) + dev = qml.device("default.qubit.legacy", wires=1, shots=1) with pytest.warns( UserWarning, match="Requested adjoint differentiation to be computed with finite shots." @@ -492,7 +492,7 @@ def test_adjoint_finite_shots(self): on QNode construction when the device has finite shots """ - dev = qml.device("default.qubit", wires=1, shots=1) + dev = qml.device("default.qubit.legacy", wires=1, shots=1) @qnode(dev, diff_method="adjoint") def circ(): @@ -507,7 +507,7 @@ def circ(): def test_sparse_diffmethod_error(self): """Test that an error is raised when the observable is SparseHamiltonian and the differentiation method is not parameter-shift.""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) @qnode(dev, diff_method="backprop") def circuit(param): @@ -523,7 +523,7 @@ def circuit(param): def test_qnode_print(self): """Test that printing a QNode object yields the right information.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def func(x): qml.RX(x, wires=0) @@ -533,7 +533,7 @@ def func(x): assert ( repr(qn) - == "" + == "" ) qn = QNode(func, dev, interface="autograd") @@ -547,7 +547,7 @@ def func(x): def test_diff_method_none(self, tol): """Test that diff_method=None creates a QNode with no interface, and no device swapping.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, diff_method=None) def circuit(x): @@ -569,7 +569,7 @@ def circuit(x): # pylint: disable=unused-variable def test_unrecognized_kwargs_raise_warning(self): """Test that passing gradient_kwargs not included in qml.gradients.SUPPORTED_GRADIENT_KWARGS raises warning""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with warnings.catch_warnings(record=True) as w: @@ -585,7 +585,7 @@ def circuit(params): def test_incorrect_diff_method_kwargs_raise_warning(self): """Tests that using one of the incorrect kwargs previously used in some examples in PennyLane (grad_method, gradient_fn) to set the qnode diff_method raises a warning""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with warnings.catch_warnings(record=True) as w: @@ -605,7 +605,7 @@ def circuit2(params): def test_auto_interface_tracker_device_switched(self): """Test that checks that the tracker is switched to the new device.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(params): @@ -627,7 +627,7 @@ def circuit(params): def test_autograd_interface_device_switched_no_warnings(self): """Test that checks that no warning is raised for device switch when you define an interface.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev, interface="autograd") def circuit(params): @@ -642,7 +642,7 @@ def circuit(params): def test_not_giving_mode_kwarg_does_not_raise_warning(self): """Test that not providing a value for mode does not raise a warning.""" with warnings.catch_warnings(record=True) as record: - _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1)) + _ = qml.QNode(lambda f: f, qml.device("default.qubit.legacy", wires=1)) assert len(record) == 0 @@ -652,7 +652,7 @@ class TestTapeConstruction: def test_basic_tape_construction(self, tol): """Test that a quantum tape is properly constructed""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -685,7 +685,7 @@ def func(x, y): def test_jacobian(self): """Test the jacobian computation""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -709,7 +709,7 @@ def func(x, y): def test_returning_non_measurements(self): """Test that an exception is raised if a non-measurement is returned from the QNode.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func0(x, y): qml.RX(x, wires=0) @@ -753,7 +753,7 @@ def func3(x, y): def test_inconsistent_measurement_order(self): """Test that an exception is raised if measurements are returned in an order different to how they were queued on the tape""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -773,7 +773,7 @@ def func(x, y): def test_consistent_measurement_order(self): """Test evaluation proceeds as expected if measurements are returned in the same order to how they were queued on the tape""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) contents = [] @@ -804,13 +804,13 @@ def circuit(x): qml.RX(x, wires=0) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(circuit, dev) with pytest.raises(qml.QuantumFunctionError, match="Operator RX must act on all wires"): qn(0.5) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) qn = QNode(circuit, dev) assert np.allclose(qn(0.5), np.cos(0.5), atol=tol, rtol=0) @@ -842,7 +842,7 @@ def test_jit_counts_raises_error(self): jitting raises an error.""" import jax - dev = qml.device("default.qubit", wires=2, shots=5) + dev = qml.device("default.qubit.legacy", wires=2, shots=5) def circuit1(param): qml.Hadamard(0) @@ -876,7 +876,7 @@ def circuit2(param): def test_decorator(tol): """Test that the decorator correctly creates a QNode.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev) def func(x, y): @@ -922,7 +922,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface="autograd") for _ in range(2): @@ -946,7 +946,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -975,7 +975,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -998,7 +998,7 @@ def test_num_exec_caching_device_swap(self): """Tests that if we swapped the original device (e.g., when diff_method='backprop') then the number of executions recorded is correct.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) cache = {} @@ -1019,7 +1019,7 @@ def test_num_exec_caching_device_swap_two_exec(self): """Tests that if we swapped the original device (e.g., when diff_method='backprop') then the number of executions recorded is correct even with multiple QNode evaluations.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) cache = {} @@ -1054,7 +1054,7 @@ def test_single_expectation_value_with_argnum_one(self, diff_method, tol): This test relies on the fact that exactly one term of the estimated jacobian will match the expected analytical value. """ - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) x = pnp.array(0.543, requires_grad=True) y = pnp.array(-0.654, requires_grad=True) @@ -1078,7 +1078,7 @@ def circuit(x, y): def test_no_defer_measurements_if_supported(self, mocker): """Test that the defer_measurements transform is not used during QNode construction if the device supports mid-circuit measurements.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) mocker.patch.object(qml.Device, "_capabilities", {"supports_mid_measure": True}) spy = mocker.spy(qml, "defer_measurements") @@ -1103,7 +1103,7 @@ def test_defer_meas_if_mcm_unsupported(self, first_par, sec_par, return_type, mo """Tests that the transform using the deferred measurement principle is applied if the device doesn't support mid-circuit measurements natively.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def cry_qnode(x, y): @@ -1132,7 +1132,7 @@ def conditional_ry_qnode(x, y): def test_drawing_has_deferred_measurements(self): """Test that `qml.draw` with qnodes uses defer_measurements to draw circuits with mid-circuit measurements.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x): @@ -1150,7 +1150,7 @@ def circuit(x): def test_sampling_with_mcm(self, basis_state, mocker): """Tests that a QNode with qml.sample and mid-circuit measurements returns the expected results.""" - dev = qml.device("default.qubit", wires=3, shots=1000) + dev = qml.device("default.qubit.legacy", wires=3, shots=1000) first_par = np.pi @@ -1182,7 +1182,7 @@ def test_conditional_ops_tensorflow(self, interface): """Test conditional operations with TensorFlow.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1225,7 +1225,7 @@ def test_conditional_ops_torch(self, interface): """Test conditional operations with Torch.""" import torch - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1264,7 +1264,7 @@ def test_conditional_ops_jax(self, jax_interface): import jax jnp = jax.numpy - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev, interface=jax_interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1295,7 +1295,7 @@ def conditional_ry_qnode(x): def test_qnode_does_not_support_nested_queuing(self): """Test that operators in QNodes are not queued to surrounding contexts.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(): @@ -1315,7 +1315,7 @@ class TestShots: # pylint: disable=unexpected-keyword-arg def test_specify_shots_per_call_sample(self): """Tests that shots can be set per call for a sample return type.""" - dev = qml.device("default.qubit", wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) @qnode(dev) def circuit(a): @@ -1331,7 +1331,7 @@ def circuit(a): def test_specify_shots_per_call_expval(self): """Tests that shots can be set per call for an expectation value. Note: this test has a vanishingly small probability to fail.""" - dev = qml.device("default.qubit", wires=1, shots=None) + dev = qml.device("default.qubit.legacy", wires=1, shots=None) @qnode(dev) def circuit(): @@ -1357,7 +1357,7 @@ def test_no_shots_per_call_if_user_has_shots_qfunc_kwarg(self): """Tests that the per-call shots overwriting is suspended if user has a shots keyword argument, but a warning is raised.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) def circuit(a, shots=0): qml.RX(a, wires=shots) @@ -1381,7 +1381,7 @@ def circuit(a, shots=0): def test_no_shots_per_call_if_user_has_shots_qfunc_arg(self): """Tests that the per-call shots overwriting is suspended if user has a shots argument, but a warning is raised.""" - dev = qml.device("default.qubit", wires=[0, 1], shots=10) + dev = qml.device("default.qubit.legacy", wires=[0, 1], shots=10) def ansatz0(a, shots): qml.RX(a, wires=shots) @@ -1396,7 +1396,7 @@ def ansatz0(a, shots): assert len(circuit(0.8, 1)) == 10 assert circuit.qtape.operations[0].wires.labels == (1,) - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) with pytest.warns( UserWarning, match="The 'shots' argument name is reserved for overriding" @@ -1414,7 +1414,7 @@ def ansatz1(a, shots): def test_shots_setting_does_not_mutate_device(self): """Tests that per-call shots setting does not change the number of shots in the device.""" - dev = qml.device("default.qubit", wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qnode(dev) def circuit(a): @@ -1428,7 +1428,7 @@ def circuit(a): def test_warning_finite_shots_dev(self): """Tests that a warning is raised when caching is used with finite shots.""" - dev = qml.device("default.qubit", wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache={}) def circuit(x): @@ -1443,7 +1443,7 @@ def circuit(x): # pylint: disable=unexpected-keyword-arg def test_warning_finite_shots_override(self): """Tests that a warning is raised when caching is used with finite shots.""" - dev = qml.device("default.qubit", wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache={}) def circuit(x): @@ -1457,7 +1457,7 @@ def circuit(x): def test_warning_finite_shots_tape(self): """Tests that a warning is raised when caching is used with finite shots.""" - dev = qml.device("default.qubit", wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) with qml.queuing.AnnotatedQueue() as q: qml.RZ(0.3, wires=0) @@ -1472,7 +1472,7 @@ def test_warning_finite_shots_tape(self): def test_no_warning_infinite_shots(self): """Tests that no warning is raised when caching is used with infinite shots.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev, cache={}) def circuit(x): @@ -1487,7 +1487,7 @@ def circuit(x): @pytest.mark.autograd def test_no_warning_internal_cache_reuse(self): """Tests that no warning is raised when only the internal cache is reused.""" - dev = qml.device("default.qubit", wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache=True) def circuit(x): @@ -1510,7 +1510,7 @@ def circuit(x): ) def test_tape_shots_set_on_call(self, shots, total_shots, shot_vector): """test that shots are placed on the tape if they are specified during a call.""" - dev = qml.device("default.qubit", wires=2, shots=5) + dev = qml.device("default.qubit.legacy", wires=2, shots=5) def func(x, y): qml.RX(x, wires=0) @@ -1548,7 +1548,7 @@ def qn2(x, y): class TestTransformProgramIntegration: def test_transform_program_modifies_circuit(self): """Test qnode integration with a transform that turns the circuit into just a pauli x.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def null_postprocessing(results): return results[0] @@ -1581,7 +1581,7 @@ def circuit(x): def tet_transform_program_modifies_results(self): """Test integration with a transform that modifies the result output.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.transforms.core.transform def pin_result( @@ -1606,7 +1606,7 @@ def circuit(x): def test_transform_order_circuit_processing(self): """Test that transforms are applied in the correct order in integration.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def null_postprocessing(results): return results[0] @@ -1653,7 +1653,7 @@ def circuit2(x): def test_transform_order_postprocessing(self): """Test that transform postprocessing is called in the right order.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def scale_by_factor(results, factor): return results[0] * factor @@ -1869,7 +1869,7 @@ class TestTapeExpansion: ) def test_device_expansion(self, diff_method, mode, mocker): """Test expansion of an unsupported operation on the device""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1902,7 +1902,7 @@ def circuit(x): def test_no_gradient_expansion(self, mocker): """Test that an unsupported operation with defined gradient recipe is not expanded""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1947,7 +1947,7 @@ def circuit(x): def test_gradient_expansion(self, mocker): """Test that a *supported* operation with no gradient recipe is expanded when applying the gradient transform, but not for execution.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class PhaseShift(qml.PhaseShift): @@ -1992,7 +1992,7 @@ def circuit(x): def test_hamiltonian_expansion_analytic(self): """Test result if there are non-commuting groups and the number of shots is None""" - dev = qml.device("default.qubit", wires=3, shots=None) + dev = qml.device("default.qubit.legacy", wires=3, shots=None) obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliZ(1)] c = np.array([-0.6543, 0.24, 0.54]) @@ -2011,7 +2011,7 @@ def circuit(): def test_hamiltonian_expansion_finite_shots(self, mocker): """Test that the Hamiltonian is expanded if there are non-commuting groups and the number of shots is finite""" - dev = qml.device("default.qubit", wires=3, shots=50000) + dev = qml.device("default.qubit.legacy", wires=3, shots=50000) obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliZ(1)] c = np.array([-0.6543, 0.24, 0.54]) @@ -2036,7 +2036,7 @@ def circuit(): def test_invalid_hamiltonian_expansion_finite_shots(self): """Test that an error is raised if multiple expectations are requested when using finite shots""" - dev = qml.device("default.qubit", wires=3, shots=50000) + dev = qml.device("default.qubit.legacy", wires=3, shots=50000) obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliZ(1)] c = np.array([-0.6543, 0.24, 0.54]) @@ -2057,7 +2057,7 @@ def circuit(): def test_device_expansion_strategy(self, mocker): """Test that the device expansion strategy performs the device decomposition at construction time, and not at execution time""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = pnp.array(0.5, requires_grad=True) @qnode(dev, diff_method="parameter-shift", expansion_strategy="device") @@ -2083,7 +2083,7 @@ def circuit(x): def test_expansion_multiple_qwc_observables(self, mocker): """Test that the QNode correctly expands tapes that return multiple measurements of commuting observables""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliY(1)] @qml.qnode(dev) diff --git a/tests/test_return_types.py b/tests/test_return_types.py index 733ff8e6119..6fcbe5298fd 100644 --- a/tests/test_return_types.py +++ b/tests/test_return_types.py @@ -22,7 +22,7 @@ test_wires = [2, 3, 4] -devices = ["default.qubit", "default.mixed"] +devices = ["default.qubit.legacy", "default.mixed"] @pytest.mark.parametrize("interface, shots", [["autograd", None], ["auto", 100]]) @@ -32,7 +32,7 @@ class TestSingleReturnExecute: @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires, interface, shots): """Return state with default.qubit.""" - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -223,7 +223,7 @@ def test_sample(self, measurement, interface, shots): if shots is None: pytest.skip("Sample requires finite shots.") - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -244,7 +244,7 @@ def test_counts(self, measurement, interface, shots): if shots is None: pytest.skip("Counts requires finite shots.") - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1221,7 +1221,7 @@ def return_type(self): DummyMeasurement(obs=qml.PauliZ(0)) tape = qml.tape.QuantumScript.from_queue(q) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) with pytest.raises( qml.QuantumFunctionError, match="Unsupported return type specified for observable" ): @@ -1231,7 +1231,7 @@ def test_state_return_with_other_types(self): """Test that an exception is raised when a state is returned along with another return type""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires=0) @@ -1248,7 +1248,7 @@ def test_state_return_with_other_types(self): def test_entropy_no_custom_wires(self): """Test that entropy cannot be returned with custom wires.""" - dev = qml.device("default.qubit", wires=["a", 1]) + dev = qml.device("default.qubit.legacy", wires=["a", 1]) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires="a") @@ -1264,7 +1264,7 @@ def test_entropy_no_custom_wires(self): def test_custom_wire_labels_error(self): """Tests that an error is raised when mutual information is measured with custom wire labels""" - dev = qml.device("default.qubit", wires=["a", "b"]) + dev = qml.device("default.qubit.legacy", wires=["a", "b"]) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires="a") diff --git a/tests/test_return_types_dq2.py b/tests/test_return_types_dq2.py new file mode 100644 index 00000000000..3acae93dc59 --- /dev/null +++ b/tests/test_return_types_dq2.py @@ -0,0 +1,1265 @@ +# Copyright 2022 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Unit tests for the new return types. +""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import MeasurementProcess + +test_wires = [2, 3, 4] + +devices = ["default.qubit"] + + +@pytest.mark.parametrize("interface, shots", [["autograd", None], ["auto", 100]]) +class TestSingleReturnExecute: + """Test that single measurements return behavior does not change.""" + + @pytest.mark.parametrize("wires", test_wires) + def test_state_default(self, wires, interface, shots): + """Return state with default.qubit.""" + dev = qml.device("default.qubit", wires=wires, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.state() + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == (2**wires,) + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("d_wires", test_wires) + def test_density_matrix(self, d_wires, device, interface, shots): + """Return density matrix.""" + dev = qml.device(device, wires=4, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.density_matrix(wires=range(0, d_wires)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == (2**d_wires, 2**d_wires) + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("device", devices) + def test_expval(self, device, interface, shots): + """Return a single expval.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.expval(qml.PauliZ(wires=1)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == () + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("device", devices) + def test_var(self, device, interface, shots): + """Return a single var.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.var(qml.PauliZ(wires=1)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == () + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("device", devices) + def test_vn_entropy(self, device, interface, shots): + """Return a single vn entropy.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.vn_entropy(wires=0) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == () + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("device", devices) + def test_mutual_info(self, device, interface, shots): + """Return a single mutual information.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert res[0].shape == () + assert isinstance(res[0], (np.ndarray, np.float64)) + + herm = np.diag([1, 2, 3, 4]) + probs_data = [ + (None, [0]), + (None, [0, 1]), + (qml.PauliZ(0), None), + (qml.Hermitian(herm, wires=[1, 0]), None), + ] + + # pylint: disable=too-many-arguments + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("op,wires", probs_data) + def test_probs(self, op, wires, device, interface, shots): + """Return a single prob.""" + dev = qml.device(device, wires=3, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.probs(op=op, wires=wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + if wires is None: + wires = op.wires + + assert res[0].shape == (2 ** len(wires),) + assert isinstance(res[0], (np.ndarray, np.float64)) + + @pytest.mark.parametrize("measurement", [qml.sample(qml.PauliZ(0)), qml.sample(wires=[0])]) + def test_sample(self, measurement, interface, shots): + """Test the sample measurement.""" + if shots is None: + pytest.skip("Sample requires finite shots.") + + dev = qml.device("default.qubit", wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert isinstance(res[0], (np.ndarray, np.float64)) + assert res[0].shape == (shots,) + + @pytest.mark.parametrize("measurement", [qml.counts(qml.PauliZ(0)), qml.counts(wires=[0])]) + def test_counts(self, measurement, interface, shots): + """Test the counts measurement.""" + if shots is None: + pytest.skip("Counts requires finite shots.") + + dev = qml.device("default.qubit", wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None, interface=interface) + + assert isinstance(res[0], dict) + assert sum(res[0].values()) == shots + + +multi_return_wires = [([0], [1]), ([1], [0]), ([0], [0]), ([1], [1])] + + +@pytest.mark.parametrize("shots", [None, 100]) +class TestMultipleReturns: + """Test the new return types for multiple measurements, it should always return a tuple containing the single + measurements. + """ + + @pytest.mark.parametrize("device", devices) + def test_multiple_expval(self, device, shots): + """Return multiple expvals.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.expval(qml.PauliZ(wires=0)), qml.expval(qml.PauliZ(wires=1)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + assert isinstance(res[0], tuple) + assert len(res[0]) == 2 + + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == () + + assert isinstance(res[0][1], (np.ndarray, np.float64)) + assert res[0][1].shape == () + + @pytest.mark.parametrize("device", devices) + def test_multiple_var(self, device, shots): + """Return multiple vars.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.var(qml.PauliZ(wires=0)), qml.var(qml.PauliZ(wires=1)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + assert isinstance(res[0], tuple) + assert len(res[0]) == 2 + + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == () + + assert isinstance(res[0][1], (np.ndarray, np.float64)) + assert res[0][1].shape == () + + # op1, wires1, op2, wires2 + multi_probs_data = [ + (None, [0], None, [0]), + (None, [0], None, [0, 1]), + (None, [0, 1], None, [0]), + (None, [0, 1], None, [0, 1]), + (qml.PauliZ(0), None, qml.PauliZ(1), None), + (None, [0], qml.PauliZ(1), None), + (qml.PauliZ(0), None, None, [0]), + (qml.PauliZ(1), None, qml.PauliZ(0), None), + ] + + # pylint: disable=too-many-arguments + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data) + def test_multiple_prob(self, op1, op2, wires1, wires2, device, shots): + """Return multiple probs.""" + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.probs(op=op1, wires=wires1), qml.probs(op=op2, wires=wires2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + assert isinstance(res[0], tuple) + assert len(res[0]) == 2 + + if wires1 is None: + wires1 = op1.wires + + if wires2 is None: + wires2 = op2.wires + + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == (2 ** len(wires1),) + + assert isinstance(res[0][1], (np.ndarray, np.float64)) + assert res[0][1].shape == (2 ** len(wires2),) + + # pylint: disable=too-many-arguments + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data) + @pytest.mark.parametrize("wires3, wires4", multi_return_wires) + def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device, shots): + """Return multiple different measurements.""" + + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return ( + qml.probs(op=op1, wires=wires1), + qml.vn_entropy(wires=wires3), + qml.probs(op=op2, wires=wires2), + qml.expval(qml.PauliZ(wires=wires4)), + ) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + if wires1 is None: + wires1 = op1.wires + + if wires2 is None: + wires2 = op2.wires + + assert isinstance(res[0], tuple) + assert len(res[0]) == 4 + + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == (2 ** len(wires1),) + + assert isinstance(res[0][1], (np.ndarray, np.float64)) + assert res[0][1].shape == () + + assert isinstance(res[0][2], (np.ndarray, np.float64)) + assert res[0][2].shape == (2 ** len(wires2),) + + assert isinstance(res[0][3], (np.ndarray, np.float64)) + assert res[0][3].shape == () + + wires = [2, 3, 4, 5] + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("wires", wires) + def test_list_multiple_expval(self, wires, device, shots): + """Return a comprehension list of multiple expvals.""" + dev = qml.device(device, wires=wires, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return [qml.expval(qml.PauliZ(wires=i)) for i in range(0, wires)] + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + assert isinstance(res[0], tuple) + assert len(res[0]) == wires + + for i in range(0, wires): + assert isinstance(res[0][i], (np.ndarray, np.float64)) + assert res[0][i].shape == () + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("measurement", [qml.sample(qml.PauliZ(0)), qml.sample(wires=[0])]) + def test_expval_sample(self, measurement, shots, device): + """Test the expval and sample measurements together.""" + if shots is None: + pytest.skip("Sample requires finite shots.") + + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.expval(qml.PauliX(1)), qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + # Expval + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == () + + # Sample + assert isinstance(res[0][1], (np.ndarray, np.float64)) + assert res[0][1].shape == (shots,) + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("measurement", [qml.counts(qml.PauliZ(0)), qml.counts(wires=[0])]) + def test_expval_counts(self, measurement, shots, device): + """Test the expval and counts measurements together.""" + if shots is None: + pytest.skip("Counts requires finite shots.") + + dev = qml.device(device, wires=2, shots=shots) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.expval(qml.PauliX(1)), qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + # Expval + assert isinstance(res[0][0], (np.ndarray, np.float64)) + assert res[0][0].shape == () + + # Counts + assert isinstance(res[0][1], dict) + assert sum(res[0][1].values()) == shots + + +pauliz = qml.PauliZ(wires=1) +proj = qml.Projector([1], wires=1) +hermitian = qml.Hermitian(np.diag([1, 2]), wires=0) + +# Note: mutual info and vn_entropy do not support some shot vectors +# qml.mutual_info(wires0=[0], wires1=[1]), qml.vn_entropy(wires=[0])] +single_scalar_output_measurements = [ + qml.expval(pauliz), + qml.var(pauliz), + qml.expval(proj), + qml.var(proj), + qml.expval(hermitian), + qml.var(hermitian), +] + +herm = np.diag([1, 2, 3, 4]) +probs_data = [ + (None, [0]), + (None, [0, 1]), + (qml.PauliZ(0), None), + (qml.Hermitian(herm, wires=[1, 0]), None), +] + +shot_vectors = [[10, 1000], [1, 10, 10, 1000], [1, (10, 2), 1000]] + + +@pytest.mark.parametrize("shot_vector", shot_vectors) +@pytest.mark.parametrize("device", devices) +class TestShotVector: + """Test the support for executing tapes with single measurements using a + device with shot vectors.""" + + @pytest.mark.parametrize("measurement", single_scalar_output_measurements) + def test_scalar(self, shot_vector, measurement, device): + """Test a single scalar-valued measurement.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(r.shape == () for r in res[0]) + + @pytest.mark.parametrize("op,wires", probs_data) + def test_probs(self, shot_vector, op, wires, device): + """Test a single probability measurement.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.probs(op=op, wires=wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + wires_to_use = wires if wires else op.wires + assert all(r.shape == (2 ** len(wires_to_use),) for r in res[0]) + + @pytest.mark.parametrize("wires", [[0], [2, 0], [1, 0], [2, 0, 1]]) + def test_density_matrix(self, shot_vector, wires, device): + """Test a density matrix measurement.""" + dev = qml.device(device, wires=3, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.density_matrix(wires=wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + if dev.shots: + pytest.skip("cannot return analytic measurements with finite shots.") + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + dim = 2 ** len(wires) + assert all(r.shape == (dim, dim) for r in res[0]) + + @pytest.mark.parametrize("measurement", [qml.sample(qml.PauliZ(0)), qml.sample(wires=[0])]) + def test_samples(self, shot_vector, measurement, device): + """Test the sample measurement.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shot_copies = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + assert len(res[0]) == len(all_shot_copies) + for r, shots in zip(res[0], all_shot_copies): + if shots == 1: + # Scalar tensors + assert r.shape == () + else: + assert r.shape == (shots,) + + @pytest.mark.parametrize("measurement", [qml.counts(qml.PauliZ(0)), qml.counts(wires=[0])]) + def test_counts(self, shot_vector, measurement, device): + """Test the counts measurement.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, dict) for r in res[0]) + + +@pytest.mark.parametrize("shot_vector", shot_vectors) +@pytest.mark.parametrize("device", devices) +class TestSameMeasurementShotVector: + """Test the support for executing tapes with the same type of measurement + multiple times using a device with shot vectors""" + + def test_scalar(self, shot_vector, device): + """Test multiple scalar-valued measurements.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.expval(qml.PauliX(0)), qml.var(qml.PauliZ(1)) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + for r in res[0]: + assert len(r) == 2 + assert all(r.shape == () for r in r) + + probs_data2 = [ + (None, [2]), + (None, [2, 3]), + (qml.PauliZ(2), None), + (qml.Hermitian(herm, wires=[3, 2]), None), + ] + + # pylint: disable=too-many-arguments + @pytest.mark.parametrize("op1,wires1", probs_data) + @pytest.mark.parametrize("op2,wires2", reversed(probs_data2)) + def test_probs(self, shot_vector, op1, wires1, op2, wires2, device): + """Test multiple probability measurements.""" + dev = qml.device(device, wires=4, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.probs(op=op1, wires=wires1), qml.probs(op=op2, wires=wires2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + + wires1 = wires1 if wires1 else op1.wires + wires2 = wires2 if wires2 else op2.wires + for r in res[0]: + assert len(r) == 2 + assert r[0].shape == (2 ** len(wires1),) + assert r[1].shape == (2 ** len(wires2),) + + @pytest.mark.parametrize("measurement1", [qml.sample(qml.PauliZ(0)), qml.sample(wires=[0])]) + @pytest.mark.parametrize("measurement2", [qml.sample(qml.PauliX(1)), qml.sample(wires=[1])]) + def test_samples(self, shot_vector, measurement1, measurement2, device): + """Test multiple sample measurements.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement1), qml.apply(measurement2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shot_copies = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + assert len(res[0]) == len(all_shot_copies) + for r, shots in zip(res[0], all_shot_copies): + shape = () if shots == 1 else (shots,) + assert all(res_item.shape == shape for res_item in r) + + @pytest.mark.parametrize("measurement1", [qml.counts(qml.PauliZ(0)), qml.counts(wires=[0])]) + @pytest.mark.parametrize("measurement2", [qml.counts(qml.PauliZ(0)), qml.counts(wires=[0])]) + def test_counts(self, shot_vector, measurement1, measurement2, device): + """Test multiple counts measurements.""" + dev = qml.device(device, wires=2, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(measurement1), qml.apply(measurement2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + for r in res[0]: + assert isinstance(r, tuple) + assert all(isinstance(res_item, dict) for res_item in r) + + +# ------------------------------------------------- +# Shot vector multi measurement tests - test data +# ------------------------------------------------- + +pauliz_w2 = qml.PauliZ(wires=2) +proj_w2 = qml.Projector([1], wires=2) +hermitian = qml.Hermitian(np.diag([1, 2]), wires=0) +tensor_product = qml.PauliZ(wires=2) @ qml.PauliX(wires=1) + +# Expval/Var with Probs + +scalar_probs_multi = [ + # Expval + (qml.expval(pauliz_w2), qml.probs(wires=[2, 0])), + (qml.expval(proj_w2), qml.probs(wires=[1, 0])), + (qml.expval(tensor_product), qml.probs(wires=[2, 0])), + # Var + (qml.var(qml.PauliZ(wires=1)), qml.probs(wires=[0, 1])), + (qml.var(proj_w2), qml.probs(wires=[1, 0])), + (qml.var(tensor_product), qml.probs(wires=[2, 0])), +] + +# Expval/Var with Sample + +scalar_sample_multi = [ + # Expval + (qml.expval(pauliz_w2), qml.sample(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.expval(proj_w2), qml.sample(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.expval(tensor_product), qml.sample(op=qml.PauliZ(0))), + # Var + (qml.var(proj_w2), qml.sample(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.var(pauliz_w2), qml.sample(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.var(tensor_product), qml.sample(op=qml.PauliZ(0))), +] + +scalar_sample_no_obs_multi = [ + (qml.expval(qml.PauliZ(wires=1)), qml.sample()), + (qml.expval(qml.PauliZ(wires=1)), qml.sample(wires=[0, 1])), + (qml.var(qml.PauliZ(wires=1)), qml.sample(wires=[0, 1])), +] + +# Expval/Var with Counts + +scalar_counts_multi = [ + # Expval + (qml.expval(pauliz_w2), qml.counts(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.expval(proj_w2), qml.counts(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.expval(tensor_product), qml.counts(op=qml.PauliZ(0))), + # Var + (qml.var(proj_w2), qml.counts(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.var(pauliz_w2), qml.counts(op=qml.PauliZ(1) @ qml.PauliZ(0))), + (qml.var(tensor_product), qml.counts(op=qml.PauliZ(0))), +] + +scalar_counts_no_obs_multi = [ + (qml.expval(qml.PauliZ(wires=1)), qml.counts()), + (qml.expval(qml.PauliZ(wires=1)), qml.counts(wires=[0, 1])), + (qml.var(qml.PauliZ(wires=1)), qml.counts(wires=[0, 1])), +] + + +@pytest.mark.parametrize("shot_vector", shot_vectors) +@pytest.mark.parametrize("device", devices) +class TestMixMeasurementsShotVector: + """Test the support for executing tapes with multiple different + measurements using a device with shot vectors""" + + @pytest.mark.parametrize("meas1,meas2", scalar_probs_multi) + def test_scalar_probs(self, shot_vector, meas1, meas2, device): + """Test scalar-valued and probability measurements""" + dev = qml.device(device, wires=3, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(meas1), qml.apply(meas2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res[0] + for m in measurement_res + ) + for meas_res in res[0]: + for i, r in enumerate(meas_res): + if i % 2 == 0: + # Scalar-val meas + assert r.shape == () + else: + assert r.shape == (2**2,) + + # Probs add up to 1 + assert np.allclose(sum(r), 1) + + @pytest.mark.parametrize("meas1,meas2", scalar_sample_multi) + def test_scalar_sample_with_obs(self, shot_vector, meas1, meas2, device): + """Test scalar-valued and sample measurements where sample takes an + observable.""" + dev = qml.device(device, wires=3, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(meas1), qml.apply(meas2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res[0] + for m in measurement_res + ) + + for idx, shots in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0 or shots == 1: + assert meas2.obs is not None + expected_shape = () + assert r.shape == expected_shape + else: + assert r.shape == (shots,) + + @pytest.mark.parametrize("meas1,meas2", scalar_sample_no_obs_multi) + @pytest.mark.xfail + def test_scalar_sample_no_obs(self, shot_vector, meas1, meas2, device): + """Test scalar-valued and computational basis sample measurements.""" + dev = qml.device(device, wires=3, shots=shot_vector) + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(meas1), qml.apply(meas2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res[0] + for m in measurement_res + ) + + for shot_tuple in dev.shots.shot_vector: + for idx in range(shot_tuple.copies): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0 or shot_tuple.shots == 1: + assert meas2.obs is not None + expected_shape = () + assert r.shape == expected_shape + else: + assert r.shape == (shot_tuple.shots,) + + @pytest.mark.parametrize("meas1,meas2", scalar_counts_multi) + def test_scalar_counts_with_obs(self, shot_vector, meas1, meas2, device): + """Test scalar-valued and counts measurements where counts takes an + observable.""" + dev = qml.device(device, wires=3, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(meas1), qml.apply(meas2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + + for r in res[0]: + assert isinstance(r[0], (np.ndarray, np.float64)) + assert isinstance(r[1], dict) + + expected_outcomes = {-1, 1} + + for idx, shots in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0: + assert meas2.obs is not None + expected_shape = () + assert r.shape == expected_shape + else: + # Samples are either -1 or 1 + assert set(r.keys()).issubset(expected_outcomes) + assert sum(r.values()) == shots + + @pytest.mark.parametrize("meas1,meas2", scalar_counts_no_obs_multi) + def test_scalar_counts_no_obs(self, shot_vector, meas1, meas2, device): + """Test scalar-valued and computational basis counts measurements.""" + dev = qml.device(device, wires=3, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.apply(meas1), qml.apply(meas2) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + + for idx, _ in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0: + assert isinstance(r, (np.ndarray, np.float64)) + assert meas2.obs is None + expected_shape = () + assert r.shape == expected_shape + else: + assert isinstance(r, dict) + + @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) + def test_probs_sample(self, shot_vector, sample_obs, device): + """Test probs and sample measurements.""" + dev = qml.device(device, wires=3, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + meas1_wires = [0, 1] + meas2_wires = [2] + + @qml.qnode(device=dev) + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + if sample_obs is not None: + # Observable provided to sample + return qml.probs(wires=meas1_wires), qml.sample(sample_obs(meas2_wires)) + + # Only wires provided to sample + return qml.probs(wires=meas1_wires), qml.sample(wires=meas2_wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res[0] + for m in measurement_res + ) + + for idx, shots in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0: + expected_shape = (len(meas1_wires) ** 2,) + assert r.shape == expected_shape + + # Probs add up to 1 + assert np.allclose(sum(r), 1) + else: + if shots == 1: + assert r.shape == () + else: + expected = (shots,) + assert r.shape == expected + + @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) + def test_probs_counts(self, shot_vector, sample_obs, device): + """Test probs and counts measurements.""" + dev = qml.device(device, wires=3, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + meas1_wires = [0, 1] + meas2_wires = [2] + + @qml.qnode(device=dev) + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + if sample_obs is not None: + # Observable provided to sample + return qml.probs(wires=meas1_wires), qml.counts(sample_obs(meas2_wires)) + + # Only wires provided to sample + return qml.probs(wires=meas1_wires), qml.counts(wires=meas2_wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(measurement_res[0], (np.ndarray, np.float64)) for measurement_res in res[0] + ) + assert all(isinstance(measurement_res[1], dict) for measurement_res in res[0]) + + expected_outcomes = {-1, 1} if sample_obs is not None else {"0", "1"} + for idx, shots in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + if i % 2 == 0: + expected_shape = (len(meas1_wires) ** 2,) + assert r.shape == expected_shape + + # Probs add up to 1 + assert np.allclose(sum(r), 1) + else: + # Samples are -1 or 1 + assert set(r.keys()).issubset(expected_outcomes) + assert sum(r.values()) == shots + + @pytest.mark.parametrize("sample_wires", [[1], [0, 2]]) + @pytest.mark.parametrize("counts_wires", [[4], [3, 5]]) + def test_sample_counts(self, shot_vector, sample_wires, counts_wires, device): + """Test sample and counts measurements, each measurement with custom + samples or computational basis state samples.""" + dev = qml.device(device, wires=6, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + @qml.qnode(device=dev) + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + + # 1. Sample obs and Counts obs + if len(sample_wires) == 1 and len(counts_wires) == 1: + return qml.sample(qml.PauliY(sample_wires)), qml.counts(qml.PauliX(counts_wires)) + + # 2. Sample no obs and Counts obs + if len(sample_wires) > 1 and len(counts_wires) == 1: + return qml.sample(wires=sample_wires), qml.counts(qml.PauliX(counts_wires)) + + # 3. Sample obs and Counts no obs + if len(sample_wires) == 1 and len(counts_wires) > 1: + return qml.sample(qml.PauliY(sample_wires)), qml.counts(wires=counts_wires) + + # 4. Sample no obs and Counts no obs + return qml.sample(wires=sample_wires), qml.counts(wires=counts_wires) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + assert all( + isinstance(measurement_res[0], (np.ndarray, np.float64)) for measurement_res in res[0] + ) + assert all(isinstance(measurement_res[1], dict) for measurement_res in res[0]) + + for idx, shots in enumerate(raw_shot_vector): + for i, r in enumerate(res[0][idx]): + num_wires = len(sample_wires) + if shots == 1 and i % 2 == 0: + expected_shape = () if num_wires == 1 else (num_wires,) + assert r.shape == expected_shape + elif i % 2 == 0: + expected_shape = (shots,) if num_wires == 1 else (shots, num_wires) + assert r.shape == expected_shape + else: + assert isinstance(r, dict) + + @pytest.mark.parametrize("meas1,meas2", scalar_probs_multi) + def test_scalar_probs_sample_counts(self, shot_vector, meas1, meas2, device): + """Test scalar-valued, probability, sample and counts measurements all + in a single qfunc.""" + dev = qml.device(device, wires=5, shots=shot_vector) + raw_shot_vector = [ + shot_tuple.shots + for shot_tuple in dev.shots.shot_vector + for _ in range(shot_tuple.copies) + ] + + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return ( + qml.apply(meas1), + qml.apply(meas2), + qml.sample(qml.PauliX(4)), + qml.counts(qml.PauliX(3)), + ) + + qnode = qml.QNode(circuit, dev) + qnode.construct([0.5], {}) + + res = qml.execute(tapes=[qnode.tape], device=dev, gradient_fn=None) + + all_shots = sum(shot_tuple.copies for shot_tuple in dev.shots.shot_vector) + + assert isinstance(res[0], tuple) + assert len(res[0]) == all_shots + assert all(isinstance(r, tuple) for r in res[0]) + + for res_idx, meas_res in enumerate(res[0]): + for i, r in enumerate(meas_res): + num_meas = i % 4 + expval_or_var = num_meas == 0 + probs = num_meas == 1 + sample = num_meas == 2 + + if expval_or_var: + assert r.shape == () + elif probs: + assert r.shape == (2**2,) + + # Probs add up to 1 + assert np.allclose(sum(r), 1) + elif sample: + shots = raw_shot_vector[res_idx] + if shots == 1: + assert r.shape == () + else: + expected = (shots,) + assert r.shape == expected + else: + # Return is Counts + assert isinstance(r, dict) + + +class TestDeviceNewUnits: + """Further unit tests for some new methods of Device.""" + + def test_unsupported_observable_return_type_raise_error(self): + """Check that an error is raised if the return type of an observable is unsupported""" + # pylint: disable=too-few-public-methods + + class UnsupportedReturnType: + value = "unsupported" + + class DummyMeasurement(MeasurementProcess): + @property + def return_type(self): + return UnsupportedReturnType + + with qml.queuing.AnnotatedQueue() as q: + qml.PauliX(wires=0) + DummyMeasurement(obs=qml.PauliZ(0)) + + tape = qml.tape.QuantumScript.from_queue(q) + dev = qml.device("default.qubit", wires=3) + with pytest.raises(qml.DeviceError, match="Analytic circuits must only contain"): + qml.execute(tapes=[tape], device=dev, gradient_fn=None) + + def test_state_return_with_other_types(self): + """Test that an exception is raised when a state is returned along with another return + type""" + + dev = qml.device("default.qubit", wires=2) + + with qml.queuing.AnnotatedQueue() as q: + qml.PauliX(wires=0) + qml.state() + qml.expval(qml.PauliZ(1)) + + tape = qml.tape.QuantumScript.from_queue(q) + res = qml.execute(tapes=[tape], device=dev, gradient_fn=None)[0] + assert isinstance(res, tuple) and len(res) == 2 + assert np.array_equal(res[0], [0.0, 0.0, 1.0, 0.0]) + assert res[1] == 1.0 + + def test_entropy_no_custom_wires(self): + """Test that entropy cannot be returned with custom wires.""" + + dev = qml.device("default.qubit", wires=["a", 1]) + + with qml.queuing.AnnotatedQueue() as q: + qml.PauliX(wires="a") + qml.vn_entropy(wires=["a"]) + + tape = qml.tape.QuantumScript.from_queue(q) + res = qml.execute(tapes=[tape], device=dev, gradient_fn=None) + assert res == (0,) + + def test_custom_wire_labels_error(self): + """Tests that an error is raised when mutual information is measured + with custom wire labels""" + dev = qml.device("default.qubit", wires=["a", "b"]) + + with qml.queuing.AnnotatedQueue() as q: + qml.PauliX(wires="a") + qml.mutual_info(wires0=["a"], wires1=["b"]) + + tape = qml.tape.QuantumScript.from_queue(q) + res = qml.execute(tapes=[tape], device=dev, gradient_fn=None) + assert res == (0,) diff --git a/tests/test_return_types_qnode.py b/tests/test_return_types_qnode.py index d4e2c11b86d..3a3cdb93997 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -50,7 +50,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == (2**wires,) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("wires", test_wires) def test_state_mixed(self, wires): @@ -65,7 +65,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == (2**wires, 2**wires) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize("d_wires", test_wires) @@ -83,7 +83,7 @@ def circuit(x): dim = 3 if device == "default.qutrit" else 2 assert res.shape == (dim**d_wires, dim**d_wires) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("device", devices) def test_expval(self, device): @@ -101,7 +101,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == () - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("device", devices) def test_var(self, device): @@ -119,7 +119,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == () - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("device", devices) def test_vn_entropy(self, device): @@ -137,7 +137,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == () - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.xfail(reason="qml.execute shot vec support required with new return types") @pytest.mark.filterwarnings("ignore:Requested Von Neumann entropy with finite shots") @@ -171,7 +171,7 @@ def circuit(x): res = qnode(0.5) assert res.shape == () - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.xfail(reason="qml.execute shot vec support required with new return types") @pytest.mark.filterwarnings("ignore:Requested mutual information with finite shots") @@ -218,7 +218,7 @@ def circuit(x): wires = op.wires assert res.shape == (2 ** len(wires),) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) probs_data_qutrit = [ (qml.GellMann(0, 3), None), @@ -243,7 +243,7 @@ def circuit(x): wires = op.wires assert res.shape == (3 ** len(wires),) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize( @@ -273,7 +273,7 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) if measurement.wires.tolist() != [0, 1]: assert res.shape == (shots,) @@ -1020,10 +1020,10 @@ def circuit(x): assert isinstance(res, tuple) assert len(res) == 2 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == () - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == () @pytest.mark.parametrize("device", devices) @@ -1049,10 +1049,10 @@ def circuit(x): assert isinstance(res, tuple) assert len(res) == 2 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == () - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == () # op1, wires1, op2, wires2 @@ -1093,10 +1093,10 @@ def circuit(x): if wires2 is None: wires2 = op2.wires - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == (2 ** len(wires1),) - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == (2 ** len(wires2),) multi_probs_data_qutrit = [ @@ -1131,10 +1131,10 @@ def circuit(x): if wires2 is None: wires2 = op2.wires - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == (3 ** len(wires1),) - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == (3 ** len(wires2),) # pylint: disable=too-many-arguments @@ -1169,16 +1169,16 @@ def circuit(x): assert isinstance(res, tuple) assert len(res) == 4 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == (2 ** len(wires1),) - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == () - assert isinstance(res[2], np.ndarray) + assert isinstance(res[2], (np.ndarray, np.float64)) assert res[2].shape == (2 ** len(wires2),) - assert isinstance(res[3], np.ndarray) + assert isinstance(res[3], (np.ndarray, np.float64)) assert res[3].shape == () # pylint: disable=too-many-arguments @@ -1211,16 +1211,16 @@ def circuit(x): assert isinstance(res, tuple) assert len(res) == 4 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == (3 ** len(wires1),) - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == () - assert isinstance(res[2], np.ndarray) + assert isinstance(res[2], (np.ndarray, np.float64)) assert res[2].shape == (3 ** len(wires2),) - assert isinstance(res[3], np.ndarray) + assert isinstance(res[3], (np.ndarray, np.float64)) assert res[3].shape == () @pytest.mark.parametrize("device", devices) @@ -1248,11 +1248,11 @@ def circuit(x): res = qnode(0.5) # Expval - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == () # Sample - assert isinstance(res[1], np.ndarray) + assert isinstance(res[1], (np.ndarray, np.float64)) assert res[1].shape == (shots,) @pytest.mark.parametrize("device", devices) @@ -1280,7 +1280,7 @@ def circuit(x): res = qnode(0.5) # Expval - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == () # Counts @@ -1306,7 +1306,7 @@ def circuit(x): assert isinstance(res, list) assert len(res) == 1 - assert isinstance(res[0], np.ndarray) + assert isinstance(res[0], (np.ndarray, np.float64)) assert res[0].shape == () shot_vectors = [None, [10, 1000], [1, 10, 10, 1000], [1, (10, 2), 1000]] @@ -1322,6 +1322,7 @@ def test_list_multiple_expval(self, wires, device, shot_vector): def circuit(x): func(x) + # pylint:disable=unexpected-keyword-arg return [ qml.expval(obs(wires=i) if device != "default.qutrit" else obs(wires=i, index=3)) for i in range(0, wires) @@ -1334,7 +1335,7 @@ def circuit(x): assert isinstance(res, list) assert len(res) == wires for r in res: - assert isinstance(r, np.ndarray) + assert isinstance(r, (np.ndarray, np.float64)) assert r.shape == () else: @@ -1343,7 +1344,7 @@ def circuit(x): assert len(r) == wires for t in r: - assert isinstance(t, np.ndarray) + assert isinstance(t, (np.ndarray, np.float64)) assert t.shape == () @pytest.mark.parametrize("device", devices) @@ -1373,9 +1374,9 @@ def circuit(x): else: assert isinstance(res[0], dict) - assert isinstance(res[1], qml.numpy.ndarray) + assert isinstance(res[1], (qml.numpy.ndarray, qml.numpy.float64)) assert res[1].shape == () - assert isinstance(res[2], qml.numpy.ndarray) + assert isinstance(res[2], (qml.numpy.ndarray, qml.numpy.float64)) assert res[2].shape == (2,) @@ -2236,7 +2237,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2257,7 +2265,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2281,7 +2296,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2303,7 +2325,11 @@ def circuit(x): res = qnode(0.5) all_shot_copies = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] assert len(res) == len(all_shot_copies) @@ -2328,7 +2354,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2353,7 +2386,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2383,7 +2423,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2410,7 +2457,11 @@ def circuit(x): res = qnode(0.5) all_shot_copies = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] assert len(res) == len(all_shot_copies) @@ -2432,7 +2483,14 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2522,12 +2580,23 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(m, np.ndarray) for measurement_res in res for m in measurement_res) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res + for m in measurement_res + ) for meas_res in res: for i, r in enumerate(meas_res): if i % 2 == 0: @@ -2545,7 +2614,11 @@ def test_scalar_sample_with_obs(self, shot_vector, meas1, meas2, device): observable.""" dev = qml.device(device, wires=3, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] def circuit(x): @@ -2556,12 +2629,23 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(m, np.ndarray) for measurement_res in res for m in measurement_res) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res + for m in measurement_res + ) for idx, shots in enumerate(raw_shot_vector): for i, r in enumerate(res[idx]): @@ -2586,14 +2670,25 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(m, np.ndarray) for measurement_res in res for m in measurement_res) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res + for m in measurement_res + ) - for shot_tuple in dev.shot_vector: + for shot_tuple in dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector: for idx in range(shot_tuple.copies): for i, r in enumerate(res[idx]): if i % 2 == 0 or shot_tuple.shots == 1: @@ -2609,7 +2704,11 @@ def test_scalar_counts_with_obs(self, shot_vector, meas1, meas2, device): observable.""" dev = qml.device(device, wires=3, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] def circuit(x): @@ -2620,14 +2719,21 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) for r in res: - assert isinstance(r[0], np.ndarray) + assert isinstance(r[0], (np.ndarray, np.float64)) assert isinstance(r[1], dict) expected_outcomes = {-1, 1} @@ -2650,7 +2756,11 @@ def test_scalar_counts_no_obs(self, shot_vector, meas1, meas2, device): dev = qml.device(device, wires=3, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] def circuit(x): @@ -2661,12 +2771,23 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(m, np.ndarray) for measurement_res in res for m in measurement_res) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res + for m in measurement_res + ) for idx, shots in enumerate(raw_shot_vector): for i, r in enumerate(res[idx]): @@ -2683,7 +2804,11 @@ def test_probs_sample(self, shot_vector, sample_obs, device): dev = qml.device(device, wires=3, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] meas1_wires = [0, 1] @@ -2702,12 +2827,23 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(m, np.ndarray) for measurement_res in res for m in measurement_res) + assert all( + isinstance(m, (np.ndarray, np.float64)) + for measurement_res in res + for m in measurement_res + ) for idx, shots in enumerate(raw_shot_vector): for i, r in enumerate(res[idx]): @@ -2729,7 +2865,11 @@ def test_probs_counts(self, shot_vector, sample_obs, device): """Test probs and counts measurements.""" dev = qml.device(device, wires=3, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] meas1_wires = [0, 1] @@ -2748,12 +2888,21 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(measurement_res[0], np.ndarray) for measurement_res in res) + assert all( + isinstance(measurement_res[0], (np.ndarray, np.float64)) for measurement_res in res + ) assert all(isinstance(measurement_res[1], dict) for measurement_res in res) expected_outcomes = {-1, 1} if sample_obs is not None else {"0", "1"} @@ -2777,7 +2926,11 @@ def test_sample_counts(self, shot_vector, sample_wires, counts_wires, device): samples or computational basis state samples.""" dev = qml.device(device, wires=6, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] def circuit(x): @@ -2802,12 +2955,21 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots assert all(isinstance(r, tuple) for r in res) - assert all(isinstance(measurement_res[0], np.ndarray) for measurement_res in res) + assert all( + isinstance(measurement_res[0], (np.ndarray, np.float64)) for measurement_res in res + ) assert all(isinstance(measurement_res[1], dict) for measurement_res in res) for idx, shots in enumerate(raw_shot_vector): @@ -2828,7 +2990,11 @@ def test_scalar_probs_sample_counts(self, shot_vector, meas1, meas2, device): in a single qfunc.""" dev = qml.device(device, wires=5, shots=shot_vector) raw_shot_vector = [ - shot_tuple.shots for shot_tuple in dev.shot_vector for _ in range(shot_tuple.copies) + shot_tuple.shots + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + for _ in range(shot_tuple.copies) ] def circuit(x): @@ -2845,7 +3011,14 @@ def circuit(x): res = qnode(0.5) - all_shots = sum([shot_tuple.copies for shot_tuple in dev.shot_vector]) + all_shots = sum( + [ + shot_tuple.copies + for shot_tuple in ( + dev.shot_vector if isinstance(dev, qml.Device) else dev.shots.shot_vector + ) + ] + ) assert isinstance(res, tuple) assert len(res) == all_shots @@ -2901,7 +3074,7 @@ def cost(a): res = qml.jacobian(cost)(x) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) assert res.shape == (2, 3) @pytest.mark.torch @@ -3068,7 +3241,7 @@ def cost(a): res = qml.jacobian(cost)(x) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) assert res.shape == (2, 2, 3) @pytest.mark.torch @@ -3207,7 +3380,7 @@ def cost(a): res = qml.jacobian(cost)(x) - assert isinstance(res, np.ndarray) + assert isinstance(res, (np.ndarray, np.float64)) assert res.shape == (6, 3) @pytest.mark.torch diff --git a/tests/test_tensor_measurements.py b/tests/test_tensor_measurements.py index 4f64a68b52d..bca43eba57b 100644 --- a/tests/test_tensor_measurements.py +++ b/tests/test_tensor_measurements.py @@ -18,7 +18,6 @@ import pytest import numpy as np -from gate_data import I, Z, S, Rotx, Roty, H, CNOT import pennylane as qml from pennylane import expval, var, sample @@ -389,25 +388,6 @@ def circuit(a, b, c): # s1 should only contain 1 and -1 assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - zero_state = np.zeros(2**3) - zero_state[0] = 1 - psi = zero_state - psi = tensor_product([Rotx(theta), I, I]) @ zero_state - psi = tensor_product([I, Rotx(phi), I]) @ psi - psi = tensor_product([I, I, Rotx(varphi)]) @ psi - psi = tensor_product([CNOT, I]) @ psi - psi = tensor_product([I, CNOT]) @ psi - - # Diagonalize according to the observable - psi = tensor_product([H, I, I]) @ psi - psi = tensor_product([I, I, Z]) @ psi - psi = tensor_product([I, I, S]) @ psi - psi = tensor_product([I, I, H]) @ psi - - expected_probabilities = np.abs(psi) ** 2 - - assert np.allclose(dev.probability(), expected_probabilities, atol=tol_stochastic, rtol=0) - def test_pauliz_tensor_hadamard(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliZ and hadamard works correctly""" dev = qml.device("default.qubit", wires=3, shots=int(1e6)) @@ -419,25 +399,6 @@ def circuit(a, b, c): s1 = circuit(theta, phi, varphi) - zero_state = np.zeros(2**3) - zero_state[0] = 1 - psi = zero_state - psi = tensor_product([Rotx(theta), I, I]) @ zero_state - psi = tensor_product([I, Rotx(phi), I]) @ psi - psi = tensor_product([I, I, Rotx(varphi)]) @ psi - psi = tensor_product([CNOT, I]) @ psi - psi = tensor_product([I, CNOT]) @ psi - - # Diagonalize according to the observable - psi = tensor_product([I, Roty(-np.pi / 4), I]) @ psi - psi = tensor_product([I, I, Z]) @ psi - psi = tensor_product([I, I, S]) @ psi - psi = tensor_product([I, I, H]) @ psi - - expected_probabilities = np.abs(psi) ** 2 - - assert np.allclose(dev.probability(), expected_probabilities, atol=tol_stochastic, rtol=0) - # s1 should only contain 1 and -1 assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) @@ -465,19 +426,3 @@ def circuit(a, b, c): # the hermitian matrix tensor product Z eigvals = np.linalg.eigvalsh(np.kron(Z, A)) assert set(np.round(s1, 8)).issubset(set(np.round(eigvals, 8))) - - zero_state = np.zeros(2**3) - zero_state[0] = 1 - psi = tensor_product([Rotx(theta), I, I]) @ zero_state - psi = tensor_product([I, Rotx(phi), I]) @ psi - psi = tensor_product([I, I, Rotx(varphi)]) @ psi - psi = tensor_product([CNOT, I]) @ psi - psi = tensor_product([I, CNOT]) @ psi - - # Diagonalize according to the observable - eigvals, eigvecs = np.linalg.eigh(A) - psi = tensor_product([I, eigvecs.conj().T]) @ psi - - expected_probabilities = np.abs(psi) ** 2 - - assert np.allclose(dev.probability(), expected_probabilities, atol=tol_stochastic, rtol=0) diff --git a/tests/test_vqe.py b/tests/test_vqe.py index 33c0910b447..fd881ab0df5 100644 --- a/tests/test_vqe.py +++ b/tests/test_vqe.py @@ -345,15 +345,19 @@ def test_optimize_torch(self, shots): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=4) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) - c2 = cost2(w) - exec_no_opt = dev.num_executions + exec_opt = tracker.latest["executions"] - assert exec_opt == 5 # Number of groups in the Hamiltonian - assert exec_no_opt == 15 + with tracker: + c2 = cost2(w) + + exec_no_opt = tracker.latest["executions"] + + # was 5, 15 on old device + assert exec_opt == 1 # Number of groups in the Hamiltonian + assert exec_no_opt == 1 assert np.allclose(c1, c2, atol=1e-1) @@ -391,15 +395,17 @@ def test_optimize_tf(self, shots): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=4) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) + exec_opt = tracker.latest["executions"] - c2 = cost2(w) - exec_no_opt = dev.num_executions + with tracker: + c2 = cost2(w) + exec_no_opt = tracker.latest["executions"] - assert exec_opt == 5 # Number of groups in the Hamiltonian - assert exec_no_opt == 15 + # was 5, 15 on old device + assert exec_opt == 1 # Number of groups in the Hamiltonian + assert exec_no_opt == 1 assert np.allclose(c1, c2, atol=1e-1) @@ -437,15 +443,17 @@ def test_optimize_autograd(self, shots): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=4) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) + exec_opt = tracker.latest["executions"] - c2 = cost2(w) - exec_no_opt = dev.num_executions + with tracker: + c2 = cost2(w) + exec_no_opt = tracker.latest["executions"] - assert exec_opt == 5 # Number of groups in the Hamiltonian - assert exec_no_opt == 15 + # was 5, 15 on old device + assert exec_opt == 1 # Number of groups in the Hamiltonian + assert exec_no_opt == 1 assert np.allclose(c1, c2, atol=1e-1) @@ -493,15 +501,17 @@ def test_optimize_multiple_terms_autograd(self): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=5) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) + exec_opt = tracker.latest["executions"] - c2 = cost2(w) - exec_no_opt = dev.num_executions + with tracker: + c2 = cost2(w) + exec_no_opt = tracker.latest["executions"] + # was 1, 8 on old device assert exec_opt == 1 # Number of groups in the Hamiltonian - assert exec_no_opt == 8 + assert exec_no_opt == 1 assert np.allclose(c1, c2) @@ -549,15 +559,17 @@ def test_optimize_multiple_terms_torch(self): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=5) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) + exec_opt = tracker.latest["executions"] - c2 = cost2(w) - exec_no_opt = dev.num_executions + with tracker: + c2 = cost2(w) + exec_no_opt = tracker.latest["executions"] + # was 1, 8 on old device assert exec_opt == 1 # Number of groups in the Hamiltonian - assert exec_no_opt == 8 + assert exec_no_opt == 1 assert np.allclose(c1, c2) @@ -605,19 +617,22 @@ def test_optimize_multiple_terms_tf(self): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=5) w = np.random.random(shape) - c1 = cost(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + c1 = cost(w) + exec_opt = tracker.latest["executions"] - c2 = cost2(w) - exec_no_opt = dev.num_executions + with tracker: + c2 = cost2(w) + exec_no_opt = tracker.latest["executions"] + # was 1, 8 on old device assert exec_opt == 1 # Number of groups in the Hamiltonian - assert exec_no_opt == 8 + assert exec_no_opt == 1 assert np.allclose(c1, c2) # pylint: disable=protected-access + @pytest.mark.skip("non-opt is less executions than opt with new device") @pytest.mark.autograd def test_optimize_grad(self): """Test that the gradient of ExpvalCost is accessible and correct when using observable @@ -646,12 +661,13 @@ def test_optimize_grad(self): shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=4) w = pnp.random.uniform(low=0, high=2 * np.pi, size=shape, requires_grad=True) - dc = qml.grad(cost)(w) - exec_opt = dev.num_executions - dev._num_executions = 0 + with qml.Tracker(dev) as tracker: + dc = qml.grad(cost)(w) + exec_opt = tracker.latest["executions"] - dc2 = qml.grad(cost2)(w) - exec_no_opt = dev.num_executions + with tracker: + dc2 = qml.grad(cost2)(w) + exec_no_opt = tracker.latest["executions"] assert exec_no_opt > exec_opt assert np.allclose(dc, big_hamiltonian_grad) @@ -750,7 +766,7 @@ def ansatz(params, **kwargs): h = qml.Hamiltonian([1, 1], [qml.PauliZ(0), qml.PauliZ(1)]) qnodes = catch_warn_ExpvalCost(ansatz, h, dev) - mt = qml.metric_tensor(qnodes, approx=approx)(p) + mt = qml.metric_tensor(qnodes, approx=approx)(p) # pylint:disable=not-callable assert mt.shape == (3, 3) assert isinstance(mt, pnp.ndarray) @@ -843,10 +859,14 @@ def circuit2(): assert np.allclose(res1, res2, atol=tol) - @pytest.mark.autograd + @pytest.mark.jax @pytest.mark.parametrize("shots, dim", [([(1000, 2)], 2), ([30, 30], 2), ([2, 3, 4], 3)]) def test_shot_distribution(self, shots, dim): """Tests that distributed shots work with the new VQE design.""" + import jax + + jax.config.update("jax_enable_x64", True) + dev = qml.device("default.qubit", wires=2, shots=shots) @qml.qnode(dev) @@ -857,12 +877,13 @@ def circuit(weights, coeffs): obs = [qml.PauliZ(0), qml.PauliX(0) @ qml.PauliZ(1)] coeffs = np.array([0.1, 0.2]) - weights = pnp.random.random([2, 2, 3], requires_grad=True) + key = jax.random.PRNGKey(42) + weights = jax.random.uniform(key, [2, 2, 3]) res = circuit(weights, coeffs) - grad = qml.jacobian(circuit, argnum=1)(weights, coeffs) + grad = jax.jacobian(circuit, argnums=[1])(weights, coeffs) assert len(res) == dim - assert grad.shape == (dim, 2) + assert qml.math.shape(grad) == (dim, 1, 2) def test_circuit_drawer(self): """Test that the circuit drawer displays Hamiltonians well.""" @@ -943,9 +964,7 @@ def test_error_var_measurement(self): def circuit(): return qml.var(H) - with pytest.raises( - qml.operation.EigvalsUndefinedError, match="Cannot compute analytic variance" - ): + with pytest.raises(NotImplementedError): circuit() def test_error_sample_measurement(self): @@ -959,7 +978,7 @@ def test_error_sample_measurement(self): def circuit(): return qml.sample(H) - with pytest.raises(ValueError, match="Can only return the expectation of a single"): + with pytest.raises(qml.operation.DiagGatesUndefinedError): circuit() @pytest.mark.autograd @@ -1010,7 +1029,7 @@ def circuit(w): w = torch.tensor(PARAMS, requires_grad=True) res = circuit(w) - res.backward() + res.backward() # pylint:disable=no-member dc = w.grad.detach().numpy() assert np.allclose(dc, big_hamiltonian_grad, atol=tol) diff --git a/tests/transforms/test_adjoint_metric_tensor.py b/tests/transforms/test_adjoint_metric_tensor.py index f79572cd074..04aa867ddec 100644 --- a/tests/transforms/test_adjoint_metric_tensor.py +++ b/tests/transforms/test_adjoint_metric_tensor.py @@ -261,7 +261,7 @@ def test_correct_output_tape_autograd(self, ansatz, params, interface): """Test that the output is correct when using Autograd and calling the adjoint metric tensor directly on a tape.""" expected = autodiff_metric_tensor(ansatz, 3)(*params) - dev = qml.devices.DefaultQubit() + dev = qml.device("default.qubit") wires = ("a", "b", "c") @@ -281,7 +281,8 @@ def circuit(*params): @pytest.mark.jax @pytest.mark.skip("JAX does not support forward pass executiong of the metric tensor.") - def test_correct_output_tape_jax(self, ansatz, params): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.jax"]) + def test_correct_output_tape_jax(self, dev_name, ansatz, params): """Test that the output is correct when using JAX and calling the adjoint metric tensor directly on a tape.""" @@ -292,7 +293,7 @@ def test_correct_output_tape_jax(self, ansatz, params): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) j_params = tuple(jax.numpy.array(p) for p in params) - dev = qml.device("default.qubit.jax", wires=self.num_wires) + dev = qml.device(dev_name, wires=self.num_wires) @qml.qnode(dev, interface="jax") def circuit(*params): @@ -312,7 +313,8 @@ def circuit(*params): @pytest.mark.torch @pytest.mark.parametrize("interface", interfaces) - def test_correct_output_tape_torch(self, ansatz, params, interface): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_correct_output_tape_torch(self, ansatz, params, interface, dev_name): """Test that the output is correct when using Torch and calling the adjoint metric tensor directly on a tape.""" @@ -320,7 +322,7 @@ def test_correct_output_tape_torch(self, ansatz, params, interface): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) t_params = tuple(torch.tensor(p, requires_grad=True) for p in params) - dev = qml.device("default.qubit.torch", wires=self.num_wires) + dev = qml.device(dev_name, wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -340,7 +342,8 @@ def circuit(*params): @pytest.mark.tf @pytest.mark.parametrize("interface", interfaces) - def test_correct_output_tape_tf(self, ansatz, params, interface): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.tf"]) + def test_correct_output_tape_tf(self, ansatz, params, interface, dev_name): """Test that the output is correct when using TensorFlow and calling the adjoint metric tensor directly on a tape.""" @@ -348,7 +351,7 @@ def test_correct_output_tape_tf(self, ansatz, params, interface): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) t_params = tuple(tf.Variable(p) for p in params) - dev = qml.device("default.qubit.tf", wires=self.num_wires) + dev = qml.device(dev_name, wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -432,7 +435,8 @@ def circuit(*params): @pytest.mark.torch @pytest.mark.parametrize("ansatz, params", list(zip(fubini_ansatze, fubini_params))) @pytest.mark.parametrize("interface", interfaces) - def test_correct_output_qnode_torch(self, ansatz, params, interface): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.torch"]) + def test_correct_output_qnode_torch(self, ansatz, params, interface, dev_name): """Test that the output is correct when using Torch and calling the adjoint metric tensor on a QNode.""" @@ -440,7 +444,7 @@ def test_correct_output_qnode_torch(self, ansatz, params, interface): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) t_params = tuple(torch.tensor(p, requires_grad=True, dtype=torch.float64) for p in params) - dev = qml.device("default.qubit.torch", wires=self.num_wires) + dev = qml.device(dev_name, wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -485,7 +489,8 @@ def circuit(*params): assert qml.math.allclose(mt, expected) @pytest.mark.autograd - def test_autograd_with_other_device(self): + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.qubit.autograd"]) + def test_autograd_with_other_device(self, dev_name): """Test passing an extra device to the QNode wrapper.""" ansatz = fubini_ansatz2 params = fubini_params[2] @@ -493,7 +498,7 @@ def test_autograd_with_other_device(self): exp_fn = autodiff_metric_tensor(ansatz, self.num_wires) expected = qml.jacobian(exp_fn)(*params) dev = qml.device("default.qubit", wires=self.num_wires) - dev2 = qml.device("default.qubit.autograd", wires=self.num_wires) + dev2 = qml.device(dev_name, wires=self.num_wires) @qml.qnode(dev) def circuit(*params): diff --git a/tests/transforms/test_batch_input.py b/tests/transforms/test_batch_input.py index 9f02442d2ee..d30a12cc06c 100644 --- a/tests/transforms/test_batch_input.py +++ b/tests/transforms/test_batch_input.py @@ -14,7 +14,7 @@ """ Unit tests for the ``batch_inputs`` transform. """ -# pylint: disable=too-few-public-methods +# pylint: disable=too-few-public-methods,no-value-for-parameter,comparison-with-callable from functools import partial import pytest @@ -183,7 +183,7 @@ def circuit(data, weights): # weights is not batched weights = np.random.random((10, 3, 3), requires_grad=True) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, weights) assert res.shape == (batch_size, 2**3) assert len(spy.call_args[0][0]) == batch_size @@ -222,7 +222,7 @@ def circuit(data, weights): # weights is not batched weights = np.random.random((10, 3, 3), requires_grad=True) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, weights) assert res.shape == (batch_size, 2**3) assert len(spy.call_args[0][0]) == batch_size diff --git a/tests/transforms/test_batch_params.py b/tests/transforms/test_batch_params.py index f2333c59eb2..36accf7bb25 100644 --- a/tests/transforms/test_batch_params.py +++ b/tests/transforms/test_batch_params.py @@ -14,6 +14,7 @@ """ Unit tests for the batch params transform. """ +# pylint:disable=comparison-with-callable import functools import pytest @@ -39,7 +40,7 @@ def circuit(data, x, weights): x = np.linspace(0.1, 0.5, batch_size, requires_grad=True) weights = np.ones((batch_size, 10, 3, 3), requires_grad=True) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, x, weights) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size @@ -63,7 +64,7 @@ def circuit(data, x, weights): x = np.linspace(0.1, 0.5, batch_size, requires_grad=True) weights = np.ones((batch_size, 10, 3, 3), requires_grad=True) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, x, weights) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size @@ -90,7 +91,7 @@ def circuit(data, x, weights): x = np.linspace(0.1, 0.5, batch_size, requires_grad=True) weights = np.ones((batch_size, 10, 3, 3), requires_grad=True) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, x, weights) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size @@ -110,7 +111,7 @@ def circuit(weights): batch_size = 5 weights = np.random.random((batch_size, 2, 2)) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(weights) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size @@ -130,7 +131,7 @@ def circuit(data): batch_size = 5 data = np.random.random((batch_size, 3)) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size @@ -154,7 +155,7 @@ def circuit(data, weights): data /= np.linalg.norm(data, axis=1).reshape(-1, 1) # normalize weights = np.random.random((batch_size, 10, 3, 3)) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, weights) assert res.shape == (batch_size, 2**3) assert len(spy.call_args[0][0]) == batch_size @@ -189,7 +190,7 @@ def circuit(data, weights): data = np.random.randint(2, size=(batch_size, 4)) weights = np.random.random((batch_size, 10, 4, 3)) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, weights) assert res.shape == (batch_size, 2**4) assert len(spy.call_args[0][0]) == batch_size @@ -225,7 +226,7 @@ def circuit(data, weights): data /= np.linalg.norm(data, axis=1).reshape(-1, 1) # normalize weights = np.random.random((batch_size, 10, 3, 3)) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(data, weights) assert res.shape == (batch_size, 2**3) assert len(spy.call_args[0][0]) == batch_size @@ -272,6 +273,7 @@ def circuit(data, x, weights): def test_shot_vector(): """Test that batching works for a simple circuit with a shot vector""" + # pylint:disable=not-an-iterable dev = qml.device("default.qubit", wires=3, shots=(100, (200, 3), 300)) @qml.batch_params @@ -801,7 +803,7 @@ def circuit(x, weights): x = np.linspace(0.1, 0.5, batch_size, requires_grad=True) weights = np.ones((batch_size, 10, 3, 3), requires_grad=False) - spy = mocker.spy(circuit.device, "batch_execute") + spy = mocker.spy(circuit.device, "execute") res = circuit(x, weights) assert res.shape == (batch_size, 4) assert len(spy.call_args[0][0]) == batch_size diff --git a/tests/transforms/test_batch_transform.py b/tests/transforms/test_batch_transform.py index 742e15bc78b..eb2d671da38 100644 --- a/tests/transforms/test_batch_transform.py +++ b/tests/transforms/test_batch_transform.py @@ -428,7 +428,7 @@ def circuit(x): assert tapes[1].operations[1].name == "RZ" assert tapes[1].operations[1].parameters == [b * np.sin(x)] - expected = fn(dev.batch_execute(tapes)) + expected = fn(dev.execute(tapes)) assert res == expected assert circuit.interface == "auto" @@ -464,7 +464,7 @@ def circuit(x): assert tapes[1].operations[1].name == "RZ" assert tapes[1].operations[1].parameters == [b * np.sin(x)] - expected = fn(dev.batch_execute(tapes)) + expected = fn(dev.execute(tapes)) assert res == expected def test_custom_qnode_wrapper(self): @@ -667,7 +667,7 @@ def circuit(weights): qml.CNOT(wires=[0, 1]) return qml.expval(H) - spy = mocker.spy(dev, "batch_transform") + spy = mocker.spy(dev, "preprocess") res = circuit(weights) spy.assert_called() diff --git a/tests/transforms/test_hamiltonian_expand.py b/tests/transforms/test_hamiltonian_expand.py index b6d4581e157..886623740fd 100644 --- a/tests/transforms/test_hamiltonian_expand.py +++ b/tests/transforms/test_hamiltonian_expand.py @@ -100,14 +100,14 @@ def test_hamiltonians(self, tape, output): """Tests that the hamiltonian_expand transform returns the correct value""" tapes, fn = hamiltonian_expand(tape) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) qs = QuantumScript(tape.operations, tape.measurements) tapes, fn = hamiltonian_expand(qs) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) @@ -117,14 +117,14 @@ def test_hamiltonians_no_grouping(self, tape, output): if we switch grouping off""" tapes, fn = hamiltonian_expand(tape, group=False) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) qs = QuantumScript(tape.operations, tape.measurements) tapes, fn = hamiltonian_expand(qs, group=False) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) @@ -274,10 +274,10 @@ def test_hamiltonian_dif_tensorflow(self): with tf.GradientTape() as gtape: with AnnotatedQueue() as q: - for i in range(2): - qml.RX(var[i, 0], wires=0) - qml.RX(var[i, 1], wires=1) - qml.RX(var[i, 2], wires=2) + for _i in range(2): + qml.RX(var[_i, 0], wires=0) + qml.RX(var[_i, 1], wires=1) + qml.RX(var[_i, 2], wires=2) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) qml.CNOT(wires=[2, 0]) @@ -405,8 +405,21 @@ def test_observables_on_same_wires(self): @pytest.mark.parametrize(("qscript", "output"), zip(SUM_QSCRIPTS, SUM_OUTPUTS)) def test_sums(self, qscript, output): """Tests that the sum_expand transform returns the correct value""" + processed, _ = dev.preprocess()[0]([qscript]) + assert len(processed) == 1 + qscript = processed[0] tapes, fn = sum_expand(qscript) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) + expval = fn(results) + + assert all(qml.math.allclose(o, e) for o, e in zip(output, expval)) + + @pytest.mark.parametrize(("qscript", "output"), zip(SUM_QSCRIPTS, SUM_OUTPUTS)) + def test_sums_legacy(self, qscript, output): + """Tests that the sum_expand transform returns the correct value""" + dev_old = qml.device("default.qubit.legacy", wires=4) + tapes, fn = sum_expand(qscript) + results = dev_old.batch_execute(tapes) expval = fn(results) assert all(qml.math.allclose(o, e) for o, e in zip(output, expval)) @@ -415,8 +428,11 @@ def test_sums(self, qscript, output): def test_sums_no_grouping(self, qscript, output): """Tests that the sum_expand transform returns the correct value if we switch grouping off""" + processed, _ = dev.preprocess()[0]([qscript]) + assert len(processed) == 1 + qscript = processed[0] tapes, fn = sum_expand(qscript, group=False) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert all(qml.math.allclose(o, e) for o, e in zip(output, expval)) @@ -559,10 +575,10 @@ def test_sum_dif_tensorflow(self): with tf.GradientTape() as gtape: with AnnotatedQueue() as q: - for i in range(2): - qml.RX(var[i, 0], wires=0) - qml.RX(var[i, 1], wires=1) - qml.RX(var[i, 2], wires=2) + for _i in range(2): + qml.RX(var[_i, 0], wires=0) + qml.RX(var[_i, 1], wires=1) + qml.RX(var[_i, 2], wires=2) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) qml.CNOT(wires=[2, 0]) diff --git a/tests/transforms/test_metric_tensor.py b/tests/transforms/test_metric_tensor.py index c28fcb23638..1b4c6db5807 100644 --- a/tests/transforms/test_metric_tensor.py +++ b/tests/transforms/test_metric_tensor.py @@ -14,7 +14,7 @@ """ Unit tests for the metric tensor transform. """ -# pylint: disable=too-many-arguments,too-many-public-methods,too-few-public-methods +# pylint: disable=too-many-arguments,too-many-public-methods,too-few-public-methods,not-callable import pytest from scipy.linalg import block_diag @@ -93,6 +93,7 @@ def circuit(a): circuit = qml.QNode(circuit, dev, diff_method=diff_method) params = np.array([0.1], requires_grad=True) + # pylint:disable=unexpected-keyword-arg result = qml.metric_tensor(circuit, hybrid=False, approx="block-diag")(*params) assert result.shape == (2, 2) @@ -1192,6 +1193,7 @@ def circuit(*params): return qml.expval(qml.PauliZ(0)) if len(params) > 1: + # pylint:disable=unexpected-keyword-arg mt = qml.metric_tensor(circuit, argnums=range(0, len(params)), approx=None)(*params) else: mt = qml.metric_tensor(circuit, approx=None)(*params) @@ -1760,7 +1762,7 @@ def circuit(x): return qml.expval(qml.PauliZ(0)) x = np.array([1.3, 0.2]) - with pytest.raises(qml.wires.WireError, match=r"Did not find some of the wires \(0, 1\)"): + with pytest.raises(qml.wires.WireError, match=r"contain wires not found on the device: \{1\}"): qml.transforms.metric_tensor(circuit)(x) diff --git a/tests/transforms/test_qcut.py b/tests/transforms/test_qcut.py index e7b92977037..d6c87fd4191 100644 --- a/tests/transforms/test_qcut.py +++ b/tests/transforms/test_qcut.py @@ -15,7 +15,8 @@ Unit tests for the `pennylane.qcut` package. """ # pylint: disable=protected-access,too-few-public-methods,too-many-arguments -# pylint: disable=too-many-public-methods +# pylint: disable=too-many-public-methods,comparison-with-callable +# pylint: disable=no-value-for-parameter,no-member,not-callable import copy import itertools import string @@ -3718,7 +3719,7 @@ def test_qcut_processing_fn_tf(self, use_opt_einsum): x = tf.Variable(0.9, dtype=tf.float64) def f(x): - x = tf.cast(x, dtype=tf.float64) + x = tf.cast(x, dtype=tf.float64) # pylint:disable=unexpected-keyword-arg t1 = x * tf.range(4, dtype=tf.float64) t2 = x**2 * tf.range(16, dtype=tf.float64) t3 = tf.sin(x * np.pi / 2) * tf.range(4, dtype=tf.float64) @@ -4020,7 +4021,9 @@ def test_simple_cut_circuit_torch_trace(self, mocker, use_opt_einsum): import torch - dev = qml.device("default.qubit", wires=2) + # TODO: this passes with default.qubit locally, but fails on CI + # possibly an architecture-specific issue + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface="torch") def circuit(x): @@ -4635,7 +4638,7 @@ def test_init_raises(self, devices, imbalance_tolerance, num_fragments_probed): """Test if ill-initialized instances throw errors.""" if ( - isinstance(devices, qml.Device) + isinstance(devices, (qml.Device, qml.devices.Device)) and imbalance_tolerance is None and num_fragments_probed is None ): diff --git a/tests/transforms/test_qmc_transform.py b/tests/transforms/test_qmc_transform.py index 9e2542986b5..61446d0c6aa 100644 --- a/tests/transforms/test_qmc_transform.py +++ b/tests/transforms/test_qmc_transform.py @@ -85,7 +85,7 @@ def unitary_z(basis_state): return qml.state() bitstrings = list(itertools.product([0, 1], repeat=n_wires)) - u = [unitary_z(np.array(bitstring)).numpy() for bitstring in bitstrings] + u = [unitary_z(np.array(bitstring)) for bitstring in bitstrings] u = np.array(u).T return u diff --git a/tests/transforms/test_sign_expand.py b/tests/transforms/test_sign_expand.py index 2641d749f1b..eec92d9ee9d 100644 --- a/tests/transforms/test_sign_expand.py +++ b/tests/transforms/test_sign_expand.py @@ -98,7 +98,7 @@ def test_hamiltonians(self, tape, output): """Tests that the sign_expand transform returns the correct value""" tapes, fn = qml.transforms.sign_expand(tape) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) @@ -125,7 +125,7 @@ def test_hamiltonians_circuit_impl(self, tape, output): """ tapes, fn = qml.transforms.sign_expand(tape, circuit=True) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval, 1e-2) @@ -186,7 +186,7 @@ def test_hamiltonians_vars(self, tape, output): """Tests that the sign_expand transform returns the correct value""" tapes, fn = qml.transforms.sign_expand(tape) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval) @@ -198,7 +198,7 @@ def test_hamiltonians_vars_circuit_impl(self, tape, output): """ tapes, fn = qml.transforms.sign_expand(tape, circuit=True) - results = dev.batch_execute(tapes) + results = dev.execute(tapes) expval = fn(results) assert np.isclose(output, expval, 1e-1) diff --git a/tests/transforms/test_specs.py b/tests/transforms/test_specs.py index bcc8540318a..10c499be588 100644 --- a/tests/transforms/test_specs.py +++ b/tests/transforms/test_specs.py @@ -49,16 +49,12 @@ def circ(): assert info["num_device_wires"] == 1 assert info["diff_method"] == diff_method assert info["num_trainable_params"] == 0 + assert info["device_name"] == dev.name if diff_method == "parameter-shift": assert info["num_gradient_executions"] == 0 assert info["gradient_fn"] == "pennylane.gradients.parameter_shift.param_shift" - if diff_method != "backprop": - assert info["device_name"] == "default.qubit" - else: - assert info["device_name"] == "default.qubit.autograd" - @pytest.mark.parametrize( "diff_method, len_info", [("backprop", 11), ("parameter-shift", 12), ("adjoint", 11)] ) @@ -96,18 +92,14 @@ def circuit(x, y, add_RY=True): assert info["num_observables"] == 2 assert info["num_diagonalizing_gates"] == 1 - assert info["num_device_wires"] == 4 + assert info["num_device_wires"] == 3 assert info["diff_method"] == diff_method assert info["num_trainable_params"] == 4 + assert info["device_name"] == dev.name if diff_method == "parameter-shift": assert info["num_gradient_executions"] == 6 - if diff_method != "backprop": - assert info["device_name"] == "default.qubit" - else: - assert info["device_name"] == "default.qubit.autograd" - @pytest.mark.parametrize( "diff_method, len_info", [("backprop", 11), ("parameter-shift", 12), ("adjoint", 11)] ) @@ -143,10 +135,11 @@ def circuit(params): params_shape = qml.BasicEntanglerLayers.shape(n_layers=n_layers, n_wires=n_wires) rng = np.random.default_rng(seed=10) - params = rng.standard_normal(params_shape) + params = rng.standard_normal(params_shape) # pylint:disable=no-member return circuit, params + @pytest.mark.xfail(reason="DefaultQubit2 does not support custom expansion depths") def test_max_expansion(self): """Test that a user can calculation specifications for a different max expansion parameter.""" @@ -167,7 +160,7 @@ def test_max_expansion(self): assert info["resources"] == expected_resources assert info["num_observables"] == 1 assert info["num_device_wires"] == 5 - assert info["device_name"] == "default.qubit.autograd" + assert info["device_name"] == "default.qubit" assert info["diff_method"] == "best" assert info["gradient_fn"] == "backprop" @@ -209,3 +202,22 @@ def circuit(): info = qml.specs(circuit)() assert info["diff_method"] == "test_specs.my_transform" assert info["gradient_fn"] == "test_specs.my_transform" + + @pytest.mark.parametrize( + "device,num_wires", + [ + (qml.device("default.qubit"), 1), + (qml.device("default.qubit", wires=2), 1), + (qml.device("default.qubit.legacy", wires=2), 2), + ], + ) + def test_num_wires_source_of_truth(self, device, num_wires): + """Tests that num_wires behaves differently on old and new devices.""" + + @qml.qnode(device) + def circuit(): + qml.PauliX(0) + return qml.state() + + info = qml.specs(circuit)() + assert info["num_device_wires"] == num_wires