From 0cd4c04c362eba3f8628e550b75949f868424190 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 31 Jul 2023 16:16:01 -0400 Subject: [PATCH 01/78] change default.qubit entrypoint to DQ2; copy tests --- pennylane/__init__.py | 1 + .../devices/experimental/default_qubit_2.py | 7 +- pennylane/devices/experimental/device_api.py | 8 +- setup.py | 2 +- .../default_qubit_1/test_default_qubit.py | 2496 +++++++++++++++++ .../test_default_qubit_autograd.py | 802 ++++++ .../test_default_qubit_broadcasting.py | 2023 +++++++++++++ .../default_qubit_1/test_default_qubit_jax.py | 1312 +++++++++ .../default_qubit_1/test_default_qubit_tf.py | 2315 +++++++++++++++ .../test_default_qubit_torch.py | 2492 ++++++++++++++++ 10 files changed, 11454 insertions(+), 4 deletions(-) create mode 100644 tests/devices/default_qubit_1/test_default_qubit.py create mode 100644 tests/devices/default_qubit_1/test_default_qubit_autograd.py create mode 100644 tests/devices/default_qubit_1/test_default_qubit_broadcasting.py create mode 100644 tests/devices/default_qubit_1/test_default_qubit_jax.py create mode 100644 tests/devices/default_qubit_1/test_default_qubit_tf.py create mode 100644 tests/devices/default_qubit_1/test_default_qubit_torch.py diff --git a/pennylane/__init__.py b/pennylane/__init__.py index e43381d2a90..beacc9ef093 100644 --- a/pennylane/__init__.py +++ b/pennylane/__init__.py @@ -122,6 +122,7 @@ import pennylane.gradients # pylint:disable=wrong-import-order import pennylane.qinfo # pylint:disable=wrong-import-order from pennylane.interfaces import execute # pylint:disable=wrong-import-order +from pennylane.devices.experimental import DefaultQubit2 # Look for an existing configuration file default_config = Configuration("config.toml") diff --git a/pennylane/devices/experimental/default_qubit_2.py b/pennylane/devices/experimental/default_qubit_2.py index e072f64edbb..89384edbe43 100644 --- a/pennylane/devices/experimental/default_qubit_2.py +++ b/pennylane/devices/experimental/default_qubit_2.py @@ -26,6 +26,7 @@ from pennylane.tape import QuantumTape, QuantumScript from pennylane.typing import Result, ResultBatch from pennylane.transforms import convert_to_numpy_parameters +from pennylane._version import __version__ from pennylane import DeviceError, Snapshot from . import Device @@ -133,13 +134,15 @@ def f(x): """ + pennylane_requires = __version__ + @property def name(self): """The name of the device.""" return "default.qubit.2" - def __init__(self, shots=None, seed="global", max_workers=None) -> None: - super().__init__(shots=shots) + def __init__(self, wires=None, shots=None, seed="global", max_workers=None) -> None: + super().__init__(wires=wires, shots=shots) self._max_workers = max_workers seed = np.random.randint(0, high=10000000) if seed == "global" else seed self._rng = np.random.default_rng(seed) diff --git a/pennylane/devices/experimental/device_api.py b/pennylane/devices/experimental/device_api.py index cc1b0c8b0de..a45a94c7050 100644 --- a/pennylane/devices/experimental/device_api.py +++ b/pennylane/devices/experimental/device_api.py @@ -153,10 +153,11 @@ def name(self) -> str: self.tracker.record() """ - def __init__(self, shots=None) -> None: + def __init__(self, wires=None, shots=None) -> None: # each instance should have its own Tracker. self.tracker = Tracker() self._shots = Shots(shots) + self._wires = wires @property def shots(self) -> Shots: @@ -168,6 +169,11 @@ def shots(self) -> Shots: """ return self._shots + @property + def wires(self): + """The device wires. None means any wires can be used.""" + return self._wires + def preprocess( self, circuits: QuantumTape_or_Batch, diff --git a/setup.py b/setup.py index dca6b2b2554..9e0f37dc6c0 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,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:DefaultQubit", + "default.qubit = pennylane.devices.experimental:DefaultQubit2", "default.gaussian = pennylane.devices:DefaultGaussian", "default.qubit.tf = pennylane.devices.default_qubit_tf:DefaultQubitTF", "default.qubit.torch = pennylane.devices.default_qubit_torch:DefaultQubitTorch", diff --git a/tests/devices/default_qubit_1/test_default_qubit.py b/tests/devices/default_qubit_1/test_default_qubit.py new file mode 100644 index 00000000000..153a7a1aeb9 --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit.py @@ -0,0 +1,2496 @@ +# Copyright 2018-2020 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 :mod:`pennylane.plugin.DefaultQubit` device. +""" +# pylint: disable=too-many-arguments,too-few-public-methods +# pylint: disable=protected-access,cell-var-from-loop,no-member +import cmath + +import math + +from functools import partial +import pytest + +import pennylane as qml +from pennylane import DeviceError +from pennylane import numpy as np +from pennylane.devices.default_qubit import DefaultQubit, _get_slice +from pennylane.pulse import ParametrizedHamiltonian +from pennylane.wires import WireError, Wires + +U = np.array( + [ + [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], + [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], + ] +) + +U2 = np.array( + [ + [ + -0.07843244 - 3.57825948e-01j, + 0.71447295 - 5.38069384e-02j, + 0.20949966 + 6.59100734e-05j, + -0.50297381 + 2.35731613e-01j, + ], + [ + -0.26626692 + 4.53837083e-01j, + 0.27771991 - 2.40717436e-01j, + 0.41228017 - 1.30198687e-01j, + 0.01384490 - 6.33200028e-01j, + ], + [ + -0.69254712 - 2.56963068e-02j, + -0.15484858 + 6.57298384e-02j, + -0.53082141 + 7.18073414e-02j, + -0.41060450 - 1.89462315e-01j, + ], + [ + -0.09686189 - 3.15085273e-01j, + -0.53241387 - 1.99491763e-01j, + 0.56928622 + 3.97704398e-01j, + -0.28671074 - 6.01574497e-02j, + ], + ] +) + +U_toffoli = np.diag([1 for i in range(8)]) +U_toffoli[6:8, 6:8] = np.array([[0, 1], [1, 0]]) + +U_swap = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) + +U_cswap = np.array( + [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + ] +) + +THETA = np.linspace(0.11, 1, 3) +PHI = np.linspace(0.32, 1, 3) +VARPHI = np.linspace(0.02, 1, 3) + + +def test_analytic_deprecation(): + """Tests if the kwarg `analytic` is used and displays error message.""" + msg = "The analytic argument has been replaced by shots=None. " + msg += "Please use shots=None instead of analytic=True." + + with pytest.raises( + DeviceError, + match=msg, + ): + qml.device("default.qubit", wires=1, shots=1, analytic=True) + + +def test_dtype_errors(): + """Test that if an incorrect dtype is provided to the device then an error is raised.""" + with pytest.raises(DeviceError, match="Real datatype must be a floating point type."): + qml.device("default.qubit", wires=1, r_dtype=np.complex128) + with pytest.raises( + DeviceError, match="Complex datatype must be a complex floating point type." + ): + qml.device("default.qubit", wires=1, c_dtype=np.float64) + + +def test_custom_op_with_matrix(): + """Test that a dummy op with a matrix is supported.""" + + class DummyOp(qml.operation.Operation): + num_wires = 1 + + def compute_matrix(self): # pylint:disable=arguments-differ + return np.eye(2) + + with qml.queuing.AnnotatedQueue() as q: + DummyOp(0) + qml.state() + + tape = qml.tape.QuantumScript.from_queue(q) + dev = qml.device("default.qubit", wires=1) + assert qml.math.allclose(dev.execute(tape), np.array([1, 0])) + + +class TestApply: + """Tests that operations and inverses of certain operations are applied correctly or that the proper + errors are raised. + """ + + test_data_no_parameters = [ + (qml.PauliX, [1, 0], np.array([0, 1])), + (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1 / math.sqrt(2)]), + (qml.PauliY, [1, 0], [0, 1j]), + (qml.PauliY, [1 / math.sqrt(2), 1 / math.sqrt(2)], [-1j / math.sqrt(2), 1j / math.sqrt(2)]), + (qml.PauliZ, [1, 0], [1, 0]), + (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), -1 / math.sqrt(2)]), + (qml.S, [1, 0], [1, 0]), + (qml.S, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1j / math.sqrt(2)]), + (qml.T, [1, 0], [1, 0]), + ( + qml.T, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / math.sqrt(2), np.exp(1j * np.pi / 4) / math.sqrt(2)], + ), + (qml.Hadamard, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)]), + (qml.Hadamard, [1 / math.sqrt(2), -1 / math.sqrt(2)], [0, 1]), + (qml.Identity, [1, 0], [1, 0]), + (qml.Identity, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1 / math.sqrt(2)]), + ] + + @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) + def test_apply_operation_single_wire_no_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have no parameters.""" + + qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) + qubit_device_1_wire.apply([operation(wires=[0])]) + + assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) + assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE + + test_data_two_wires_no_parameters = [ + (qml.CNOT, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.CNOT, [0, 0, 1, 0], [0, 0, 0, 1]), + ( + qml.CNOT, + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + [1 / math.sqrt(2), 0, 1 / math.sqrt(2), 0], + ), + (qml.SWAP, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.SWAP, [0, 0, 1, 0], [0, 1, 0, 0]), + ( + qml.SWAP, + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + [1 / math.sqrt(2), -1 / math.sqrt(2), 0, 0], + ), + (qml.CZ, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.CZ, [0, 0, 0, 1], [0, 0, 0, -1]), + ( + qml.CZ, + [1 / math.sqrt(2), 0, 0, -1 / math.sqrt(2)], + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + ), + ] + + test_data_iswap = [ + (qml.ISWAP, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.ISWAP, [0, 0, 1, 0], [0, 1j, 0, 0]), + ( + qml.ISWAP, + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + [1 / math.sqrt(2), -1j / math.sqrt(2), 0, 0], + ), + ] + + test_data_siswap = [ + (qml.SISWAP, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.SISWAP, [0, 1, 0, 0], [0, 1 / math.sqrt(2), 1 / math.sqrt(2) * 1j, 0]), + ( + qml.SISWAP, + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [1 / math.sqrt(2), 0.5, 0.5 * 1j, 0], + ), + ] + + test_data_sqisw = [ + (qml.SQISW, [1, 0, 0, 0], [1, 0, 0, 0]), + (qml.SQISW, [0, 1, 0, 0], [0, 1 / math.sqrt(2), 1 / math.sqrt(2) * 1j, 0]), + ( + qml.SQISW, + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [1 / math.sqrt(2), 0.5, 0.5 * 1j, 0], + ), + ] + + all_two_wires_no_parameters = ( + test_data_two_wires_no_parameters + test_data_iswap + test_data_siswap + test_data_sqisw + ) + + @pytest.mark.parametrize("operation,input,expected_output", all_two_wires_no_parameters) + def test_apply_operation_two_wires_no_parameters( + self, qubit_device_2_wires, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for two wire + operations that have no parameters.""" + + qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( + (2, 2) + ) + qubit_device_2_wires.apply([operation(wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 + ) + assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE + + test_data_three_wires_no_parameters = [ + (qml.CSWAP, [1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0]), + (qml.CSWAP, [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0]), + (qml.CSWAP, [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0, 0]), + ] + + @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) + def test_apply_operation_three_wires_no_parameters( + self, qubit_device_3_wires, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for three wire + operations that have no parameters.""" + + qubit_device_3_wires._state = np.array(input, dtype=qubit_device_3_wires.C_DTYPE).reshape( + (2, 2, 2) + ) + qubit_device_3_wires.apply([operation(wires=[0, 1, 2])]) + + assert np.allclose( + qubit_device_3_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 + ) + assert qubit_device_3_wires._state.dtype == qubit_device_3_wires.C_DTYPE + + @pytest.mark.parametrize( + "operation,expected_output,par", + [ + (qml.BasisState, [0, 0, 1, 0], [1, 0]), + (qml.BasisState, [0, 0, 1, 0], [1, 0]), + (qml.BasisState, [0, 0, 0, 1], [1, 1]), + (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), + (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), + (qml.QubitStateVector, [0, 0, 0, 1], [0, 0, 0, 1]), + ( + qml.QubitStateVector, + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + ), + ( + qml.QubitStateVector, + [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], + [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], + ), + ], + ) + def test_apply_operation_state_preparation( + self, qubit_device_2_wires, tol, operation, expected_output, par + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have no parameters.""" + + par = np.array(par) + qubit_device_2_wires.reset() + qubit_device_2_wires.apply([operation(par, wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 + ) + + test_data_single_wire_with_parameters = [ + (qml.PhaseShift, [1, 0], [1, 0], [math.pi / 2]), + (qml.PhaseShift, [0, 1], [0, 1j], [math.pi / 2]), + ( + qml.PhaseShift, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / math.sqrt(2), 1 / 2 + 1j / 2], + [math.pi / 4], + ), + (qml.RX, [1, 0], [1 / math.sqrt(2), -1j * 1 / math.sqrt(2)], [math.pi / 2]), + (qml.RX, [1, 0], [0, -1j], [math.pi]), + ( + qml.RX, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / 2 - 1j / 2, 1 / 2 - 1j / 2], + [math.pi / 2], + ), + (qml.RY, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)], [math.pi / 2]), + (qml.RY, [1, 0], [0, 1], [math.pi]), + (qml.RY, [1 / math.sqrt(2), 1 / math.sqrt(2)], [0, 1], [math.pi / 2]), + (qml.RZ, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2]), + (qml.RZ, [0, 1], [0, 1j], [math.pi]), + ( + qml.RZ, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], + [math.pi / 2], + ), + (qml.MultiRZ, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2]), + (qml.MultiRZ, [0, 1], [0, 1j], [math.pi]), + ( + qml.MultiRZ, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], + [math.pi / 2], + ), + (qml.Rot, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2, 0, 0]), + (qml.Rot, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)], [0, math.pi / 2, 0]), + ( + qml.Rot, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], + [0, 0, math.pi / 2], + ), + ( + qml.Rot, + [1, 0], + [-1j / math.sqrt(2), -1 / math.sqrt(2)], + [math.pi / 2, -math.pi / 2, math.pi / 2], + ), + ( + qml.Rot, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / 2 + 1j / 2, -1 / 2 + 1j / 2], + [-math.pi / 2, math.pi, math.pi], + ), + ( + qml.QubitUnitary, + [1, 0], + [1j / math.sqrt(2), 1j / math.sqrt(2)], + [ + np.array( + [ + [1j / math.sqrt(2), 1j / math.sqrt(2)], + [1j / math.sqrt(2), -1j / math.sqrt(2)], + ] + ) + ], + ), + ( + qml.QubitUnitary, + [0, 1], + [1j / math.sqrt(2), -1j / math.sqrt(2)], + [ + np.array( + [ + [1j / math.sqrt(2), 1j / math.sqrt(2)], + [1j / math.sqrt(2), -1j / math.sqrt(2)], + ] + ) + ], + ), + ( + qml.QubitUnitary, + [1 / math.sqrt(2), -1 / math.sqrt(2)], + [0, 1j], + [ + np.array( + [ + [1j / math.sqrt(2), 1j / math.sqrt(2)], + [1j / math.sqrt(2), -1j / math.sqrt(2)], + ] + ) + ], + ), + (qml.DiagonalQubitUnitary, [1, 0], [-1, 0], [np.array([-1, 1])]), + ( + qml.DiagonalQubitUnitary, + [1 / math.sqrt(2), 1 / math.sqrt(2)], + [1 / math.sqrt(2), 1j / math.sqrt(2)], + [np.array([1, 1j])], + ), + ( + qml.DiagonalQubitUnitary, + [1 / 2, math.sqrt(3) / 4], + [cmath.exp(1j * 0.4) / 2, cmath.exp(1j * -0.4) * math.sqrt(3) / 4], + [np.array([cmath.exp(1j * 0.4), cmath.exp(1j * -0.4)])], + ), + (qml.SpecialUnitary, [1, 0], [0, 1j], [np.array([np.pi / 2, 0, 0])]), + (qml.SpecialUnitary, [1, 0], [0, -1], [np.array([0, np.pi / 2, 0])]), + (qml.SpecialUnitary, [1, 0], [1j, 0], [np.array([0, 0, np.pi / 2])]), + (qml.SpecialUnitary, [0.6, 0.8], [0.573 + 0.236j, 0.764 + 0.177j], [np.array([0.3, 0, 0])]), + ( + qml.SpecialUnitary, + [0.8j, -0.6], + [-0.808 + 0.049j, -0.411 + 0.419j], + [np.array([0.4, 0.2, 1.2])], + ), + ] + + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_single_wire_with_parameters + ) + def test_apply_operation_single_wire_with_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have parameters.""" + + qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) + + qubit_device_1_wire.apply([operation(*par, wires=[0])]) + + assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) + assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE + + test_data_two_wires_with_parameters = [ + (qml.CRX, [0, 1, 0, 0], [0, 1, 0, 0], [math.pi / 2]), + (qml.CRX, [0, 0, 0, 1], [0, 0, -1j, 0], [math.pi]), + ( + qml.CRX, + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 1 / math.sqrt(2), 1 / 2, -1j / 2], + [math.pi / 2], + ), + (qml.CRY, [0, 0, 0, 1], [0, 0, -1 / math.sqrt(2), 1 / math.sqrt(2)], [math.pi / 2]), + (qml.CRY, [0, 0, 0, 1], [0, 0, -1, 0], [math.pi]), + ( + qml.CRY, + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [math.pi / 2], + ), + (qml.CRZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2)], [math.pi / 2]), + (qml.CRZ, [0, 0, 0, 1], [0, 0, 0, 1j], [math.pi]), + ( + qml.CRZ, + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [math.pi / 2], + ), + (qml.MultiRZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], [math.pi / 2]), + (qml.MultiRZ, [0, 0, 1, 0], [0, 0, 1j, 0], [math.pi]), + ( + qml.MultiRZ, + [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], + [1 / 2 - 1j / 2, 1 / 2 + 1j / 2, 0, 0], + [math.pi / 2], + ), + ( + qml.CRot, + [0, 0, 0, 1], + [0, 0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2)], + [math.pi / 2, 0, 0], + ), + (qml.CRot, [0, 0, 0, 1], [0, 0, -1 / math.sqrt(2), 1 / math.sqrt(2)], [0, math.pi / 2, 0]), + ( + qml.CRot, + [0, 0, 1 / math.sqrt(2), 1 / math.sqrt(2)], + [0, 0, 1 / 2 - 1j / 2, 1 / 2 + 1j / 2], + [0, 0, math.pi / 2], + ), + ( + qml.CRot, + [0, 0, 0, 1], + [0, 0, 1 / math.sqrt(2), 1j / math.sqrt(2)], + [math.pi / 2, -math.pi / 2, math.pi / 2], + ), + ( + qml.CRot, + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 1 / math.sqrt(2), 0, -1 / 2 + 1j / 2], + [-math.pi / 2, math.pi, math.pi], + ), + ( + qml.QubitUnitary, + [1, 0, 0, 0], + [1, 0, 0, 0], + [ + np.array( + [ + [1, 0, 0, 0], + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + [0, 0, 0, 1], + ] + ) + ], + ), + ( + qml.QubitUnitary, + [0, 1, 0, 0], + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [ + np.array( + [ + [1, 0, 0, 0], + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + [0, 0, 0, 1], + ] + ) + ], + ), + ( + qml.QubitUnitary, + [1 / 2, 1 / 2, -1 / 2, 1 / 2], + [1 / 2, 0, 1 / math.sqrt(2), 1 / 2], + [ + np.array( + [ + [1, 0, 0, 0], + [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + [0, 0, 0, 1], + ] + ) + ], + ), + (qml.DiagonalQubitUnitary, [1, 0, 0, 0], [-1, 0, 0, 0], [np.array([-1, 1, 1, -1])]), + ( + qml.DiagonalQubitUnitary, + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + [1 / math.sqrt(2), 0, 0, -1 / math.sqrt(2)], + [np.array([1, 1, 1, -1])], + ), + (qml.DiagonalQubitUnitary, [0, 0, 1, 0], [0, 0, 1j, 0], [np.array([-1, 1j, 1j, -1])]), + ( + qml.SpecialUnitary, + [0.5, -0.5j, 0.5j, -0.5], + [0.382 - 0.322j, -0.322 - 0.382j, 0.322 + 0.382j, -0.382 + 0.322j], + [np.eye(15)[4] * 0.7], + ), + ( + qml.SpecialUnitary, + [0.6, 0, 0, -0.8], + [0.553, 0.312, -0.234, -0.737], + [np.eye(15)[10] * 0.4], + ), + ( + qml.SpecialUnitary, + [0, 0, 1, 0], + [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], + [-np.eye(15)[4] * np.pi / 4], + ), # Like Ising XX + ( + qml.SpecialUnitary, + [0, 0, 1, 0], + [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], + [-np.eye(15)[9] * np.pi / 4], + ), # Like Ising YY + ( + qml.SpecialUnitary, + [0, 0, 0, 1], + [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], + [-np.eye(15)[14] * np.pi / 4], + ), # Like Ising ZZ + ( + qml.SpecialUnitary, + [0.5, -0.5j, -0.5, -0.5], + [-0.616 - 0.018j, 0.316 + 0.243j, 0.427 + 0.437j, 0.294 + 0.043j], + [np.linspace(0.1, 3, 15)], + ), + (qml.IsingXX, [0, 0, 1, 0], [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], [math.pi / 2]), + (qml.IsingXX, [0, 0, 0, 1], [-1j / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], [math.pi / 2]), + (qml.IsingXX, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, -1j / math.sqrt(2)], [math.pi / 2]), + (qml.IsingYY, [0, 0, 1, 0], [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], [math.pi / 2]), + (qml.IsingYY, [0, 0, 0, 1], [1j / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], [math.pi / 2]), + (qml.IsingYY, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, 1j / math.sqrt(2)], [math.pi / 2]), + (qml.IsingZZ, [0, 0, 1, 0], [0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2), 0], [math.pi / 2]), + (qml.IsingZZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], [math.pi / 2]), + (qml.IsingZZ, [1, 0, 0, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0, 0, 0], [math.pi / 2]), + ] + + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_two_wires_with_parameters + ) + def test_apply_operation_two_wires_with_parameters( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that applying an operation yields the expected output state for two wire + operations that have parameters.""" + + qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( + (2, 2) + ) + qubit_device_2_wires.apply([operation(*par, wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 + ) + assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE + + def test_apply_errors_qubit_state_vector(self, qubit_device_2_wires): + """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" + with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): + qubit_device_2_wires.apply([qml.QubitStateVector(np.array([1, -1]), wires=[0])]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): + p = np.array([1, 0, 1, 1, 0]) / np.sqrt(3) + qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) + + with pytest.raises( + DeviceError, + match="Operation QubitStateVector cannot be used after other Operations have already been applied " + "on a default.qubit device.", + ): + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.RZ(0.5, wires=[0]), qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[0, 1])] + ) + + def test_apply_errors_basis_state(self, qubit_device_2_wires): + with pytest.raises( + ValueError, match="BasisState parameter must consist of 0 or 1 integers." + ): + qubit_device_2_wires.apply([qml.BasisState(np.array([-0.2, 4.2]), wires=[0, 1])]) + + with pytest.raises( + ValueError, match="BasisState parameter and wires must be of equal length." + ): + qubit_device_2_wires.apply([qml.BasisState(np.array([0, 1]), wires=[0])]) + + with pytest.raises( + DeviceError, + match="Operation BasisState cannot be used after other Operations have already been applied " + "on a default.qubit device.", + ): + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.RZ(0.5, wires=[0]), qml.BasisState(np.array([1, 1]), wires=[0, 1])] + ) + + +class TestExpval: + """Tests that expectation values are properly calculated or that the proper errors are raised.""" + + @pytest.mark.parametrize( + "operation,input,expected_output", + [ + (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), + (qml.PauliX, [1 / math.sqrt(2), -1 / math.sqrt(2)], -1), + (qml.PauliX, [1, 0], 0), + (qml.PauliY, [1 / math.sqrt(2), 1j / math.sqrt(2)], 1), + (qml.PauliY, [1 / math.sqrt(2), -1j / math.sqrt(2)], -1), + (qml.PauliY, [1, 0], 0), + (qml.PauliZ, [1, 0], 1), + (qml.PauliZ, [0, 1], -1), + (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), + (qml.Hadamard, [1, 0], 1 / math.sqrt(2)), + (qml.Hadamard, [0, 1], -1 / math.sqrt(2)), + (qml.Hadamard, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / math.sqrt(2)), + (qml.Identity, [1, 0], 1), + (qml.Identity, [0, 1], 1), + (qml.Identity, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1), + ], + ) + def test_expval_single_wire_no_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that expectation values are properly calculated for single-wire observables without parameters.""" + + obs = operation(wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.expval(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + (qml.Hermitian, [1, 0], 1, [[1, 1j], [-1j, 1]]), + (qml.Hermitian, [0, 1], 1, [[1, 1j], [-1j, 1]]), + (qml.Hermitian, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, [[1, 1j], [-1j, 1]]), + ], + ) + def test_expval_single_wire_with_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that expectation values are properly calculated for single-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.expval(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + ( + qml.Hermitian, + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + 5 / 3, + [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [0, 0, 0, 1], + 0, + [[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], + ), + ( + qml.Hermitian, + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + 1, + [[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [1 / math.sqrt(3), -1 / math.sqrt(3), 1 / math.sqrt(6), 1 / math.sqrt(6)], + 1, + [[1, 1j, 0, 0.5j], [-1j, 1, 0, 0], [0, 0, 1, -1j], [-0.5j, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + 1, + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ( + qml.Hermitian, + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + -1, + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ], + ) + def test_expval_two_wires_with_parameters( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that expectation values are properly calculated for two-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0, 1]) + + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() + ) + res = qubit_device_2_wires.expval(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + def test_expval_estimate(self): + """Test that the expectation value is not analytically calculated""" + + dev = qml.device("default.qubit", wires=1, shots=3) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + return qml.expval(qml.PauliX(0)) + + expval = circuit() + + # With 3 samples we are guaranteed to see a difference between + # an estimated variance an an analytically calculated one + assert expval != 0.0 + + +class TestVar: + """Tests that variances are properly calculated.""" + + @pytest.mark.parametrize( + "operation,input,expected_output", + [ + (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), + (qml.PauliX, [1 / math.sqrt(2), -1 / math.sqrt(2)], 0), + (qml.PauliX, [1, 0], 1), + (qml.PauliY, [1 / math.sqrt(2), 1j / math.sqrt(2)], 0), + (qml.PauliY, [1 / math.sqrt(2), -1j / math.sqrt(2)], 0), + (qml.PauliY, [1, 0], 1), + (qml.PauliZ, [1, 0], 0), + (qml.PauliZ, [0, 1], 0), + (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), + (qml.Hadamard, [1, 0], 1 / 2), + (qml.Hadamard, [0, 1], 1 / 2), + (qml.Hadamard, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / 2), + (qml.Identity, [1, 0], 0), + (qml.Identity, [0, 1], 0), + (qml.Identity, [1 / math.sqrt(2), -1 / math.sqrt(2)], 0), + ], + ) + def test_var_single_wire_no_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that variances are properly calculated for single-wire observables without parameters.""" + + obs = operation(wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.var(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + (qml.Hermitian, [1, 0], 1, [[1, 1j], [-1j, 1]]), + (qml.Hermitian, [0, 1], 1, [[1, 1j], [-1j, 1]]), + (qml.Hermitian, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, [[1, 1j], [-1j, 1]]), + ], + ) + def test_var_single_wire_with_parameters( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that variances are properly calculated for single-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.var(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + ( + qml.Hermitian, + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + 11 / 9, + [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [0, 0, 0, 1], + 1, + [[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], + ), + ( + qml.Hermitian, + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + 1, + [[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + 0, + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ( + qml.Hermitian, + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + 0, + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ], + ) + def test_var_two_wires_with_parameters( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that variances are properly calculated for two-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0, 1]) + + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() + ) + res = qubit_device_2_wires.var(obs) + + assert np.isclose(res, expected_output, atol=tol, rtol=0) + + def test_var_estimate(self): + """Test that the variance is not analytically calculated""" + + dev = qml.device("default.qubit", wires=1, shots=3) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + return qml.var(qml.PauliX(0)) + + var = circuit() + + # With 3 samples we are guaranteed to see a difference between + # an estimated variance and an analytically calculated one + assert var != 1.0 + + +class TestSample: + """Tests that samples are properly calculated.""" + + def test_sample_dimensions(self): + """Tests if the samples returned by the sample function have + the correct dimensions + """ + + # Explicitly resetting is necessary as the internal + # state is set to None in __init__ and only properly + # initialized during reset + dev = qml.device("default.qubit", wires=2, shots=1000) + + dev.apply([qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])]) + + dev.shots = 10 + dev._wires_measured = {0} + dev._samples = dev.generate_samples() + s1 = dev.sample(qml.PauliZ(wires=[0])) + assert np.array_equal(s1.shape, (10,)) + + dev.reset() + dev.shots = 12 + dev._wires_measured = {1} + dev._samples = dev.generate_samples() + s2 = dev.sample(qml.PauliZ(wires=[1])) + assert np.array_equal(s2.shape, (12,)) + + dev.reset() + dev.shots = 17 + dev._wires_measured = {0, 1} + dev._samples = dev.generate_samples() + s3 = dev.sample(qml.PauliX(0) @ qml.PauliZ(1)) + assert np.array_equal(s3.shape, (17,)) + + def test_sample_values(self, tol): + """Tests if the samples returned by sample have + the correct values + """ + + # Explicitly resetting is necessary as the internal + # state is set to None in __init__ and only properly + # initialized during reset + dev = qml.device("default.qubit", wires=2, shots=1000) + + dev.apply([qml.RX(1.5708, wires=[0])]) + dev._wires_measured = {0} + dev._samples = dev.generate_samples() + + s1 = dev.sample(qml.PauliZ(0)) + + # s1 should only contain 1 and -1, which is guaranteed if + # they square to 1 + assert np.allclose(s1**2, 1, atol=tol, rtol=0) + + +class TestDefaultQubitIntegration: + """Integration tests for default.qubit. This test ensures it integrates + properly with the PennyLane interface, in particular QNode.""" + + def test_defines_correct_capabilities(self): + """Test that the device defines the right capabilities""" + + dev = qml.device("default.qubit", wires=1) + cap = dev.capabilities() + capabilities = { + "model": "qubit", + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "returns_state": True, + "supports_inverse_operations": True, + "supports_analytic_computation": True, + "supports_broadcasting": True, + "passthru_devices": { + "torch": "default.qubit.torch", + "tf": "default.qubit.tf", + "autograd": "default.qubit.autograd", + "jax": "default.qubit.jax", + }, + } + assert cap == capabilities + + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + def test_qubit_circuit(self, qubit_device_1_wire, r_dtype, tol): + """Test that the default qubit plugin provides correct result for a simple circuit""" + + p = 0.543 + + dev = qubit_device_1_wire + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -np.sin(p) + + res = circuit(p) + assert np.isclose(res, expected, atol=tol, rtol=0) + assert res.dtype == r_dtype + + def test_qubit_identity(self, qubit_device_1_wire, tol): + """Test that the default qubit plugin provides correct result for the Identity expectation""" + + p = 0.543 + + @qml.qnode(qubit_device_1_wire) + def circuit(x): + """Test quantum function""" + qml.RX(x, wires=0) + return qml.expval(qml.Identity(0)) + + assert np.isclose(circuit(p), 1, atol=tol, rtol=0) + + def test_nonzero_shots(self, tol): + """Test that the default qubit plugin provides correct result for high shot number""" + + shots = 10**5 + dev = qml.device("default.qubit", wires=1, shots=shots) + + p = 0.543 + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + """Test quantum function""" + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + runs = [] + for _ in range(100): + runs.append(circuit(p)) + + assert np.isclose(np.mean(runs), -np.sin(p), atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output", + [ + ("PauliX", [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), + ("PauliX", [1 / math.sqrt(2), -1 / math.sqrt(2)], -1), + ("PauliX", [1, 0], 0), + ("PauliY", [1 / math.sqrt(2), 1j / math.sqrt(2)], 1), + ("PauliY", [1 / math.sqrt(2), -1j / math.sqrt(2)], -1), + ("PauliY", [1, 0], 0), + ("PauliZ", [1, 0], 1), + ("PauliZ", [0, 1], -1), + ("PauliZ", [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), + ("Hadamard", [1, 0], 1 / math.sqrt(2)), + ("Hadamard", [0, 1], -1 / math.sqrt(2)), + ("Hadamard", [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / math.sqrt(2)), + ], + ) + def test_supported_observable_single_wire_no_parameters( + self, qubit_device_1_wire, tol, name, state, expected_output + ): + """Tests supported observables on single wires without parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_1_wire.supports_observable(name) + + @qml.qnode(qubit_device_1_wire) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0]) + return qml.expval(obs(wires=[0])) + + assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output,par", + [ + ("Identity", [1, 0], 1, []), + ("Identity", [0, 1], 1, []), + ("Identity", [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, []), + ("Hermitian", [1, 0], 1, [np.array([[1, 1j], [-1j, 1]])]), + ("Hermitian", [0, 1], 1, [np.array([[1, 1j], [-1j, 1]])]), + ( + "Hermitian", + [1 / math.sqrt(2), -1 / math.sqrt(2)], + 1, + [np.array([[1, 1j], [-1j, 1]])], + ), + ], + ) + def test_supported_observable_single_wire_with_parameters( + self, qubit_device_1_wire, tol, name, state, expected_output, par + ): + """Tests supported observables on single wires with parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_1_wire.supports_observable(name) + + @qml.qnode(qubit_device_1_wire) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0]) + return qml.expval(obs(*par, wires=[0])) + + assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output,par", + [ + ( + "Hermitian", + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + 5 / 3, + [np.array([[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]])], + ), + ( + "Hermitian", + [0, 0, 0, 1], + 0, + [np.array([[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]])], + ), + ( + "Hermitian", + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + 1, + [np.array([[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]])], + ), + ( + "Hermitian", + [1 / math.sqrt(3), -1 / math.sqrt(3), 1 / math.sqrt(6), 1 / math.sqrt(6)], + 1, + [np.array([[1, 1j, 0, 0.5j], [-1j, 1, 0, 0], [0, 0, 1, -1j], [-0.5j, 0, 1j, 1]])], + ), + ( + "Hermitian", + [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], + 1, + [np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])], + ), + ( + "Hermitian", + [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], + -1, + [np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])], + ), + ], + ) + def test_supported_observable_two_wires_with_parameters( + self, qubit_device_2_wires, tol, name, state, expected_output, par + ): + """Tests supported observables on two wires with parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_2_wires.supports_observable(name) + + @qml.qnode(qubit_device_2_wires) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0, 1]) + return qml.expval(obs(*par, wires=[0, 1])) + + assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) + + def test_multi_samples_return_correlated_results(self): + """Tests if the samples returned by the sample function have + the correct dimensions + """ + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.Hadamard(0) + qml.CNOT(wires=[0, 1]) + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + + outcomes = circuit() + + assert np.array_equal(outcomes[0], outcomes[1]) + + @pytest.mark.parametrize("num_wires", [3, 4, 5, 6, 7, 8]) + def test_multi_samples_return_correlated_results_more_wires_than_size_of_observable( + self, num_wires + ): + """Tests if the samples returned by the sample function have + the correct dimensions + """ + + dev = qml.device("default.qubit", wires=num_wires, shots=1000) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.Hadamard(0) + qml.CNOT(wires=[0, 1]) + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + + outcomes = circuit() + + assert np.array_equal(outcomes[0], outcomes[1]) + + +# pylint: disable=unused-argument +@pytest.mark.parametrize("theta,phi,varphi", list(zip(THETA, PHI, VARPHI))) +class TestTensorExpval: + """Test tensor expectation values""" + + def test_paulix_pauliy(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_identity(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and Identity works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.cos(varphi) * np.cos(phi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.5 * ( + -6 * np.cos(theta) * (np.cos(varphi) + 1) + - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) + + 3 * np.cos(varphi) * np.sin(phi) + + np.sin(phi) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving two Hermitian matrices works correctly""" + dev = qml.device("default.qubit", wires=3) + + A1 = np.array([[1, 2], [2, 4]]) + + A2 = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.25 * ( + -30 + + 4 * np.cos(phi) * np.sin(theta) + + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) + - 3 * np.sin(phi) + - 2 + * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) + * np.sin(varphi) + + np.cos(theta) + * ( + 18 + + 5 * np.sin(phi) + + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) + + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) + ) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" + dev = qml.device("default.qubit", wires=2) + + A = np.array( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] + ) + + obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" + dev = qml.device("default.qubit", wires=3) + + A = np.array( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] + ) + Identity = np.array([[1, 0], [0, 1]]) + H = np.kron(np.kron(Identity, Identity), A) + obs = qml.Hermitian(H, wires=[2, 1, 0]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) +class TestTensorVar: + """Tests for variance of tensor observables""" + + def test_paulix_pauliy(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 + - np.cos(2 * (theta - phi)) + - np.cos(2 * (theta + phi)) + + 2 * np.cos(2 * theta) + + 2 * np.cos(2 * phi) + + 14 + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 3 + + np.cos(2 * phi) * np.cos(varphi) ** 2 + - np.cos(2 * theta) * np.sin(varphi) ** 2 + - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) + ) / 4 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3) + + A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 1057 + - np.cos(2 * phi) + + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) + - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) + + 16 * np.sin(2 * phi) + - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) + - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 + - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) + - 8 + * np.cos(theta) + * ( + 4 + * np.cos(phi) + * ( + 4 + + 8 * np.cos(varphi) + + np.cos(2 * varphi) + - (1 + 6 * np.cos(varphi)) * np.sin(varphi) + ) + + np.sin(phi) + * ( + 15 + + 8 * np.cos(varphi) + - 11 * np.cos(2 * varphi) + + 42 * np.sin(varphi) + + 3 * np.sin(2 * varphi) + ) + ) + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) +class TestTensorSample: + """Test tensor expectation values""" + + def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.probability(wires=dev.map_wires(obs.wires)) + + # s1 should only contain 1 and -1 + assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + + mean = s1 @ p + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = (s1**2) @ p - (s1 @ p).real ** 2 + expected = ( + 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 + - np.cos(2 * (theta - phi)) + - np.cos(2 * (theta + phi)) + + 2 * np.cos(2 * theta) + + 2 * np.cos(2 * phi) + + 14 + ) / 16 + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.marginal_prob(dev.probability(), wires=obs.wires) + + # s1 should only contain 1 and -1 + assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + + mean = s1 @ p + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = (s1**2) @ p - (s1 @ p).real ** 2 + expected = ( + 3 + + np.cos(2 * phi) * np.cos(varphi) ** 2 + - np.cos(2 * theta) * np.sin(varphi) ** 2 + - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) + ) / 4 + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + def test_hermitian(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + + A = 0.1 * np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.marginal_prob(dev.probability(), wires=obs.wires) + + # s1 should only contain the eigenvalues of + # the hermitian matrix tensor product Z + Z = np.diag([1, -1]) + eigvals = np.linalg.eigvalsh(np.kron(Z, A)) + assert set(np.round(s1, 8).tolist()).issubset(set(np.round(eigvals, 8).tolist())) + + mean = s1 @ p + expected = ( + 0.1 + * 0.5 + * ( + -6 * np.cos(theta) * (np.cos(varphi) + 1) + - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) + + 3 * np.cos(varphi) * np.sin(phi) + + np.sin(phi) + ) + ) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = (s1**2) @ p - (s1 @ p).real ** 2 + expected = ( + 0.01 + * ( + 1057 + - np.cos(2 * phi) + + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) + - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) + + 16 * np.sin(2 * phi) + - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) + - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 + - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) + - 8 + * np.cos(theta) + * ( + 4 + * np.cos(phi) + * ( + 4 + + 8 * np.cos(varphi) + + np.cos(2 * varphi) + - (1 + 6 * np.cos(varphi)) * np.sin(varphi) + ) + + np.sin(phi) + * ( + 15 + + 8 * np.cos(varphi) + - 11 * np.cos(2 * varphi) + + 42 * np.sin(varphi) + + 3 * np.sin(2 * varphi) + ) + ) + ) + / 16 + ) + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + +@pytest.mark.parametrize( + "r_dtype,c_dtype", [(np.float32, np.complex64), (np.float64, np.complex128)] +) +class TestDtypePreserved: + """Test that the user-defined dtype of the device is preserved for QNode + evaluation""" + + @pytest.mark.parametrize( + "op", + [ + qml.SingleExcitation, + qml.SingleExcitationPlus, + qml.SingleExcitationMinus, + qml.DoubleExcitation, + qml.DoubleExcitationPlus, + qml.DoubleExcitationMinus, + qml.OrbitalRotation, + qml.FermionicSWAP, + qml.QubitSum, + qml.QubitCarry, + ], + ) + def test_state_dtype_after_op(self, r_dtype, c_dtype, op): + """Test that the default qubit plugin preserves data types of states when an operation is + applied. As TestApply class check most of operators, we here only check some subtle + examples. + """ + + dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + + n_wires = op.num_wires + n_params = op.num_params + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + if n_params == 0: + op(wires=range(n_wires)) + elif n_params == 1: + op(0.543, wires=range(n_wires)) + else: + op([0.543] * n_params, wires=range(n_wires)) + return qml.state() + + res = circuit() + assert res.dtype == c_dtype + + @pytest.mark.parametrize( + "measurement", + [ + qml.expval(qml.PauliY(0)), + qml.var(qml.PauliY(0)), + qml.probs(wires=[1]), + qml.probs(wires=[2, 0]), + ], + ) + def test_measurement_real_dtype(self, r_dtype, c_dtype, measurement): + """Test that the default qubit plugin provides correct result for a simple circuit""" + p = 0.543 + + dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == r_dtype + + @pytest.mark.parametrize( + "measurement", + [qml.state(), qml.density_matrix(wires=[1]), qml.density_matrix(wires=[2, 0])], + ) + def test_measurement_complex_dtype(self, r_dtype, c_dtype, measurement): + """Test that the default qubit plugin provides correct result for a simple circuit""" + p = 0.543 + + dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == c_dtype + + +class TestProbabilityIntegration: + """Test probability method for when analytic is True/False""" + + # pylint: disable=unused-argument + def mock_analytic_counter(self, wires=None): + self.analytic_counter += 1 + return np.array([1, 0, 0, 0], dtype=float) + + @pytest.mark.parametrize("x", [[0.2, 0.5], [0.4, 0.9], [0.8, 0.3]]) + def test_probability(self, x, tol): + """Test that the probability function works for finite and infinite shots""" + dev = qml.device("default.qubit", wires=2, shots=1000) + dev_analytic = qml.device("default.qubit", wires=2, shots=None) + + def circuit(x): + qml.RX(x[0], wires=0) + qml.RY(x[1], wires=0) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[0, 1]) + + prob = qml.QNode(circuit, dev) + prob_analytic = qml.QNode(circuit, dev_analytic) + + assert np.isclose(prob(x).sum(), 1, atol=tol, rtol=0) + assert np.allclose(prob_analytic(x), prob(x), atol=0.1, rtol=0) + assert not np.array_equal(prob_analytic(x), prob(x)) + + # pylint: disable=attribute-defined-outside-init + def test_call_generate_samples(self, monkeypatch): + """Test analytic_probability call when generating samples""" + self.analytic_counter = False + + dev = qml.device("default.qubit", wires=2, shots=1000) + monkeypatch.setattr(dev, "analytic_probability", self.mock_analytic_counter) + + # generate samples through `generate_samples` (using 'analytic_probability') + dev.generate_samples() + + # should call `analytic_probability` once through `generate_samples` + assert self.analytic_counter == 1 + + def test_stateless_analytic_return(self): + """Test that analytic_probability returns None if device is stateless""" + dev = qml.device("default.qubit", wires=2) + dev._state = None + + assert dev.analytic_probability() is None + + +class TestWiresIntegration: + """Test that the device integrates with PennyLane's wire management.""" + + def make_circuit_probs(self, wires): + """Factory for a qnode returning probabilities using arbitrary wire labels.""" + dev = qml.device("default.qubit", wires=wires) + n_wires = len(wires) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(0.5, wires=wires[0 % n_wires]) + qml.RY(2.0, wires=wires[1 % n_wires]) + if n_wires > 1: + qml.CNOT(wires=[wires[0], wires[1]]) + return qml.probs(wires=wires) + + return circuit + + @pytest.mark.parametrize( + "wires1, wires2", + [ + (["a", "c", "d"], [2, 3, 0]), + ([-1, -2, -3], ["q1", "ancilla", 2]), + (["a", "c"], [3, 0]), + ([-1, -2], ["ancilla", 2]), + (["a"], ["nothing"]), + ], + ) + def test_wires_probs(self, wires1, wires2, tol): + """Test that the probability vector of a circuit is independent from the wire labels used.""" + + circuit1 = self.make_circuit_probs(wires1) + circuit2 = self.make_circuit_probs(wires2) + + assert np.allclose(circuit1(), circuit2(), tol) + + def test_wires_not_found_exception(self): + """Tests that an exception is raised when wires not present on the device are adressed.""" + dev = qml.device("default.qubit", wires=["a", "b"]) + + with qml.queuing.AnnotatedQueue() as q: + qml.RX(0.5, wires="c") + + tape = qml.tape.QuantumScript.from_queue(q) + with pytest.raises(WireError, match="Did not find some of the wires"): + dev.execute(tape) + + wires_to_try = [ + (1, Wires([0])), + (4, Wires([1, 3])), + (["a", 2], Wires([2])), + (["a", 2], Wires([2, "a"])), + ] + + @pytest.mark.parametrize("dev_wires, wires_to_map", wires_to_try) + def test_map_wires_caches(self, dev_wires, wires_to_map): + """Test that multiple calls to map_wires will use caching.""" + dev = qml.device("default.qubit", wires=dev_wires) + + original_hits = dev.map_wires.cache_info().hits + original_misses = dev.map_wires.cache_info().misses + + # The first call is computed: it's a miss as it didn't come from the cache + dev.map_wires(wires_to_map) + + # The number of misses increased + assert dev.map_wires.cache_info().misses > original_misses + + # The second call comes from the cache: it's a hit + dev.map_wires(wires_to_map) + + # The number of hits increased + assert dev.map_wires.cache_info().hits > original_hits + + +class TestGetSlice: + """Tests for the _get_slice function.""" + + def test_get_slice(self): + """Test that the _get_slice function returns the expected slice and allows us to slice + correctly into an array.""" + + sl = _get_slice(1, 1, 3) + array = np.arange(27).reshape((3, 3, 3)) + target = array[:, 1, :] + + assert sl == (slice(None, None, None), 1, slice(None, None, None)) + assert np.allclose(array[sl], target) + + def test_get_slice_first(self): + """Test that the _get_slice function returns the expected slice when accessing the first + axis of an array.""" + + sl = _get_slice(2, 0, 3) + array = np.arange(27).reshape((3, 3, 3)) + target = array[2] + + assert sl == (2, slice(None, None, None), slice(None, None, None)) + assert np.allclose(array[sl], target) + + def test_get_slice_last(self): + """Test that the _get_slice function returns the expected slice when accessing the last + axis of an array.""" + + sl = _get_slice(0, 2, 3) + array = np.arange(27).reshape((3, 3, 3)) + target = array[:, :, 0] + + assert sl == (slice(None, None, None), slice(None, None, None), 0) + assert np.allclose(array[sl], target) + + def test_get_slice_1d(self): + """Test that the _get_slice function returns the expected slice when accessing a + 1-dimensional array.""" + + sl = _get_slice(2, 0, 1) + array = np.arange(27) + target = array[2] + + assert sl == (2,) + assert np.allclose(array[sl], target) + + +class TestApplyOps: + """Tests for special methods listed in _apply_ops that use array manipulation tricks to apply + gates in DefaultQubit.""" + + state = np.arange(2**4, dtype=np.complex128).reshape((2, 2, 2, 2)) + dev = qml.device("default.qubit", wires=4) + + single_qubit_ops = [ + (qml.PauliX, dev._apply_x), + (qml.PauliY, dev._apply_y), + (qml.PauliZ, dev._apply_z), + (qml.Hadamard, dev._apply_hadamard), + (qml.S, dev._apply_s), + (qml.T, dev._apply_t), + (qml.SX, dev._apply_sx), + ] + two_qubit_ops = [ + (qml.CNOT, dev._apply_cnot), + (qml.SWAP, dev._apply_swap), + (qml.CZ, dev._apply_cz), + ] + three_qubit_ops = [ + (qml.Toffoli, dev._apply_toffoli), + ] + + @pytest.mark.parametrize("op, method", single_qubit_ops) + def test_apply_single_qubit_op(self, op, method): + """Test if the application of single qubit operations is correct.""" + state_out = method(self.state, axes=[1]) + op = op(wires=[1]) + matrix = op.matrix() + state_out_einsum = np.einsum("ab,ibjk->iajk", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", two_qubit_ops) + def test_apply_two_qubit_op(self, op, method): + """Test if the application of two qubit operations is correct.""" + state_out = method(self.state, axes=[0, 1]) + op = op(wires=[0, 1]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2, 2, 2)) + state_out_einsum = np.einsum("abcd,cdjk->abjk", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", two_qubit_ops) + def test_apply_two_qubit_op_reverse(self, op, method): + """Test if the application of two qubit operations is correct when the applied wires are + reversed.""" + state_out = method(self.state, axes=[2, 1]) + op = op(wires=[2, 1]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2, 2, 2)) + state_out_einsum = np.einsum("abcd,idck->ibak", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_smaller(self, op, method): + """Test if the application of three qubit operations is correct when both control wires are + smaller than the target wire.""" + state_out = method(self.state, axes=[0, 2, 3]) + op = op(wires=[0, 2, 3]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,dkef->akbc", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_greater(self, op, method): + """Test if the application of three qubit operations is correct when both control wires are + greater than the target wire.""" + state_out = method(self.state, axes=[2, 1, 0]) + op = op(wires=[2, 1, 0]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,fedk->cbak", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_split(self, op, method): + """Test if the application of three qubit operations is correct when one control wire is smaller + and one control wire is greater than the target wire.""" + state_out = method(self.state, axes=[3, 1, 2]) + op = op(wires=[3, 1, 2]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,kdfe->kacb", matrix, self.state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.jax + def test_apply_parametrized_evolution_raises_error(self): + """Test that applying a ParametrizedEvolution raises an error.""" + param_ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX(0)])) + with pytest.raises( + NotImplementedError, + match="The device default.qubit cannot execute a ParametrizedEvolution operation", + ): + self.dev._apply_parametrized_evolution(state=self.state, operation=param_ev) + + @qml.qnode(self.dev) + def circuit(): + qml.apply(param_ev) + return qml.expval(qml.PauliZ(0)) + + with pytest.raises( + DeviceError, + match="Gate ParametrizedEvolution not supported on device default.qubit.autograd", + ): + circuit() + + self.dev.operations.add("ParametrizedEvolution") + with pytest.raises( + NotImplementedError, + match="The device default.qubit.autograd cannot execute a ParametrizedEvolution operation", + ): + circuit() + + +class TestStateVector: + """Unit tests for the _apply_state_vector method""" + + def test_full_subsystem(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubit(wires=["a", "b", "c"]) + state = np.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(dev._state.flatten() == state) + spy.assert_not_called() + + def test_partial_subsystem(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubit(wires=["a", "b", "c"]) + state = np.array([1, 0, 1, 0]) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = np.sum(dev._state, axis=(1,)).flatten() + + assert np.all(res == state) + spy.assert_called() + + +class TestApplyOperationUnit: + """Unit tests for the internal _apply_operation method.""" + + def test_internal_apply_ops_case(self, monkeypatch): + """Tests that if we provide an operation that has an internal + implementation, then we use that specific implementation. + + This test provides a new internal function that `default.qubit` uses to + apply `PauliX` (rather than redefining the gate itself). + """ + dev = qml.device("default.qubit", wires=1) + + # Create a dummy operation + expected_test_output = np.ones(1) + supported_gate_application = lambda *args, **kwargs: expected_test_output + + with monkeypatch.context() as m: + # Set the internal ops implementations dict + m.setattr(dev, "_apply_ops", {"PauliX": supported_gate_application}) + + test_state = np.array([1, 0]) + op = qml.PauliX(0) + + res = dev._apply_operation(test_state, op) + assert np.allclose(res, expected_test_output) + + def test_diagonal_operation_case(self, monkeypatch): + """Tests the case when the operation to be applied is + diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" + dev = qml.device("default.qubit", wires=1) + par = 0.3 + + test_state = np.array([1, 0]) + wires = 0 + op = qml.PhaseShift(par, wires=wires) + assert op.name not in dev._apply_ops + + # Set the internal _apply_diagonal_unitary + history = [] + mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) + with monkeypatch.context() as m: + m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) + assert dev._apply_diagonal_unitary == mock_apply_diag + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, np.diag(op.matrix())) + assert np.allclose(res_wires, wires) + + def test_apply_einsum_case(self, monkeypatch): + """Tests the case when np.einsum is used to apply an operation in + default.qubit.""" + dev = qml.device("default.qubit", wires=1) + + test_state = np.array([1, 0]) + wires = 0 + + # Redefine the S gate so that it is an example for a one-qubit gate + # that is not registered in the diagonal_in_z_basis attribute + class TestSGate(qml.operation.Operation): + num_wires = 1 + + # pylint: disable=unused-argument + @staticmethod + def compute_matrix(*params, **hyperparams): + return np.array([[1, 0], [0, 1j]]) + + dev.operations.add("TestSGate") + op = TestSGate(wires=wires) + + assert op.name in dev.operations + assert op.name not in dev._apply_ops + + # Set the internal _apply_unitary_einsum + history = [] + mock_apply_einsum = lambda state, matrix, wires: history.append((state, matrix, wires)) + with monkeypatch.context() as m: + m.setattr(dev, "_apply_unitary_einsum", mock_apply_einsum) + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, op.matrix()) + assert np.allclose(res_wires, wires) + + def test_apply_tensordot_case(self, monkeypatch): + """Tests the case when np.tensordot is used to apply an operation in + default.qubit.""" + dev = qml.device("default.qubit", wires=3) + + test_state = np.array([1, 0]) + wires = [0, 1, 2] + + # Redefine the Toffoli gate so that it is an example for a gate with + # more than two wires + class TestToffoli(qml.operation.Operation): + num_wires = 3 + + # pylint: disable=unused-argument + @staticmethod + def compute_matrix(*params, **hyperparams): + return U_toffoli + + dev.operations.add("TestToffoli") + op = TestToffoli(wires=wires) + + assert op.name in dev.operations + assert op.name not in dev._apply_ops + + # Set the internal _apply_unitary_tensordot + history = [] + mock_apply_tensordot = lambda state, matrix, wires: history.append((state, matrix, wires)) + + with monkeypatch.context() as m: + m.setattr(dev, "_apply_unitary", mock_apply_tensordot) + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, op.matrix()) + assert np.allclose(res_wires, wires) + + def test_apply_unitary_tensordot_double_broadcasting_error(self): + """Tests that an error is raised if attempting to use _apply_unitary + with a broadcasted matrix and a broadcasted state simultaneously.""" + dev = qml.device("default.qubit", wires=3) + + class BroadcastedToffoli(qml.operation.Operation): + num_wires = 3 + batch_size = 3 + num_params = 0 + + # pylint: disable=unused-argument + @staticmethod + def compute_matrix(*params, **hyperparams): + return np.array([U_toffoli] * 3) + + state = np.eye(8)[:3] + wires = qml.wires.Wires([0, 1, 2]) + + mat = BroadcastedToffoli(wires=wires).matrix() + with pytest.raises(NotImplementedError, match="broadcasted unitary to an already"): + dev._apply_unitary(state, mat, wires=wires) + + def test_identity_skipped(self, mocker): + """Test that applying the identity operation does not perform any additional computations.""" + dev = qml.device("default.qubit", wires=1) + + starting_state = np.array([1, 0]) + op = qml.Identity(0) + + spy_diagonal = mocker.spy(dev, "_apply_diagonal_unitary") + spy_einsum = mocker.spy(dev, "_apply_unitary_einsum") + spy_unitary = mocker.spy(dev, "_apply_unitary") + + res = dev._apply_operation(starting_state, op) + assert res is starting_state + + spy_diagonal.assert_not_called() + spy_einsum.assert_not_called() + spy_unitary.assert_not_called() + + +class TestHamiltonianSupport: + """Tests the devices' native support for Hamiltonian observables.""" + + def test_do_not_split_analytic(self, mocker): + """Tests that the Hamiltonian is not split for shots=None.""" + dev = qml.device("default.qubit", wires=2) + H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="parameter-shift", interface=None) + def circuit(): + return qml.expval(H) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_split_finite_shots(self, mocker): + """Tests that the Hamiltonian is split for finite shots.""" + dev = qml.device("default.qubit", wires=2, shots=10) + spy = mocker.spy(dev, "expval") + + H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev) + def circuit(): + return qml.expval(H) + + circuit() + + # evaluated one expval per Pauli observable + assert spy.call_count == 2 + + def test_error_hamiltonian_expval_finite_shots(self): + """Tests that the Hamiltonian is split for finite shots.""" + dev = qml.device("default.qubit", wires=2, shots=10) + H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) + + with pytest.raises(AssertionError, match="Hamiltonian must be used with shots=None"): + dev.expval(H) + + def test_error_hamiltonian_expval_wrong_wires(self): + """Tests that expval fails if Hamiltonian uses non-device wires.""" + dev = qml.device("default.qubit", wires=2, shots=None) + H = qml.Hamiltonian([0.1, 0.2, 0.3], [qml.PauliX(0), qml.PauliZ(1), qml.PauliY(2)]) + + with pytest.raises( + WireError, + match=r"Did not find some of the wires \(0, 1, 2\) on device with wires \(0, 1\).", + ): + dev.expval(H) + + def test_Hamiltonian_filtered_from_rotations(self, mocker): + """Tests that the device does not attempt to get rotations for Hamiltonians.""" + dev = qml.device("default.qubit", wires=2, shots=10) + H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) + + spy = mocker.spy(qml.QubitDevice, "_get_diagonalizing_gates") + qs = qml.tape.QuantumScript([qml.RX(1, 0)], [qml.expval(qml.PauliX(0)), qml.expval(H)]) + rotations = dev._get_diagonalizing_gates(qs) + + assert len(rotations) == 1 + assert qml.equal(rotations[0], qml.Hadamard(0)) + + call_args = spy.call_args.args[1] # 0 is self (the device) + assert isinstance(call_args, qml.tape.QuantumScript) + assert len(call_args.operations) == 0 + assert len(call_args.measurements) == 1 + assert qml.equal(call_args.measurements[0], qml.expval(qml.PauliX(0))) + + +@pytest.mark.parametrize("is_state_batched", [False, True]) +class TestSumSupport: + """Tests for custom Sum support in DefaultQubit.""" + + @staticmethod + def expected_grad(is_state_batched): + if is_state_batched: + return [[-np.sin(1.3), -np.sin(0.4)], [np.cos(1.3), np.cos(0.4)]] + return [-np.sin(1.3), np.cos(1.3)] + + @staticmethod + def circuit(y, z, is_state_batched): + rx_param = [1.3, 0.4] if is_state_batched else 1.3 + qml.RX(rx_param, 0) + return qml.expval( + qml.sum( + qml.s_prod(y, qml.PauliY(0)), + qml.s_prod(z, qml.PauliZ(0)), + ) + ) + + def test_super_expval_not_called(self, is_state_batched, mocker): + """Tests basic expval result, and ensures QubitDevice.expval is not called.""" + dev = qml.device("default.qubit", wires=1) + spy = mocker.spy(qml.QubitDevice, "expval") + obs = qml.sum(qml.s_prod(0.1, qml.PauliX(0)), qml.s_prod(0.2, qml.PauliZ(0))) + assert np.isclose(dev.expval(obs), 0.2) + spy.assert_not_called() + + @pytest.mark.autograd + def test_trainable_autograd(self, is_state_batched): + """Tests that coeffs passed to a sum are trainable with autograd.""" + if is_state_batched: + pytest.skip(msg="Broadcasting, qml.jacobian and new return types do not work together") + dev = qml.device("default.qubit", wires=1) + qnode = qml.QNode(self.circuit, dev, interface="autograd") + y, z = np.array([1.1, 2.2]) + actual = qml.grad(qnode, argnum=[0, 1])(y, z, is_state_batched) + assert np.allclose(actual, self.expected_grad(is_state_batched)) + + @pytest.mark.torch + def test_trainable_torch(self, is_state_batched): + """Tests that coeffs passed to a sum are trainable with torch.""" + import torch + + dev = qml.device("default.qubit", wires=1) + qnode = qml.QNode(self.circuit, dev, interface="torch") + y, z = torch.tensor(1.1, requires_grad=True), torch.tensor(2.2, requires_grad=True) + _qnode = partial(qnode, is_state_batched=is_state_batched) + actual = torch.stack(torch.autograd.functional.jacobian(_qnode, (y, z))) + assert np.allclose(actual, self.expected_grad(is_state_batched)) + + @pytest.mark.tf + def test_trainable_tf(self, is_state_batched): + """Tests that coeffs passed to a sum are trainable with tf.""" + import tensorflow as tf + + dev = qml.device("default.qubit", wires=1) + qnode = qml.QNode(self.circuit, dev, interface="tensorflow") + y, z = tf.Variable(1.1, dtype=tf.float64), tf.Variable(2.2, dtype=tf.float64) + with tf.GradientTape() as tape: + res = qnode(y, z, is_state_batched) + actual = tape.jacobian(res, [y, z]) + assert np.allclose(actual, self.expected_grad(is_state_batched)) + + @pytest.mark.jax + def test_trainable_jax(self, is_state_batched): + """Tests that coeffs passed to a sum are trainable with jax.""" + import jax + + dev = qml.device("default.qubit", wires=1) + qnode = qml.QNode(self.circuit, dev, interface="jax") + y, z = jax.numpy.array([1.1, 2.2]) + actual = jax.jacobian(qnode, argnums=[0, 1])(y, z, is_state_batched) + assert np.allclose(actual, self.expected_grad(is_state_batched)) + + +class TestGetBatchSize: + """Tests for the helper method ``_get_batch_size`` of ``QubitDevice``.""" + + @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) + def test_batch_size_None(self, shape): + """Test that a ``batch_size=None`` is reported correctly.""" + dev = qml.device("default.qubit", wires=1) + tensor0 = np.ones(shape, dtype=complex) + assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None + tensor1 = np.arange(np.prod(shape)).reshape(shape) + assert dev._get_batch_size(tensor1, shape, qml.math.prod(shape)) is None + + @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) + @pytest.mark.parametrize("batch_size", [1, 3]) + def test_batch_size_int(self, shape, batch_size): + """Test that an integral ``batch_size`` is reported correctly.""" + dev = qml.device("default.qubit", wires=1) + full_shape = (batch_size,) + shape + tensor0 = np.ones(full_shape, dtype=complex) + assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size + tensor1 = np.arange(np.prod(full_shape)).reshape(full_shape) + assert dev._get_batch_size(tensor1, shape, qml.math.prod(shape)) == batch_size + + @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested") + def test_invalid_tensor(self): + """Test that an error is raised if a tensor is provided that does not + have a proper shape/ndim.""" + dev = qml.device("default.qubit", wires=1) + with pytest.raises(ValueError, match="could not broadcast"): + dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) + + +class TestDenseMatrixDecompositionThreshold: + """Tests for QFT and Grover operators the automatic transition from dense matrix to decomposition + on calculations.""" + + input = [ + (qml.QFT, 4, True), + (qml.QFT, 6, False), + (qml.GroverOperator, 4, True), + (qml.GroverOperator, 13, False), + ] + + @pytest.mark.parametrize("op, n_wires, condition", input) + def test_threshold(self, op, n_wires, condition): + wires = np.linspace(0, n_wires - 1, n_wires, dtype=int) + op = op(wires=wires) + assert DefaultQubit.stopping_condition.__get__(op)(op) == condition diff --git a/tests/devices/default_qubit_1/test_default_qubit_autograd.py b/tests/devices/default_qubit_1/test_default_qubit_autograd.py new file mode 100644 index 00000000000..d1e01f99cc3 --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit_autograd.py @@ -0,0 +1,802 @@ +# Copyright 2018-2020 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. +""" +Integration tests for the ``default.qubit.autograd`` device. +""" +import pytest + +import pennylane as qml +from pennylane import numpy as np +from pennylane.devices.default_qubit_autograd import DefaultQubitAutograd +from pennylane import DeviceError + + +@pytest.mark.autograd +def test_analytic_deprecation(): + """Tests if the kwarg `analytic` is used and displays error message.""" + msg = "The analytic argument has been replaced by shots=None. " + msg += "Please use shots=None instead of analytic=True." + + with pytest.raises( + DeviceError, + match=msg, + ): + qml.device("default.qubit.autograd", wires=1, shots=1, analytic=True) + + +@pytest.mark.autograd +class TestQNodeIntegration: + """Integration tests for default.qubit.autograd. This test ensures it integrates + properly with the PennyLane UI, in particular the new QNode.""" + + def test_defines_correct_capabilities(self): + """Test that the device defines the right capabilities""" + + dev = qml.device("default.qubit.autograd", wires=1) + cap = dev.capabilities() + capabilities = { + "model": "qubit", + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "returns_state": True, + "supports_inverse_operations": True, + "supports_analytic_computation": True, + "passthru_interface": "autograd", + "supports_broadcasting": True, + "passthru_devices": { + "torch": "default.qubit.torch", + "tf": "default.qubit.tf", + "autograd": "default.qubit.autograd", + "jax": "default.qubit.jax", + }, + } + assert cap == capabilities + + def test_load_device(self): + """Test that the plugin device loads correctly""" + dev = qml.device("default.qubit.autograd", wires=2) + assert dev.num_wires == 2 + assert dev.shots is None + assert dev.short_name == "default.qubit.autograd" + assert dev.capabilities()["passthru_interface"] == "autograd" + + def test_qubit_circuit(self, tol): + """Test that the device provides the correct + result for a simple circuit.""" + p = np.array(0.543) + + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -np.sin(p) + + assert circuit.gradient_fn == "backprop" + assert np.isclose(circuit(p), expected, atol=tol, rtol=0) + + def test_qubit_circuit_broadcasted(self, tol): + """Test that the device provides the correct + result for a simple broadcasted circuit.""" + p = np.array([0.543, 0.21, 1.5]) + + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -np.sin(p) + + assert circuit.gradient_fn == "backprop" + assert np.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_correct_state(self, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + + dev = qml.device("default.qubit.autograd", wires=2) + + state = dev.state + expected = np.array([1, 0, 0, 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(np.pi / 4, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + amplitude = np.exp(-1j * np.pi / 8) / np.sqrt(2) + + expected = np.array([amplitude, 0, np.conj(amplitude), 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_broadcasted(self, tol): + """Test that the device state is correct after applying a + broadcasted quantum function on the device""" + + dev = qml.device("default.qubit.autograd", wires=2) + + state = dev.state + expected = np.array([1, 0, 0, 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(np.array([np.pi / 4, np.pi / 2]), wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + phase = np.exp(-1j * np.pi / 8) + + expected = np.array( + [ + [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], + [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], + ] + ) + assert np.allclose(state, expected, atol=tol, rtol=0) + + +@pytest.mark.autograd +class TestDtypePreserved: + """Test that the user-defined dtype of the device is preserved for QNode + evaluation""" + + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + @pytest.mark.parametrize( + "measurement", + [ + qml.expval(qml.PauliY(0)), + qml.var(qml.PauliY(0)), + qml.probs(wires=[1]), + qml.probs(wires=[2, 0]), + ], + ) + def test_real_dtype(self, r_dtype, measurement): + """Test that the default qubit plugin returns the correct + real data type for a simple circuit""" + p = 0.543 + + dev = qml.device("default.qubit.autograd", wires=3) + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="backprop") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == r_dtype + + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + @pytest.mark.parametrize( + "measurement", + [ + qml.expval(qml.PauliY(0)), + qml.var(qml.PauliY(0)), + qml.probs(wires=[1]), + qml.probs(wires=[2, 0]), + ], + ) + def test_real_dtype_broadcasted(self, r_dtype, measurement): + """Test that the default qubit plugin returns the correct + real data type for a simple broadcasted circuit""" + p = np.array([0.543, 0.21, 1.6]) + + dev = qml.device("default.qubit.autograd", wires=3) + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="backprop") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == r_dtype + + @pytest.mark.parametrize("c_dtype", [np.complex64, np.complex128]) + @pytest.mark.parametrize( + "measurement", + [qml.state(), qml.density_matrix(wires=[1]), qml.density_matrix(wires=[2, 0])], + ) + def test_complex_dtype(self, c_dtype, measurement): + """Test that the default qubit plugin returns the correct + complex data type for a simple circuit""" + p = 0.543 + + dev = qml.device("default.qubit.autograd", wires=3) + dev.C_DTYPE = c_dtype + + @qml.qnode(dev, diff_method="backprop") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == c_dtype + + @pytest.mark.parametrize("c_dtype", [np.complex64, np.complex128]) + def test_complex_dtype_broadcasted(self, c_dtype): + """Test that the default qubit plugin returns the correct + complex data type for a simple broadcasted circuit""" + p = np.array([0.543, 0.21, 1.6]) + + dev = qml.device("default.qubit.autograd", wires=3) + dev.C_DTYPE = c_dtype + + measurement = qml.state() + + @qml.qnode(dev, diff_method="backprop") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == c_dtype + + +@pytest.mark.autograd +class TestPassthruIntegration: + """Tests for integration with the PassthruQNode""" + + def test_jacobian_variable_multiply(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.autograd device + gives the correct result in the case of parameters multiplied by scalars""" + x = 0.43316321 + y = 0.2162158 + z = 0.75110998 + weights = np.array([x, y, z], requires_grad=True) + + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + assert circuit.gradient_fn == "backprop" + res = circuit(weights) + + expected = np.cos(3 * x) * np.cos(y) * np.cos(z / 2) - np.sin(3 * x) * np.sin(z / 2) + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = qml.jacobian(circuit, 0) + res = grad_fn(np.array(weights)) + + expected = np.array( + [ + -3 * (np.sin(3 * x) * np.cos(y) * np.cos(z / 2) + np.cos(3 * x) * np.sin(z / 2)), + -np.cos(3 * x) * np.sin(y) * np.cos(z / 2), + -0.5 * (np.sin(3 * x) * np.cos(z / 2) + np.cos(3 * x) * np.cos(y) * np.sin(z / 2)), + ] + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_variable_multiply_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.autograd device + gives the correct result in the case of broadcasted parameters multiplied by scalars""" + x = np.array([0.43316321, 92.1, -0.5129]) + y = np.array([0.2162158, 0.241, -0.51]) + z = np.array([0.75110998, 0.12512, 9.12]) + weights = np.array([x, y, z], requires_grad=True) + + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + assert circuit.gradient_fn == "backprop" + res = circuit(weights) + + expected = np.cos(3 * x) * np.cos(y) * np.cos(z / 2) - np.sin(3 * x) * np.sin(z / 2) + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = qml.jacobian(circuit, 0) + res = grad_fn(np.array(weights)) + + expected = np.array( + [ + -3 * (np.sin(3 * x) * np.cos(y) * np.cos(z / 2) + np.cos(3 * x) * np.sin(z / 2)), + -np.cos(3 * x) * np.sin(y) * np.cos(z / 2), + -0.5 * (np.sin(3 * x) * np.cos(z / 2) + np.cos(3 * x) * np.cos(y) * np.sin(z / 2)), + ] + ) + + assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + def test_jacobian_repeated(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.autograd device + gives the correct result in the case of repeated parameters""" + x = 0.43316321 + y = 0.2162158 + z = 0.75110998 + p = np.array([x, y, z], requires_grad=True) + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + + expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = qml.jacobian(circuit, 0) + res = grad_fn(p) + + expected = np.array( + [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0] + ) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_repeated_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.autograd device + gives the correct result in the case of repeated broadcasted parameters""" + x = np.array([0.43316321, 92.1, -0.5129]) + y = np.array([0.2162158, 0.241, -0.51]) + z = np.array([0.75110998, 0.12512, 9.12]) + p = np.array([x, y, z], requires_grad=True) + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + + expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = qml.jacobian(circuit, 0) + res = grad_fn(p) + + expected = np.array( + [ + -np.cos(x) * np.sin(y) ** 2, + -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), + np.zeros_like(x), + ] + ) + assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + def test_jacobian_agrees_backprop_parameter_shift(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.autograd device + gives the correct result with respect to the parameter-shift method""" + p = np.array([0.43316321, 0.2162158, 0.75110998, 0.94714242], requires_grad=True) + + def circuit(x): + for i in range(0, len(p), 2): + qml.RX(x[i], wires=0) + qml.RY(x[i + 1], wires=1) + for i in range(2): + qml.CNOT(wires=[i, i + 1]) + return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) + + dev1 = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=3) + + def cost(x): + return qml.math.stack(circuit(x)) + + circuit1 = qml.QNode(cost, dev1, diff_method="backprop", interface="autograd") + circuit2 = qml.QNode(cost, dev2, diff_method="parameter-shift") + + res = circuit1(p) + + assert np.allclose(res, circuit2(p), atol=tol, rtol=0) + + assert circuit1.gradient_fn == "backprop" + assert circuit2.gradient_fn is qml.gradients.param_shift + + grad_fn = qml.jacobian(circuit1, 0) + res = grad_fn(p) + assert np.allclose(res, qml.jacobian(circuit2)(p), atol=tol, rtol=0) + + @pytest.mark.parametrize("wires", [[0], ["abc"]]) + def test_state_differentiability(self, wires, tol): + """Test that the device state can be differentiated""" + dev = qml.device("default.qubit.autograd", wires=wires) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a): + qml.RY(a, wires=wires[0]) + return qml.state() + + a = np.array(0.54, requires_grad=True) + + def cost(a): + """A function of the device quantum state, as a function + of input QNode parameters.""" + res = np.abs(circuit(a)) ** 2 + return res[1] - res[0] + + grad = qml.grad(cost)(a) + expected = np.sin(a) + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_state_differentiability_broadcasted(self, tol): + """Test that the broadcasted device state can be differentiated""" + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a): + qml.RY(a, wires=0) + return qml.expval(qml.PauliZ(0)) + + a = np.array([0.54, 0.32, 1.2], requires_grad=True) + + def cost(a): + """A function of the device quantum state, as a function + of input QNode parameters.""" + circuit(a) + res = np.abs(dev.state) ** 2 + return res[:, 1] - res[:, 0] + + grad = qml.jacobian(cost)(a) + expected = np.diag(np.sin(a)) + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_prob_differentiability(self, tol): + """Test that the device probability can be differentiated""" + dev = qml.device("default.qubit.autograd", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = np.array(0.54, requires_grad=True) + b = np.array(0.12, requires_grad=True) + + def cost(a, b): + prob_wire_1 = circuit(a, b) + return prob_wire_1[1] - prob_wire_1[0] # pylint:disable=unsubscriptable-object + + res = cost(a, b) + expected = -np.cos(a) * np.cos(b) + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad = qml.grad(cost)(a, b) + expected = [np.sin(a) * np.cos(b), np.cos(a) * np.sin(b)] + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_prob_differentiability_broadcasted(self, tol): + """Test that the broadcasted device probability can be differentiated""" + dev = qml.device("default.qubit.autograd", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = np.array([0.54, 0.32, 1.2], requires_grad=True) + b = np.array(0.12, requires_grad=True) + + def cost(a, b): + prob_wire_1 = circuit(a, b) + return prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object + + res = cost(a, b) + expected = -np.cos(a) * np.cos(b) + assert np.allclose(res, expected, atol=tol, rtol=0) + + jac = qml.jacobian(cost)(a, b) + expected = np.array([np.sin(a) * np.cos(b), np.cos(a) * np.sin(b)]) + expected = (np.diag(expected[0]), expected[1]) # Only first parameter is broadcasted + assert all(np.allclose(j, e, atol=tol, rtol=0) for j, e in zip(jac, expected)) + + def test_backprop_gradient(self, tol): + """Tests that the gradient of the qnode is correct""" + dev = qml.device("default.qubit.autograd", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = np.array(-0.234, requires_grad=True) + b = np.array(0.654, requires_grad=True) + + res = circuit(a, b) + expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) + assert np.allclose(res, expected_cost, atol=tol, rtol=0) + + res = qml.grad(circuit)(a, b) + expected_grad = np.array( + [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] + ) + assert np.allclose(res, expected_grad, atol=tol, rtol=0) + + def test_backprop_gradient_broadcasted(self, tol): + """Tests that the gradient of the broadcasted qnode is correct""" + dev = qml.device("default.qubit.autograd", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = np.array(0.12, requires_grad=True) + b = np.array([0.54, 0.32, 1.2], requires_grad=True) + + res = circuit(a, b) + expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) + assert np.allclose(res, expected_cost, atol=tol, rtol=0) + + res = qml.jacobian(circuit)(a, b) + expected = np.array([-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))]) + expected = (expected[0], np.diag(expected[1])) + assert all(np.allclose(r, e, atol=tol, rtol=0) for r, e in zip(res, expected)) + + @pytest.mark.parametrize( + "x, shift", + [np.array((0.0, 0.0), requires_grad=True), np.array((0.5, -0.5), requires_grad=True)], + ) + def test_hessian_at_zero(self, x, shift): + """Tests that the Hessian at vanishing state vector amplitudes + is correct.""" + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def circuit(x): + qml.RY(shift, wires=0) + qml.RY(x, wires=0) + return qml.expval(qml.PauliZ(0)) + + assert qml.math.isclose(qml.jacobian(circuit)(x), 0.0) + assert qml.math.isclose(qml.jacobian(qml.jacobian(circuit))(x), -1.0) + assert qml.math.isclose(qml.grad(qml.grad(circuit))(x), -1.0) + + @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) + @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) + def test_autograd_interface_gradient(self, operation, diff_method, tol): + """Tests that the gradient of an arbitrary U3 gate is correct + using the Autograd interface, using a variety of differentiation methods.""" + dev = qml.device("default.qubit.autograd", wires=1) + state = np.array(1j * np.array([1, -1]) / np.sqrt(2), requires_grad=False) + + @qml.qnode(dev, diff_method=diff_method, interface="autograd") + def circuit(x, weights, w): + """In this example, a mixture of scalar + arguments, array arguments, and keyword arguments are used.""" + qml.QubitStateVector(state, wires=w) + operation(x, weights[0], weights[1], wires=w) + return qml.expval(qml.PauliX(w)) + + def cost(params): + """Perform some classical processing""" + return circuit(params[0], params[1:], w=0) ** 2 + + theta = 0.543 + phi = -0.234 + lam = 0.654 + + params = np.array([theta, phi, lam], requires_grad=True) + + res = cost(params) + expected_cost = (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) ** 2 + assert np.allclose(res, expected_cost, atol=tol, rtol=0) + + # Check that the correct differentiation method is being used. + if diff_method == "backprop": + assert circuit.gradient_fn == "backprop" + elif diff_method == "parameter-shift": + assert circuit.gradient_fn is qml.gradients.param_shift + else: + assert circuit.gradient_fn is qml.gradients.finite_diff + + res = qml.grad(cost)(params) + expected_grad = ( + np.array( + [ + np.sin(theta) * np.cos(lam) * np.cos(phi), + np.cos(theta) * np.cos(lam) * np.sin(phi) + np.sin(lam) * np.cos(phi), + np.cos(theta) * np.sin(lam) * np.cos(phi) + np.cos(lam) * np.sin(phi), + ] + ) + * 2 + * (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) + ) + assert np.allclose(res, expected_grad, atol=tol, rtol=0) + + @pytest.mark.parametrize("interface", ["tf", "torch"]) + def test_error_backprop_wrong_interface(self, interface): + """Tests that an error is raised if diff_method='backprop' but not using + the Autograd interface""" + dev = qml.device("default.qubit.autograd", wires=1) + + def circuit(x, w=None): + qml.RZ(x, wires=w) + return qml.expval(qml.PauliX(w)) + + with pytest.raises( + qml.QuantumFunctionError, + match="default.qubit.autograd only supports diff_method='backprop' when using the autograd interface", + ): + qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) + + +@pytest.mark.autograd +class TestHighLevelIntegration: + """Tests for integration with higher level components of PennyLane.""" + + def test_do_not_split_analytic_autograd(self, mocker): + """Tests that the Hamiltonian is not split for shots=None using the autograd device.""" + dev = qml.device("default.qubit.autograd", wires=2) + H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(): + return qml.expval(H) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_do_not_split_analytic_autograd_broadcasted(self, mocker): + """Tests that the Hamiltonian is not split for shots=None + and broadcasting using the autograd device.""" + dev = qml.device("default.qubit.autograd", wires=2) + H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="autograd") + def circuit(): + qml.RX(np.zeros(5), 0) + return qml.expval(H) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_template_integration(self): + """Test that a PassthruQNode default.qubit.autograd works with templates.""" + dev = qml.device("default.qubit.autograd", wires=2) + + @qml.qnode(dev, diff_method="backprop") + def circuit(weights): + qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=2) + weights = np.random.random(shape, requires_grad=True) + + grad = qml.grad(circuit)(weights) + assert grad.shape == weights.shape + + +# pylint: disable=protected-access +@pytest.mark.autograd +class TestOps: + """Unit tests for operations supported by the default.qubit.autograd device""" + + def test_multirz_jacobian(self): + """Test that the patched numpy functions are used for the MultiRZ + operation and the jacobian can be computed.""" + wires = 4 + dev = qml.device("default.qubit.autograd", wires=wires) + + @qml.qnode(dev, diff_method="backprop") + def circuit(param): + qml.MultiRZ(param, wires=[0, 1]) + return qml.probs(wires=list(range(wires))) + + param = np.array(0.3, requires_grad=True) + res = qml.jacobian(circuit)(param) + assert np.allclose(res, np.zeros(wires**2)) + + def test_full_subsystem(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubitAutograd(wires=["a", "b", "c"]) + state = np.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(dev._state.flatten() == state) + spy.assert_not_called() + + def test_partial_subsystem(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubitAutograd(wires=["a", "b", "c"]) + state = np.array([1, 0, 1, 0]) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = np.sum(dev._state, axis=(1,)).flatten() + + assert np.all(res == state) + spy.assert_called() + + +@pytest.mark.autograd +class TestOpsBroadcasted: + """Unit tests for broadcasted operations supported by the default.qubit.autograd device""" + + def test_multirz_jacobian_broadcasted(self): + """Test that the patched numpy functions are used for the MultiRZ + operation and the jacobian can be computed.""" + wires = 4 + dev = qml.device("default.qubit.autograd", wires=wires) + + @qml.qnode(dev, diff_method="backprop") + def circuit(param): + qml.MultiRZ(param, wires=[0, 1]) + return qml.probs(wires=list(range(wires))) + + param = np.array([0.3, 0.9, -4.3], requires_grad=True) + res = qml.jacobian(circuit)(param) + assert np.allclose(res, np.zeros((3, wires**2, 3))) + + def test_full_subsystem_broadcasted(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubitAutograd(wires=["a", "b", "c"]) + state = np.array([[1, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 1, 1, 1, 0]]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(dev._state.reshape((2, 8)) == state) + spy.assert_not_called() + + def test_partial_subsystem_broadcasted(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubitAutograd(wires=["a", "b", "c"]) + state = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [1, 1, 0, 0]]) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = np.sum(dev._state, axis=(2,)).reshape((3, 4)) + + assert np.allclose(res, state) + spy.assert_called() diff --git a/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py b/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py new file mode 100644 index 00000000000..4fb4bd2a84a --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py @@ -0,0 +1,2023 @@ +# Copyright 2018-2020 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 :mod:`pennylane.plugin.DefaultQubit` device when using broadcasting. +""" +from itertools import product + +# pylint: disable=protected-access,cell-var-from-loop,too-many-arguments +import math + +import pytest +from gate_data import ( + X, + Y, + Z, + S, + T, + H, + CNOT, + SWAP, + CZ, + ISWAP, + SISWAP, + CSWAP, + Rphi, + Rotx, + Roty, + Rotz, + MultiRZ1, + Rot3, + CRotx, + CRoty, + CRotz, + MultiRZ2, + IsingXX, + IsingYY, + IsingZZ, + CRot3, + I, + Toffoli, +) + +import pennylane as qml +from pennylane import numpy as np, DeviceError +from pennylane.devices.default_qubit import DefaultQubit + +THETA = np.linspace(0.11, 1, 3) +PHI = np.linspace(0.32, 1, 3) +VARPHI = np.linspace(0.02, 1, 3) + +INVSQ2 = 1 / math.sqrt(2) +T_PHASE = np.exp(1j * np.pi / 4) +T_PHASE_C = np.exp(-1j * np.pi / 4) + +# Variant of diag that does not take the diagonal of a 2d array, but broadcasts diag. +diag = lambda x: np.array([np.diag(_x) for _x in x]) if np.ndim(x) == 2 else np.diag(x) + + +def mat_vec(mat, vec, par=None, inv=False): + if par is not None: + scalar = [np.isscalar(p) for p in par] + if not all(scalar): + batch_size = len(par[scalar.index(False)]) + par = [tuple(p if s else p[i] for p, s in zip(par, scalar)) for i in range(batch_size)] + mat = np.array([mat(*_par) for _par in par]) + else: + mat = mat(*par) + + if inv: + mat = np.moveaxis(mat.conj(), -2, -1) + + return np.einsum("...ij,...j->...i", mat, vec) + + +class TestApplyBroadcasted: + """Tests that operations and inverses of certain operations are applied to a broadcasted + state/with broadcasted parameters (or both) correctly, or that the proper errors are raised. + """ + + triple_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + test_data_no_parameters = [ + (qml.PauliX, triple_state, mat_vec(X, triple_state)), + (qml.PauliY, triple_state, mat_vec(Y, triple_state)), + (qml.PauliZ, triple_state, mat_vec(Z, triple_state)), + (qml.S, triple_state, mat_vec(S, triple_state)), + (qml.T, triple_state, mat_vec(T, triple_state)), + (qml.Hadamard, triple_state, mat_vec(H, triple_state)), + (qml.Identity, triple_state, triple_state), + ] + + @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) + def test_apply_operation_single_wire_no_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have no parameters.""" + + qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) + qubit_device_1_wire.apply([operation(wires=[0])]) + + assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) + assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE + + single_state = np.array([[0, 0.6, 0, 0.8]]) + triple_state = np.array([[1, 0, 0, 0], [0, 0, INVSQ2, -INVSQ2], [0, 0.6, 0, 0.8]]) + + test_data_two_wires_no_param = [ + (qml_op, state, mat_vec(mat_op, state)) + for (qml_op, mat_op), state in product( + zip( + [qml.CNOT, qml.SWAP, qml.CZ, qml.ISWAP, qml.SISWAP, qml.SQISW], + [CNOT, SWAP, CZ, ISWAP, SISWAP, SISWAP], + ), + [single_state, triple_state], + ) + ] + + @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_param) + def test_apply_operation_two_wires_no_parameters_broadcasted( + self, qubit_device_2_wires, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for two wire + operations that have no parameters.""" + + qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( + (-1, 2, 2) + ) + qubit_device_2_wires.apply([operation(wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.reshape((-1, 4)), + np.array(expected_output), + atol=tol, + rtol=0, + ) + assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE + + quad_state = np.array( + [ + [0.6, 0, 0, 0, 0, 0, 0.8, 0], + [-INVSQ2, INVSQ2, 0, 0, 0, 0, 0, 0], + [0, 0, 0.5, 0.5, 0.5, -0.5, 0, 0], + [0, 0, 0.5, 0, 0.5, -0.5, 0, 0.5], + ] + ) + test_data_three_wires_no_parameters = [(qml.CSWAP, quad_state, mat_vec(CSWAP, quad_state))] + + @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) + def test_apply_operation_three_wires_no_parameters_broadcasted( + self, qubit_device_3_wires, tol, operation, input, expected_output + ): + """Tests that applying an operation yields the expected output state for three wire + operations that have no parameters.""" + + qubit_device_3_wires._state = np.array(input, dtype=qubit_device_3_wires.C_DTYPE).reshape( + (-1, 2, 2, 2) + ) + qubit_device_3_wires.apply([operation(wires=[0, 1, 2])]) + + assert np.allclose( + qubit_device_3_wires._state.reshape((-1, 8)), + np.array(expected_output), + atol=tol, + rtol=0, + ) + assert qubit_device_3_wires._state.dtype == qubit_device_3_wires.C_DTYPE + + single_state = np.array([[0, 0, 1, 0]]) + triple_state = np.array( + [ + [0, 0, 1, 0], + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [0.5, -0.5, 0.5j, -0.5j], + ] + ) + + # TODO[dwierichs]: add tests with qml.BaisState once `_apply_basis_state` supports broadcasting + @pytest.mark.parametrize( + "operation,expected_output,par", + [(qml.QubitStateVector, s, s) for s in [single_state, triple_state]], + ) + def test_apply_operation_state_preparation_broadcasted( + self, qubit_device_2_wires, tol, operation, expected_output, par + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have no parameters.""" + + par = np.array(par) + qubit_device_2_wires.reset() + qubit_device_2_wires.apply([operation(par, wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.reshape((-1, 4)), + np.array(expected_output), + atol=tol, + rtol=0, + ) + + # Collect test cases for single-scalar-parameter single-wire operations and their inverses + # For each operation, we choose broadcasted state, broadcasted params, or both + state_1 = np.array([0.6, 0.8j]) + state_5 = np.array([[INVSQ2, INVSQ2], [0.6, 0.8], [0, 1j], [-1, 0], [-INVSQ2, INVSQ2]]) + scalar_par_1 = [np.pi / 2] + scalar_par_5 = [[np.pi / 3, np.pi, 0.5, -1.2, -3 * np.pi / 2]] + test_data_single_wire_with_parameters = [ + (qml_op, state, mat_vec(mat_op, state, par=par), par) + for (qml_op, mat_op), (state, par) in product( + zip( + [qml.PhaseShift, qml.RX, qml.RY, qml.RZ, qml.MultiRZ], + [Rphi, Rotx, Roty, Rotz, MultiRZ1], + ), + [(state_1, scalar_par_5), (state_5, scalar_par_1), (state_5, scalar_par_5)], + ) + ] + + # Add qml.QubitUnitary test cases + matrix_1_par_1 = [np.array([[1, 1j], [1j, 1]]) * INVSQ2] + matrix_1_par_5 = [ + np.array( + [ + np.array([[1, -1j], [-1j, 1]]) * INVSQ2, + np.array([[1, -1], [1, 1]]) * INVSQ2, + np.array([[T_PHASE_C, 0], [0, T_PHASE]]), + np.array([[1, 0], [0, -1]]), + T, + ] + ) + ] + test_data_single_wire_with_parameters += [ + (qml.QubitUnitary, s, mat_vec(par[0], s), par) + for s, par in [ + (state_1, matrix_1_par_5), + (state_5, matrix_1_par_1), + (state_5, matrix_1_par_5), + ] + ] + + # Add qml.DiagonalQubitUnitary test cases + diag_par_1 = [[np.exp(1j * 0.1), np.exp(1j * np.pi)]] + diag_par_5 = [ + np.array( + [ + [1, -1j], + [np.exp(1j * 0.4), np.exp(1j * -0.4)], + [np.exp(1j * 0.1), np.exp(1j * np.pi)], + [1.0, np.exp(1j * np.pi / 2)], + [1, 1], + ] + ) + ] + test_data_single_wire_with_parameters += [ + (qml.DiagonalQubitUnitary, s, mat_vec(diag(par[0]), s), par) + for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)] + ] + + # Add qml.SpecialUnitary test cases + theta_1_par_1 = [np.array([np.pi / 2, 0, 0])] + theta_1_par_5 = [ + np.array( + [[np.pi / 2, 0, 0], [0, np.pi / 2, 0], [0, 0, np.pi / 2], [0.3, 0, 0], [0.4, 0.2, 1.2]] + ) + ] + test_data_single_wire_with_parameters += [ + (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 1), s), par) + for s, par in [(state_1, theta_1_par_5), (state_5, theta_1_par_1), (state_5, theta_1_par_5)] + ] + + # Add qml.Rot test cases + multi_par_1 = { + "rz_0": [0.632, 0, 0], + "ry": [0, 0.632, 0], + "rz_1": [0, 0, 0.632], + "mixed": [0.12, -2.468, 0.812], + } + multi_par_5 = { + "rz_0": [[np.pi / 2 * i for i in range(5)], 0, 0], + "ry": [0, [np.pi / 2 * i for i in range(5)], 0], + "rz_1": [0, 0, [np.pi / 2 * i for i in range(5)]], + "mixed": [[np.pi / 2 * i for i in range(5)], [np.pi / 2 * i for i in range(5)], np.pi], + } + for like in ["rz_0", "ry", "rz_1", "mixed"]: + states_and_pars = [ + (state_1, multi_par_5[like]), + (state_5, multi_par_1[like]), + (state_5, multi_par_5[like]), + ] + test_data_single_wire_with_parameters += [ + (qml.Rot, s, mat_vec(Rot3, s, par=par), par) for s, par in states_and_pars + ] + + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_single_wire_with_parameters + ) + def test_apply_operation_single_wire_with_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that applying an operation yields the expected output state for single wire + operations that have parameters.""" + + qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) + + par = tuple(np.array(p) for p in par) + qubit_device_1_wire.apply([operation(*par, wires=[0])]) + + assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) + assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE + + # Collect test cases for single-scalar-parameter two-wires operations and their inverses + # For each operation, we choose broadcasted state, broadcasted params, or both + state_1 = np.array([0.6, 0.8j, -0.6, -0.8j]) * INVSQ2 + state_5 = np.array( + [ + [0, 1, 0, 0], + [0, 0, 0, 1], + [0, INVSQ2, INVSQ2, 0], + [0.5, 0.5j, -0.5, 0.5], + [0.6, 0, -0.8j, 0], + ] + ) + scalar_par_1 = [np.pi / 2] + scalar_par_5 = [[np.pi / 3, np.pi, 0.5, -1.2, -3 * np.pi / 2]] + two_wires_scalar_par_ops = [ + qml.CRX, + qml.CRY, + qml.CRZ, + qml.MultiRZ, + qml.IsingXX, + qml.IsingYY, + qml.IsingZZ, + ] + two_wires_scalar_par_mats = [CRotx, CRoty, CRotz, MultiRZ2, IsingXX, IsingYY, IsingZZ] + test_data_two_wires_with_parameters = [ + (qml_op, state, mat_vec(mat_op, state, par=par), par) + for (qml_op, mat_op), (state, par) in product( + zip(two_wires_scalar_par_ops, two_wires_scalar_par_mats), + [(state_1, scalar_par_5), (state_5, scalar_par_1), (state_5, scalar_par_5)], + ) + ] + + # Add qml.CRot test cases + multi_par_1 = { + "rz_0": [0.632, 0, 0], + "ry": [0, 0.632, 0], + "rz_1": [0, 0, 0.632], + "mixed": [0.12, -2.468, 0.812], + } + multi_par_5 = { + "rz_0": [[np.pi / 2 * i for i in range(5)], 0, 0], + "ry": [0, [np.pi / 2 * i for i in range(5)], 0], + "rz_1": [0, 0, [np.pi / 2 * i for i in range(5)]], + "mixed": [[np.pi / 2 * i for i in range(5)], [np.pi / 2 * i for i in range(5)], np.pi], + } + for like in ["rz_0", "ry", "rz_1", "mixed"]: + states_and_pars = [ + (state_1, multi_par_5[like]), + (state_5, multi_par_1[like]), + (state_5, multi_par_5[like]), + ] + test_data_two_wires_with_parameters += [ + (qml.CRot, s, mat_vec(CRot3, s, par=par), par) for s, par in states_and_pars + ] + + # Add qml.QubitUnitary test cases + matrix_2_par_1 = [SISWAP] + matrix_2_par_5 = [ + np.array( + [ + np.eye(4), + np.array([[1, -1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, -1j, 1]]) * INVSQ2, + np.array([[1, -1, 0, 0], [1, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, -1]]) * INVSQ2, + np.array([[T_PHASE_C, 0, 0, 0], [0, T_PHASE, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1j]]), + SISWAP, + ] + ) + ] + test_data_two_wires_with_parameters += [ + (qml.QubitUnitary, s, mat_vec(par[0], s), par) + for s, par in [ + (state_1, matrix_2_par_5), + (state_5, matrix_2_par_1), + (state_5, matrix_2_par_5), + ] + ] + + # Add qml.DiagonalQubitUnitary test cases + diag_par_1 = [np.exp(1j * np.array([0.1, np.pi, 0.2, -2.4]))] + diag_par_5 = [ + np.array( + [ + np.ones(4), + [1, -1j, 1, 1j], + [np.exp(1j * 0.4), np.exp(1j * -0.4), 1j, 1], + [np.exp(1j * 0.1), np.exp(1j * np.pi), INVSQ2 * (1 + 1j), INVSQ2 * (1 - 1j)], + [1.0, np.exp(1j * np.pi / 2), 1, 1], + ] + ) + ] + test_data_two_wires_with_parameters += [ + (qml.DiagonalQubitUnitary, s, mat_vec(diag(par[0]), s), par) + for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)] + ] + + # Add qml.SpecialUnitary test cases + theta_2_par_1 = [np.linspace(0.1, 3, 15)] + theta_2_par_5 = [np.array([0.4, -0.2, 1.2, -0.5, 2.2])[:, np.newaxis] * np.eye(15)[2::3]] + test_data_two_wires_with_parameters += [ + (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 2), s), par) + for s, par in [(state_1, theta_2_par_5), (state_5, theta_2_par_1), (state_5, theta_2_par_5)] + ] + + @pytest.mark.parametrize( + "operation,input,expected_output,par", test_data_two_wires_with_parameters + ) + def test_apply_operation_two_wires_with_parameters_broadcasted( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that applying an operation yields the expected output state for two wire + operations that have parameters.""" + + shape = (5, 2, 2) if np.array(input).size == 20 else (2, 2) + dtype = qubit_device_2_wires.C_DTYPE + qubit_device_2_wires._state = np.array(input, dtype=dtype).reshape(shape) + par = tuple(np.array(p) for p in par) + qubit_device_2_wires.apply([operation(*par, wires=[0, 1])]) + + assert np.allclose( + qubit_device_2_wires._state.reshape((5, 4)), expected_output, atol=tol, rtol=0 + ) + assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE + + def test_apply_errors_qubit_state_vector_broadcasted(self, qubit_device_2_wires): + """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" + with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array([[1, -1], [0, 2]]), wires=[0])] + ) + + # Also test that the sum-check is *not* performed along the broadcasting dimension + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array([[0.6, 0.8], [0.6, 0.8]]), wires=[0])] + ) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): + # Second dimension does not match 2**num_wires + p = np.array([[1, 0, 1, 1, 0], [0, 1, 1, 0, 1]]) / np.sqrt(3) + qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): + # Broadcasting dimension is not first dimension + p = np.array([[1, 1, 0], [0, 1, 1], [1, 0, 1], [0, 1, 1]]) / np.sqrt(2) + qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) + + qubit_device_2_wires.reset() + vec = qml.QubitStateVector(np.array([[0, 1, 0, 0], [0, 0, 1, 0]]), wires=[0, 1]) + with pytest.raises( + DeviceError, + match="Operation QubitStateVector cannot be used after other Operations have already been applied " + "on a default.qubit device.", + ): + qubit_device_2_wires.apply([qml.RZ(0.5, wires=[0]), vec]) + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_apply_errors_basis_state_broadcasted(self, qubit_device_2_wires): + """Test that applying the BasisState operation raises the correct errors.""" + with pytest.raises( + ValueError, match="BasisState parameter must consist of 0 or 1 integers." + ): + op = qml.BasisState(np.array([[-0.2, 4.2], [0.5, 1.2]]), wires=[0, 1]) + qubit_device_2_wires.apply([op]) + + with pytest.raises( + ValueError, match="BasisState parameter and wires must be of equal length." + ): + # Test that the error is raised + qubit_device_2_wires.apply( + [qml.BasisState(np.array([[0, 1], [1, 1], [1, 0]]), wires=[0])] + ) + # Test that the broadcasting dimension is allowed to mismatch the length of the wires + qubit_device_2_wires.apply([qml.BasisState(np.array([[0], [1], [0]]), wires=[0])]) + + qubit_device_2_wires.reset() + qubit_device_2_wires.apply([qml.RZ(0.5, wires=[0])]) + vec = qml.BasisState(np.array([[0, 0], [1, 0], [1, 1]]), wires=[0, 1]) + with pytest.raises( + DeviceError, + match="Operation BasisState cannot be used after other Operations have already been applied " + "on a default.qubit device.", + ): + qubit_device_2_wires.apply([vec]) + + +zero = [1, 0] +one = [0, 1] +plus = [INVSQ2, INVSQ2] +minus = [INVSQ2, -INVSQ2] +y_plus = [INVSQ2, 1j * INVSQ2] +y_minus = [INVSQ2, -1j * INVSQ2] + + +class TestExpvalBroadcasted: + """Tests that expectation values are properly calculated for broadcasted states + or that the proper errors are raised.""" + + @pytest.mark.parametrize( + "operation,input,expected_output", + [ + (qml.PauliX, np.array([plus, zero, minus]), [1, 0, -1]), + (qml.PauliY, np.array([y_plus, zero, y_minus]), [1, 0, -1]), + (qml.PauliZ, np.array([plus, zero, one]), [0, 1, -1]), + (qml.Hadamard, np.array([plus, zero, one]), [INVSQ2, INVSQ2, -INVSQ2]), + (qml.Identity, np.array([minus, zero, one]), [1, 1, 1]), + ], + ) + def test_expval_single_wire_no_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that expectation values are properly calculated for single-wire observables without parameters.""" + + obs = operation(wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.expval(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [(qml.Hermitian, [zero, one, minus, y_plus], [1, 1, 1, 0], I - Y)], + ) + def test_expval_single_wire_with_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that expectation values are properly calculated for single-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.expval(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + ( + qml.Hermitian, + [ + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [0, 0, 0, 1], + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + ], + [4 / 3, 0, 1], + [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 0]], + ), + ( + qml.Hermitian, + [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], + [1, -1], + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ], + ) + def test_expval_two_wires_with_parameters_broadcasted( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that expectation values are properly calculated for two-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0, 1]) + + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() + ) + res = qubit_device_2_wires.expval(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + def test_expval_estimate_broadcasted(self): + """Test that the expectation value is not analytically calculated""" + + dev = qml.device("default.qubit", wires=1, shots=3) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(np.zeros(5), wires=0) # Broadcast the tape without applying an op + return qml.expval(qml.PauliX(0)) + + expval = circuit() + + # With 3 samples we are guaranteed to see a difference between + # an estimated variance an an analytically calculated one + assert np.all(expval != 0.0) + + +class TestVarBroadcasted: + """Tests that variances are properly calculated for broadcasted states.""" + + @pytest.mark.parametrize( + "operation,input,expected_output", + [ + (qml.PauliX, [plus, zero, minus], [0, 1, 0]), + (qml.PauliY, [y_plus, zero, y_minus], [0, 1, 0]), + (qml.PauliZ, [plus, zero, one], [1, 0, 0]), + (qml.Hadamard, [plus, zero, one], [0.5, 0.5, 0.5]), + (qml.Identity, [minus, zero, one], [0, 0, 0]), + ], + ) + def test_var_single_wire_no_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output + ): + """Tests that variances are properly calculated for single-wire observables without parameters.""" + + obs = operation(wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.var(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [(qml.Hermitian, [zero, one, minus, y_plus], [1, 1, 1, 0], I - Y)], + ) + def test_var_single_wire_with_parameters_broadcasted( + self, qubit_device_1_wire, tol, operation, input, expected_output, par + ): + """Tests that variances are properly calculated for single-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0]) + + qubit_device_1_wire.reset() + qubit_device_1_wire.apply( + [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() + ) + res = qubit_device_1_wire.var(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "operation,input,expected_output,par", + [ + ( + qml.Hermitian, + [ + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [0, 0, 0, 1], + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + ], + [11 / 9, 2, 3 / 2], + [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], + ), + ( + qml.Hermitian, + [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], + [0, 0], + [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], + ), + ], + ) + def test_var_two_wires_with_parameters_broadcasted( + self, qubit_device_2_wires, tol, operation, input, expected_output, par + ): + """Tests that variances are properly calculated for two-wire observables with parameters.""" + + obs = operation(np.array(par), wires=[0, 1]) + + qubit_device_2_wires.reset() + qubit_device_2_wires.apply( + [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() + ) + res = qubit_device_2_wires.var(obs) + + assert np.allclose(res, expected_output, atol=tol, rtol=0) + + def test_var_estimate_broadcasted(self): + """Test that the variance is not analytically calculated""" + + dev = qml.device("default.qubit", wires=1, shots=3) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(np.zeros(5), wires=0) # Broadcast the tape without applying an op + return qml.var(qml.PauliX(0)) + + var = circuit() + + # With 3 samples we are guaranteed to see a difference between + # an estimated variance and an analytically calculated one + assert np.all(var != 1.0) + + +class TestSampleBroadcasted: + """Tests that samples are properly calculated for broadcasted states.""" + + def test_sample_dimensions_broadcasted(self): + """Tests if the samples returned by the sample function have + the correct dimensions + """ + + # Explicitly resetting is necessary as the internal + # state is set to None in __init__ and only properly + # initialized during reset + dev = qml.device("default.qubit", wires=2, shots=1000) + + dev.apply([qml.RX(np.array([np.pi / 2, 0.0]), 0), qml.RX(np.array([np.pi / 2, 0.0]), 1)]) + + dev.shots = 10 + dev._wires_measured = {0} + dev._samples = dev.generate_samples() + s1 = dev.sample(qml.PauliZ(0)) + assert s1.shape == ( + 2, + 10, + ) + + dev.reset() + dev.shots = 12 + dev._wires_measured = {1} + dev._samples = dev.generate_samples() + s2 = dev.sample(qml.PauliZ(wires=[1])) + assert s2.shape == (12,) + + dev.reset() + dev.apply([qml.RX(np.ones(5), 0), qml.RX(np.ones(5), 1)]) + dev.shots = 17 + dev._wires_measured = {0, 1} + dev._samples = dev.generate_samples() + s3 = dev.sample(qml.PauliX(0) @ qml.PauliZ(1)) + assert s3.shape == (5, 17) + + def test_sample_values_broadcasted(self, tol): + """Tests if the samples returned by sample have + the correct values + """ + + # Explicitly resetting is necessary as the internal + # state is set to None in __init__ and only properly + # initialized during reset + dev = qml.device("default.qubit", wires=2, shots=1000) + + dev.apply([qml.RX(np.ones(3), wires=[0])]) + dev._wires_measured = {0} + dev._samples = dev.generate_samples() + + s1 = dev.sample(qml.PauliZ(0)) + + # s1 should only contain 1 and -1, which is guaranteed if + # they square to 1 + assert np.allclose(s1**2, 1, atol=tol, rtol=0) + + +class TestDefaultQubitIntegrationBroadcasted: + """Integration tests for default.qubit. This test ensures it integrates + properly with the PennyLane interface, in particular QNode.""" + + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + def test_qubit_circuit_broadcasted(self, qubit_device_1_wire, r_dtype, tol): + """Test that the default qubit plugin provides correct result for a simple circuit""" + + p = np.array([0.543, np.pi / 2, 0.0, 1.0]) + + dev = qubit_device_1_wire + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -np.sin(p) + + res = circuit(p) + assert np.allclose(res, expected, atol=tol, rtol=0) + assert res.dtype == r_dtype # pylint:disable=no-member + + def test_qubit_identity_broadcasted(self, qubit_device_1_wire, tol): + """Test that the default qubit plugin provides correct result for the Identity expectation""" + + p = np.array([0.543, np.pi / 2, 0.0, 1.0]) + + @qml.qnode(qubit_device_1_wire) + def circuit(x): + """Test quantum function""" + qml.RX(x, wires=0) + return qml.expval(qml.Identity(0)) + + assert np.allclose(circuit(p), 1, atol=tol, rtol=0) + + def test_nonzero_shots_broadcasted(self, tol): + """Test that the default qubit plugin provides correct result for high shot number""" + + shots = 10**5 + dev = qml.device("default.qubit", wires=1, shots=shots) + + p = np.array([0.543, np.pi / 2, 0.0, 1.0]) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + """Test quantum function""" + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + runs = [] + for _ in range(100): + runs.append(circuit(p)) + + assert np.allclose(np.mean(runs, axis=0), -np.sin(p), atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output", + [ + ("PauliX", [plus, minus, zero], [1, -1, 0]), + ("PauliY", [y_plus, y_minus, zero], [1, -1, 0]), + ("PauliZ", [plus, one, zero], [0, -1, 1]), + ("Hadamard", [plus, one, zero], [INVSQ2, -INVSQ2, INVSQ2]), + ], + ) + def test_supported_observable_single_wire_no_parameters_broadcasted( + self, qubit_device_1_wire, tol, name, state, expected_output + ): + """Tests supported observables on single wires without parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_1_wire.supports_observable(name) + + @qml.qnode(qubit_device_1_wire) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0]) + return qml.expval(obs(wires=[0])) + + assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output,par", + [ + ("Identity", [zero, one, plus], [1, 1, 1], []), + ("Hermitian", [zero, one, minus], [1, 1, 1], [I - Y]), + ], + ) + def test_supported_observable_single_wire_with_parameters_broadcasted( + self, qubit_device_1_wire, tol, name, state, expected_output, par + ): + """Tests supported observables on single wires with parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_1_wire.supports_observable(name) + + @qml.qnode(qubit_device_1_wire) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0]) + return qml.expval(obs(*par, wires=[0])) + + assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "name,state,expected_output,par", + [ + ( + "Hermitian", + [ + [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], + [0, 0, 0, 1], + [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], + ], + [4 / 3, 0, 1], + ([[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 0]],), + ), + ( + "Hermitian", + [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], + [1, -1], + ([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]],), + ), + ], + ) + def test_supported_observable_two_wires_with_parameters_broadcasted( + self, qubit_device_2_wires, tol, name, state, expected_output, par + ): + """Tests supported observables on two wires with parameters.""" + + obs = getattr(qml.ops, name) + + assert qubit_device_2_wires.supports_observable(name) + + @qml.qnode(qubit_device_2_wires) + def circuit(): + qml.QubitStateVector(np.array(state), wires=[0, 1]) + return qml.expval(obs(*par, wires=[0, 1])) + + assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) + + def test_multi_samples_return_correlated_results_broadcasted(self): + """Tests if the samples returned by the sample function are correlated + correctly for correlated observables. + """ + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.Hadamard(0) + qml.RX(np.zeros(5), 0) + qml.CNOT(wires=[0, 1]) + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + + outcomes = circuit() + + assert np.array_equal(outcomes[0], outcomes[1]) + + @pytest.mark.parametrize("num_wires", [3, 4, 5, 6, 7, 8]) + def test_multi_samples_correlated_results_more_wires_than_observable_broadcasted( + self, num_wires + ): + """Tests if the samples returned by the sample function are correlated + correctly for correlated observables on larger devices than the observables + """ + + dev = qml.device("default.qubit", wires=num_wires, shots=1000) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.Hadamard(0) + qml.RX(np.zeros(5), 0) + qml.CNOT(wires=[0, 1]) + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) + + outcomes = circuit() + + assert np.array_equal(outcomes[0], outcomes[1]) + + +# pylint: disable=unused-argument +@pytest.mark.parametrize( + "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] +) +class TestTensorExpvalBroadcasted: + """Test tensor expectation values for broadcasted states""" + + def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and Identity works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.cos(varphi) * np.cos(phi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3) + dev.reset() + + A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.5 * ( + -6 * np.cos(theta) * (np.cos(varphi) + 1) + - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) + + 3 * np.cos(varphi) * np.sin(phi) + + np.sin(phi) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving two Hermitian matrices works correctly""" + dev = qml.device("default.qubit", wires=3) + + A1 = np.array([[1, 2], [2, 4]]) + + A2 = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.25 * ( + -30 + + 4 * np.cos(phi) * np.sin(theta) + + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) + - 3 * np.sin(phi) + - 2 + * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) + * np.sin(varphi) + + np.cos(theta) + * ( + 18 + + 5 * np.sin(phi) + + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) + + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) + ) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" + dev = qml.device("default.qubit", wires=2) + + A = np.array( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] + ) + + obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_two_wires_identity_expectation_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" + dev = qml.device("default.qubit", wires=3) + + A = np.array( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] + ) + Identity = np.array([[1, 0], [0, 1]]) + Ham = np.kron(np.kron(Identity, Identity), A) + obs = qml.Hermitian(Ham, wires=[2, 1, 0]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.parametrize( + "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] +) +class TestTensorVarBroadcasted: + """Tests for variance of tensor observables for broadcasted states""" + + def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 + - np.cos(2 * (theta - phi)) + - np.cos(2 * (theta + phi)) + + 2 * np.cos(2 * theta) + + 2 * np.cos(2 * phi) + + 14 + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 3 + + np.cos(2 * phi) * np.cos(varphi) ** 2 + - np.cos(2 * theta) * np.sin(varphi) ** 2 + - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) + ) / 4 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_broadcasted(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3) + + A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 1057 + - np.cos(2 * phi) + + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) + - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) + + 16 * np.sin(2 * phi) + - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) + - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 + - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) + - 8 + * np.cos(theta) + * ( + 4 + * np.cos(phi) + * ( + 4 + + 8 * np.cos(varphi) + + np.cos(2 * varphi) + - (1 + 6 * np.cos(varphi)) * np.sin(varphi) + ) + + np.sin(phi) + * ( + 15 + + 8 * np.cos(varphi) + - 11 * np.cos(2 * varphi) + + 42 * np.sin(varphi) + + 3 * np.sin(2 * varphi) + ) + ) + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.parametrize( + "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] +) +class TestTensorSampleBroadcasted: + """Test tensor sampling for broadcated states""" + + def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.probability(wires=dev.map_wires(obs.wires)) + + # s1 should only contain 1 and -1 + assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + + mean = p @ s1 + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = p @ (s1**2) - (p @ s1).real ** 2 + expected = ( + 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 + - np.cos(2 * (theta - phi)) + - np.cos(2 * (theta + phi)) + + 2 * np.cos(2 * theta) + + 2 * np.cos(2 * phi) + + 14 + ) / 16 + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.marginal_prob(dev.probability(), wires=obs.wires) + + # s1 should only contain 1 and -1 + assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) + + mean = p @ s1 + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = p @ (s1**2) - (p @ s1).real ** 2 + expected = ( + 3 + + np.cos(2 * phi) * np.cos(varphi) ** 2 + - np.cos(2 * theta) * np.sin(varphi) ** 2 + - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) + ) / 4 + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + def test_hermitian_broadcasted(self, theta, phi, varphi, tol_stochastic): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + + A = 0.1 * np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + dev._wires_measured = {0, 1, 2} + dev._samples = dev.generate_samples() + dev.sample(obs) + + s1 = obs.eigvals() + p = dev.marginal_prob(dev.probability(), wires=obs.wires) + + # s1 should only contain the eigenvalues of + # the hermitian matrix tensor product Z + z = np.diag([1, -1]) + eigvals = np.linalg.eigvalsh(np.kron(z, A)) + assert set(np.round(s1, 8).tolist()).issubset(set(np.round(eigvals, 8).tolist())) + + mean = p @ s1 + expected = ( + 0.1 + * 0.5 + * ( + -6 * np.cos(theta) * (np.cos(varphi) + 1) + - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) + + 3 * np.cos(varphi) * np.sin(phi) + + np.sin(phi) + ) + ) + assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) + + var = p @ (s1**2) - (p @ s1).real ** 2 + expected = ( + 0.01 + * ( + 1057 + - np.cos(2 * phi) + + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) + - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) + + 16 * np.sin(2 * phi) + - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) + - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 + - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) + - 8 + * np.cos(theta) + * ( + 4 + * np.cos(phi) + * ( + 4 + + 8 * np.cos(varphi) + + np.cos(2 * varphi) + - (1 + 6 * np.cos(varphi)) * np.sin(varphi) + ) + + np.sin(phi) + * ( + 15 + + 8 * np.cos(varphi) + - 11 * np.cos(2 * varphi) + + 42 * np.sin(varphi) + + 3 * np.sin(2 * varphi) + ) + ) + ) + / 16 + ) + assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) + + +@pytest.mark.parametrize( + "r_dtype,c_dtype", [(np.float32, np.complex64), (np.float64, np.complex128)] +) +class TestDtypePreservedBroadcasted: + """Test that the user-defined dtype of the device is preserved for QNode + evaluation""" + + @pytest.mark.parametrize( + "op", + [ + qml.SingleExcitation, + qml.SingleExcitationPlus, + qml.SingleExcitationMinus, + qml.DoubleExcitation, + qml.DoubleExcitationPlus, + qml.DoubleExcitationMinus, + qml.OrbitalRotation, + qml.FermionicSWAP, + qml.QubitSum, + qml.QubitCarry, + ], + ) + def test_state_dtype_after_op_broadcasted(self, r_dtype, c_dtype, op): + """Test that the default qubit plugin preserves data types of states when an operation is + applied. As TestApply class check most of operators, we here only check some subtle + examples. + """ + + dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + + n_wires = op.num_wires + n_params = op.num_params + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + x = np.array([0.543, 0.622, 1.3]) + if n_params == 0: + op(wires=range(n_wires)) + elif n_params == 1: + op(x, wires=range(n_wires)) + else: + op([x] * n_params, wires=range(n_wires)) + return qml.state() + + res = circuit() + assert res.dtype == c_dtype # pylint:disable=no-member + + @pytest.mark.parametrize( + "measurement", + [ + qml.expval(qml.PauliY(0)), + qml.var(qml.PauliY(0)), + qml.probs(wires=[1]), + qml.probs(wires=[2, 0]), + ], + ) + def test_measurement_real_dtype_broadcasted(self, r_dtype, c_dtype, measurement): + """Test that the default qubit plugin provides correct result for a simple circuit""" + p = np.array([0.543, 0.622, 1.3]) + + dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(measurement) + + res = circuit(p) + assert res.dtype == r_dtype + + def test_measurement_complex_dtype_broadcasted(self, r_dtype, c_dtype): + """Test that the default qubit plugin provides correct result for a simple circuit""" + p = np.array([0.543, 0.622, 1.3]) + m = qml.state() + + dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.apply(m) + + res = circuit(p) + assert res.dtype == c_dtype + + +class TestProbabilityIntegrationBroadcasted: + """Test probability method for when analytic is True/False""" + + # pylint: disable=no-member, unused-argument + def mock_analytic_counter(self, wires=None): + self.analytic_counter += 1 + return np.array([1, 0, 0, 0], dtype=float) + + def test_probability_broadcasted(self, tol): + """Test that the probability function works for finite and infinite shots""" + dev = qml.device("default.qubit", wires=2, shots=1000) + dev_analytic = qml.device("default.qubit", wires=2, shots=None) + + x = np.array([[0.2, 0.5, 0.4], [0.9, 0.8, 0.3]]) + + def circuit(x): + qml.RX(x[0], wires=0) + qml.RY(x[1], wires=0) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[0, 1]) + + prob = qml.QNode(circuit, dev) + prob_analytic = qml.QNode(circuit, dev_analytic) + + assert np.allclose(prob(x).sum(axis=-1), 1, atol=tol, rtol=0) + assert np.allclose(prob_analytic(x), prob(x), atol=0.1, rtol=0) + assert not np.array_equal(prob_analytic(x), prob(x)) + + +class TestWiresIntegrationBroadcasted: + """Test that the device integrates with PennyLane's wire management.""" + + def make_circuit_probs(self, wires): + """Factory for a qnode returning probabilities using arbitrary wire labels.""" + dev = qml.device("default.qubit", wires=wires) + n_wires = len(wires) + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(np.array([0.5, 1.2, -0.6]), wires=wires[0 % n_wires]) + qml.RY(np.array([2.0, 0.4, 1.2]), wires=wires[1 % n_wires]) + if n_wires > 1: + qml.CNOT(wires=[wires[0], wires[1]]) + return qml.probs(wires=wires) + + return circuit + + @pytest.mark.parametrize( + "wires1, wires2", + [ + (["a", "c", "d"], [2, 3, 0]), + ([-1, -2, -3], ["q1", "ancilla", 2]), + (["a", "c"], [3, 0]), + ([-1, -2], ["ancilla", 2]), + (["a"], ["nothing"]), + ], + ) + def test_wires_probs_broadcasted(self, wires1, wires2, tol): + """Test that the probability vector of a circuit is independent from the wire labels used.""" + + circuit1 = self.make_circuit_probs(wires1) + circuit2 = self.make_circuit_probs(wires2) + + assert np.allclose(circuit1(), circuit2(), tol) + + +class TestApplyOpsBroadcasted: + """Tests for special methods listed in _apply_ops that use array manipulation tricks to apply + gates in DefaultQubit.""" + + broadcasted_state = np.arange(2**4 * 3, dtype=np.complex128).reshape((3, 2, 2, 2, 2)) + dev = qml.device("default.qubit", wires=4) + + single_qubit_ops = [ + (qml.PauliX, dev._apply_x), + (qml.PauliY, dev._apply_y), + (qml.PauliZ, dev._apply_z), + (qml.Hadamard, dev._apply_hadamard), + (qml.S, dev._apply_s), + (qml.T, dev._apply_t), + (qml.SX, dev._apply_sx), + ] + two_qubit_ops = [ + (qml.CNOT, dev._apply_cnot), + (qml.SWAP, dev._apply_swap), + (qml.CZ, dev._apply_cz), + ] + three_qubit_ops = [ + (qml.Toffoli, dev._apply_toffoli), + ] + + @pytest.mark.parametrize("op, method", single_qubit_ops) + def test_apply_single_qubit_op_broadcasted_state(self, op, method): + """Test if the application of single qubit operations to a + broadcasted state is correct.""" + state_out = method(self.broadcasted_state, axes=[2]) + op = op(wires=[1]) + matrix = op.matrix() + state_out_einsum = np.einsum("ab,mibjk->miajk", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", two_qubit_ops) + def test_apply_two_qubit_op_broadcasted_state(self, op, method): + """Test if the application of two qubit operations to a + broadcasted state is correct.""" + state_out = method(self.broadcasted_state, axes=[1, 2]) + op = op(wires=[0, 1]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2, 2, 2)) + state_out_einsum = np.einsum("abcd,mcdjk->mabjk", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", two_qubit_ops) + def test_apply_two_qubit_op_reverse_broadcasted_state(self, op, method): + """Test if the application of two qubit operations to a + broadcasted state is correct when the applied wires are reversed.""" + state_out = method(self.broadcasted_state, axes=[3, 2]) + op = op(wires=[2, 1]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2, 2, 2)) + state_out_einsum = np.einsum("abcd,midck->mibak", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_smaller_broadcasted_state(self, op, method): + """Test if the application of three qubit operations to a broadcasted + state is correct when both control wires are smaller than the target wire.""" + state_out = method(self.broadcasted_state, axes=[1, 3, 4]) + op = op(wires=[0, 2, 3]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,mdkef->makbc", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_greater_broadcasted_state(self, op, method): + """Test if the application of three qubit operations to a broadcasted + state is correct when both control wires are greater than the target wire.""" + state_out = method(self.broadcasted_state, axes=[3, 2, 1]) + op = op(wires=[2, 1, 0]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,mfedk->mcbak", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + @pytest.mark.parametrize("op, method", three_qubit_ops) + def test_apply_three_qubit_op_controls_split_broadcasted_state(self, op, method): + """Test if the application of three qubit operations to a broadcasted state is correct + when one control wire is smaller and one control wire is greater than the target wire.""" + state_out = method(self.broadcasted_state, axes=[4, 2, 3]) + op = op(wires=[3, 1, 2]) + matrix = op.matrix() + matrix = matrix.reshape((2, 2) * 3) + state_out_einsum = np.einsum("abcdef,mkdfe->mkacb", matrix, self.broadcasted_state) + assert np.allclose(state_out, state_out_einsum) + + +class TestStateVectorBroadcasted: + """Unit tests for the _apply_state_vector method with broadcasting""" + + def test_full_subsystem_broadcasted(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubit(wires=["a", "b", "c"]) + state = np.array([[0, 1, 1, 0, 1, 1, 0, 0], [1, 0, 0, 0, 1, 0, 1, 1]]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(dev._state.reshape((2, 8)) == state) + spy.assert_not_called() + + def test_partial_subsystem_broadcasted(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubit(wires=["a", "b", "c"]) + state = np.array([[0, 1, 1, 0], [1, 0, 1, 0], [1, 1, 0, 0]]) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + # Axes are (broadcasting, wire "a", wire "b", wire "c"), so we sum over axis=2 + res = np.sum(dev._state, axis=(2,)).reshape((3, 4)) + + assert np.all(res == state) + spy.assert_called() + + +class TestApplyOperationBroadcasted: + """Unit tests for the internal _apply_operation method.""" + + def test_internal_apply_ops_case_broadcasted(self, monkeypatch): + """Tests that if we provide an operation that has an internal + implementation, then we use that specific implementation. + + This test provides a new internal function that `default.qubit` uses to + apply `PauliX` (rather than redefining the gate itself). + """ + dev = qml.device("default.qubit", wires=1) + + test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + # Create a dummy operation + expected_test_output = np.ones(1) + supported_gate_application = lambda *args, **kwargs: expected_test_output + + with monkeypatch.context() as m: + # Set the internal ops implementations dict + m.setattr(dev, "_apply_ops", {"PauliX": supported_gate_application}) + + op = qml.PauliX(0) + + res = dev._apply_operation(test_state, op) + assert np.allclose(res, expected_test_output) + + def test_diagonal_operation_case_broadcasted(self, monkeypatch): + """Tests the case when the operation to be applied is + diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" + dev = qml.device("default.qubit", wires=1) + par = 0.3 + + test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + wires = 0 + op = qml.PhaseShift(par, wires=wires) + assert op.name not in dev._apply_ops + + # Set the internal _apply_diagonal_unitary + history = [] + mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) + with monkeypatch.context() as m: + m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) + assert dev._apply_diagonal_unitary == mock_apply_diag + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, np.diag(op.matrix())) + assert np.allclose(res_wires, wires) + + def test_apply_einsum_case_broadcasted(self, monkeypatch): + """Tests the case when np.einsum is used to apply an operation in + default.qubit.""" + dev = qml.device("default.qubit", wires=1) + + test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + wires = 0 + + # Redefine the S gate so that it is an example for a one-qubit gate + # that is not registered in the diagonal_in_z_basis attribute + # pylint: disable=too-few-public-methods + class TestSGate(qml.operation.Operation): + num_wires = 1 + + # pylint: disable=unused-argument + @staticmethod + def compute_matrix(*params, **hyperparams): + return np.array([[1, 0], [0, 1j]]) + + dev.operations.add("TestSGate") + op = TestSGate(wires=wires) + + assert op.name in dev.operations + assert op.name not in dev._apply_ops + + # Set the internal _apply_unitary_einsum + history = [] + mock_apply_einsum = lambda state, matrix, wires: history.append((state, matrix, wires)) + with monkeypatch.context() as m: + m.setattr(dev, "_apply_unitary_einsum", mock_apply_einsum) + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, op.matrix()) + assert np.allclose(res_wires, wires) + + def test_apply_tensordot_case_broadcasted(self, monkeypatch): + """Tests the case when np.tensordot is used to apply an operation in + default.qubit.""" + dev = qml.device("default.qubit", wires=3) + + test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + wires = [0, 1, 2] + + # Redefine the Toffoli gate so that it is an example for a gate with + # more than two wires + # pylint: disable=too-few-public-methods + class TestToffoli(qml.operation.Operation): + num_wires = 3 + + # pylint: disable=unused-argument + @staticmethod + def compute_matrix(*params, **hyperparams): + return Toffoli + + dev.operations.add("TestToffoli") + op = TestToffoli(wires=wires) + + assert op.name in dev.operations + assert op.name not in dev._apply_ops + + # Set the internal _apply_unitary_tensordot + history = [] + mock_apply_tensordot = lambda state, matrix, wires: history.append((state, matrix, wires)) + + with monkeypatch.context() as m: + m.setattr(dev, "_apply_unitary", mock_apply_tensordot) + + dev._apply_operation(test_state, op) + + res_state, res_mat, res_wires = history[0] + + assert np.allclose(res_state, test_state) + assert np.allclose(res_mat, op.matrix()) + assert np.allclose(res_wires, wires) + + def test_identity_skipped_broadcasted(self, mocker): + """Test that applying the identity operation does not perform any additional computations.""" + dev = qml.device("default.qubit", wires=1) + + starting_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) + op = qml.Identity(0) + + spy_diagonal = mocker.spy(dev, "_apply_diagonal_unitary") + spy_einsum = mocker.spy(dev, "_apply_unitary_einsum") + spy_unitary = mocker.spy(dev, "_apply_unitary") + + res = dev._apply_operation(starting_state, op) + assert res is starting_state + + spy_diagonal.assert_not_called() + spy_einsum.assert_not_called() + spy_unitary.assert_not_called() + + +class TestHamiltonianSupportBroadcasted: + """Tests the devices' native support for Hamiltonian observables.""" + + def test_do_not_split_analytic_broadcasted(self, mocker): + """Tests that the Hamiltonian is not split for shots=None.""" + dev = qml.device("default.qubit", wires=2) + Ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="parameter-shift", interface=None) + def circuit(): + qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity + return qml.expval(Ham) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_split_finite_shots_broadcasted(self, mocker): + """Tests that the Hamiltonian is split for finite shots.""" + dev = qml.device("default.qubit", wires=2, shots=10) + spy = mocker.spy(dev, "expval") + + ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev) + def circuit(): + qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity + return qml.expval(ham) + + circuit() + + # evaluated one expval per Pauli observable + assert spy.call_count == 2 + + +original_capabilities = qml.devices.DefaultQubit.capabilities() + + +@pytest.fixture(scope="function", name="mock_default_qubit") +def mock_default_qubit_fixture(monkeypatch): + """A function to create a mock device that mocks the broadcasting support flag + to be False, so that default support via broadcast_expand transform can be tested""" + + # pylint: disable=unused-argument + def overwrite_support(*cls): + capabilities = original_capabilities.copy() + capabilities.update(supports_broadcasting=False) + return capabilities + + with monkeypatch.context() as m: + m.setattr(qml.devices.DefaultQubit, "capabilities", overwrite_support) + + def get_default_qubit(wires=1, shots=None): + dev = qml.devices.DefaultQubit(wires=wires, shots=shots) + return dev + + yield get_default_qubit + + +@pytest.mark.parametrize("shots", [None, 100000]) +class TestBroadcastingSupportViaExpansion: + """Tests that the device correctly makes use of ``broadcast_expand`` to + execute broadcasted tapes if its capability to execute broadcasted tapes + is artificially deactivated.""" + + @pytest.mark.parametrize("x", [0.2, np.array([0.1, 0.6, 0.3]), np.array([0.1])]) + def test_with_single_broadcasted_par(self, x, shots, mock_default_qubit): + """Test that broadcasting on a circuit with a + single parametrized operation works.""" + dev = mock_default_qubit(wires=2, shots=shots) + + @qml.qnode(dev) + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit.construct((np.array(x),), {}) + out = circuit(np.array(x)) + + assert circuit.device.num_executions == (1 if isinstance(x, float) else len(x)) + tol = 1e-10 if shots is None else 1e-2 + assert qml.math.allclose(out, qml.math.cos(x), atol=tol, rtol=0) + + @pytest.mark.parametrize( + "x, y", [(0.2, np.array([0.4])), (np.array([0.1, 5.1]), np.array([0.1, -0.3]))] + ) + def test_with_multiple_pars(self, x, y, shots, mock_default_qubit): + """Test that broadcasting on a circuit with a + single parametrized operation works.""" + dev = mock_default_qubit(wires=2, shots=shots) + + @qml.qnode(dev) + def circuit(x, y): + qml.RX(x, wires=0) + qml.RX(y, wires=1) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1)) + + out = circuit(x, y) + expected = qml.math.stack([qml.math.cos(x) * qml.math.ones_like(y), -qml.math.sin(y)]) + + assert circuit.device.num_executions == len(y) + tol = 1e-10 if shots is None else 1e-2 + + assert qml.math.allclose(out[0], expected[0], atol=tol, rtol=0) + assert qml.math.allclose(out[1], expected[1], atol=tol, rtol=0) + + @pytest.mark.parametrize( + "x, y", [(0.2, np.array([0.4])), (np.array([0.1, 5.1]), np.array([0.1, -0.3]))] + ) + def test_with_Hamiltonian(self, x, y, shots, mock_default_qubit): + """Test that broadcasting on a circuit with a + single parametrized operation works.""" + dev = mock_default_qubit(wires=2, shots=shots) + + Ham = qml.Hamiltonian([0.3, 0.9], [qml.PauliZ(0), qml.PauliY(1)]) + Ham.compute_grouping() + + @qml.qnode(dev) + def circuit(x, y): + qml.RX(x, wires=0) + qml.RX(y, wires=1) + return qml.expval(Ham) + + out = circuit(x, y) + expected = 0.3 * qml.math.cos(x) * qml.math.ones_like(y) - 0.9 * qml.math.sin(y) + + assert circuit.device.num_executions == len(y) + tol = 1e-10 if shots is None else 1e-2 + assert qml.math.allclose(out, expected, atol=tol, rtol=0) diff --git a/tests/devices/default_qubit_1/test_default_qubit_jax.py b/tests/devices/default_qubit_1/test_default_qubit_jax.py new file mode 100644 index 00000000000..b805b2d1772 --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit_jax.py @@ -0,0 +1,1312 @@ +# Copyright 2018-2021 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. +""" +Integration tests for the ``default.qubit.jax`` device. +""" +import pytest +import numpy as np + +import pennylane as qml +from pennylane import DeviceError +from pennylane.pulse import ParametrizedHamiltonian + +jax = pytest.importorskip("jax", minversion="0.2") +from pennylane.devices.default_qubit_jax import ( # pylint: disable=wrong-import-position + DefaultQubitJax, +) + +jnp = jax.numpy + + +@pytest.mark.jax +def test_analytic_deprecation(): + """Tests if the kwarg `analytic` is used and displays error message.""" + msg = "The analytic argument has been replaced by shots=None. " + msg += "Please use shots=None instead of analytic=True." + + with pytest.raises( + DeviceError, + match=msg, + ): + qml.device("default.qubit.jax", wires=1, shots=1, analytic=True) + + +# pylint: disable=too-many-public-methods +@pytest.mark.jax +class TestQNodeIntegration: + """Integration tests for default.qubit.jax. This test ensures it integrates + properly with the PennyLane UI, in particular the new QNode.""" + + def test_defines_correct_capabilities(self): + """Test that the device defines the right capabilities""" + + dev = qml.device("default.qubit.jax", wires=1) + cap = dev.capabilities() + capabilities = { + "model": "qubit", + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "returns_state": True, + "supports_inverse_operations": True, + "supports_analytic_computation": True, + "supports_broadcasting": True, + "passthru_interface": "jax", + "passthru_devices": { + "torch": "default.qubit.torch", + "tf": "default.qubit.tf", + "autograd": "default.qubit.autograd", + "jax": "default.qubit.jax", + }, + } + assert cap == capabilities + + def test_defines_correct_capabilities_directly_from_class(self): + """Test that the device defines the right capabilities""" + + dev = DefaultQubitJax(wires=1) + cap = dev.capabilities() + assert cap["passthru_interface"] == "jax" + + def test_load_device(self): + """Test that the plugin device loads correctly""" + dev = qml.device("default.qubit.jax", wires=2) + assert dev.num_wires == 2 + assert dev.shots is None + assert dev.short_name == "default.qubit.jax" + assert dev.capabilities()["passthru_interface"] == "jax" + + @pytest.mark.parametrize( + "jax_enable_x64, c_dtype, r_dtype", + ([True, np.complex128, np.float64], [False, np.complex64, np.float32]), + ) + def test_float_precision(self, jax_enable_x64, c_dtype, r_dtype): + """Test that the plugin device uses the same float precision as the jax config.""" + jax.config.update("jax_enable_x64", jax_enable_x64) + dev = qml.device("default.qubit.jax", wires=2) + assert dev.state.dtype == c_dtype + assert dev.state.real.dtype == r_dtype + + def test_qubit_circuit(self, tol): + """Test that the device provides the correct + result for a simple circuit.""" + p = jnp.array(0.543) + + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -jnp.sin(p) + assert jnp.isclose(circuit(p), expected, atol=tol, rtol=0) + + def test_qubit_circuit_with_jit(self, tol): + """Test that the device provides the correct + result for a simple circuit under a jax.jit.""" + p = jnp.array(0.543) + + dev = qml.device("default.qubit.jax", wires=1) + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -jnp.sin(p) + # Do not test isinstance here since the @jax.jit changes the function + # type. Just test that it works and spits our the right value. + assert jnp.isclose(circuit(p), expected, atol=tol, rtol=0) + + # Test with broadcasted parameters + p = jnp.array([0.543, 0.21, 1.5]) + expected = -jnp.sin(p) + assert jnp.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_qubit_circuit_broadcasted(self, tol): + """Test that the device provides the correct + result for a simple broadcasted circuit.""" + p = jnp.array([0.543, 0.21, 1.5]) + + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -jnp.sin(p) + + assert jnp.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_correct_state(self, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + + dev = qml.device("default.qubit.jax", wires=2) + + state = dev.state + expected = jnp.array([1, 0, 0, 0]) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(jnp.pi / 4, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + amplitude = jnp.exp(-1j * jnp.pi / 8) / jnp.sqrt(2) + + expected = jnp.array([amplitude, 0, jnp.conj(amplitude), 0]) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_broadcasted(self, tol): + """Test that the device state is correct after applying a + broadcasted quantum function on the device""" + + dev = qml.device("default.qubit.jax", wires=2) + + state = dev.state + expected = jnp.array([1, 0, 0, 0]) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(jnp.array([np.pi / 4, np.pi / 2]), wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + phase = jnp.exp(-1j * jnp.pi / 8) + + expected = np.array( + [ + [phase / jnp.sqrt(2), 0, jnp.conj(phase) / jnp.sqrt(2), 0], + [phase**2 / jnp.sqrt(2), 0, jnp.conj(phase) ** 2 / jnp.sqrt(2), 0], + ] + ) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_returned(self, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(jnp.pi / 4, wires=0) + return qml.state() + + state = circuit() + + amplitude = jnp.exp(-1j * jnp.pi / 8) / jnp.sqrt(2) + + expected = jnp.array([amplitude, 0, jnp.conj(amplitude), 0]) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_returned_broadcasted(self, tol): + """Test that the device state is correct after applying a + broadcasted quantum function on the device""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(jnp.array([np.pi / 4, np.pi / 2]), wires=0) + return qml.state() + + state = circuit() + + phase = jnp.exp(-1j * jnp.pi / 8) + + expected = np.array( + [ + [phase / jnp.sqrt(2), 0, jnp.conj(phase) / jnp.sqrt(2), 0], + [phase**2 / jnp.sqrt(2), 0, jnp.conj(phase) ** 2 / jnp.sqrt(2), 0], + ] + ) + assert jnp.allclose(state, expected, atol=tol, rtol=0) + + def test_probs_jax(self, tol): + """Test that returning probs works with jax""" + dev = qml.device("default.qubit.jax", wires=1, shots=100) + expected = jnp.array([0.0, 1.0]) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.PauliX(wires=0) + return qml.probs(wires=0) + + result = circuit() + assert jnp.allclose(result, expected, atol=tol) + + def test_probs_jax_broadcasted(self, tol): + """Test that returning probs works with jax""" + dev = qml.device("default.qubit.jax", wires=1, shots=100) + expected = jnp.array([[0.0, 1.0]] * 3) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.RX(jnp.zeros(3), 0) + qml.PauliX(wires=0) + return qml.probs(wires=0) + + result = circuit() + assert jnp.allclose(result, expected, atol=tol) + + def test_probs_jax_jit(self, tol): + """Test that returning probs works with jax and jit""" + dev = qml.device("default.qubit.jax", wires=1, shots=100) + expected = jnp.array([0.0, 1.0]) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(z): + qml.RX(z, wires=0) + qml.PauliX(wires=0) + return qml.probs(wires=0) + + result = circuit(0.0) + assert jnp.allclose(result, expected, atol=tol) + + # Test with broadcasting + result = circuit(jnp.zeros(3)) + expected = jnp.array([[0.0, 1.0]] * 3) + assert jnp.allclose(result, expected, atol=tol) + + def test_custom_shots_probs_jax_jit(self, tol): + """Test that returning probs works with jax and jit when using custom shot vector""" + # pylint:disable=unsubscriptable-object + dev = qml.device("default.qubit.jax", wires=1, shots=(3, 2)) + expected = jnp.array([[0.0, 1.0], [0.0, 1.0]]) + + @jax.jit + @qml.qnode(dev, diff_method=None, interface="jax") + def circuit(): + qml.PauliX(wires=0) + return qml.probs(wires=0) + + result = circuit() + assert jnp.allclose(qml.math.hstack(result[0]), expected[0], atol=tol) + assert jnp.allclose(qml.math.hstack(result[1]), expected[1], atol=tol) + + @pytest.mark.skip("Shot lists are not supported with broadcasting yet") + def test_custom_shots_probs_jax_jit_broadcasted(self, tol): + """Test that returning probs works with jax and jit when + using a custom shot vector and broadcasting""" + dev = qml.device("default.qubit.jax", wires=1, shots=(2, 2)) + expected = jnp.array([[[0.0, 1.0], [0.0, 1.0]]] * 5) + + @jax.jit + @qml.qnode(dev, diff_method=None, interface="jax") + def circuit(): + qml.RX(jnp.zeros(5), 0) + qml.PauliX(wires=0) + return qml.probs(wires=0) + + result = circuit() + assert jnp.allclose(result, expected, atol=tol) + + def test_sampling_with_jit(self): + """Test that sampling works with a jax.jit""" + + @jax.jit + def circuit(x, key): + dev = qml.device("default.qubit.jax", wires=1, shots=1000, prng_key=key) + + @qml.qnode(dev, interface="jax", diff_method=None) + def inner_circuit(): + qml.RX(x, wires=0) + qml.Hadamard(0) + return qml.sample(qml.PauliZ(wires=0)) + + return inner_circuit() + + a = circuit(0.0, jax.random.PRNGKey(0)) + b = circuit(0.0, jax.random.PRNGKey(0)) + c = circuit(0.0, jax.random.PRNGKey(1)) + np.testing.assert_array_equal(a, b) + assert not np.all(a == c) + + # Test with broadcasting + d = circuit(jnp.zeros(5), jax.random.PRNGKey(9)) + assert qml.math.shape(d) == (5, 1000) + + @pytest.mark.parametrize( + "state_vector", + [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], + ) + def test_qubit_state_vector_arg_jax_jit(self, state_vector, tol): + """Test that Qubit state vector as argument works with a jax.jit""" + dev = qml.device("default.qubit.jax", wires=list(range(2))) + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(x): + wires = list(range(2)) + qml.QubitStateVector(x, wires=wires) + return [qml.expval(qml.PauliX(wires=i)) for i in wires] + + res = circuit(state_vector) + assert jnp.allclose(jnp.array(res), jnp.array([0, 1]), atol=tol, rtol=0) + + @pytest.mark.parametrize( + "state_vector", + [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], + ) + def test_qubit_state_vector_arg_jax(self, state_vector, tol): + """Test that Qubit state vector as argument works with jax""" + dev = qml.device("default.qubit.jax", wires=list(range(2))) + + @qml.qnode(dev, interface="jax") + def circuit(x): + wires = list(range(2)) + qml.QubitStateVector(x, wires=wires) + return [qml.expval(qml.PauliX(wires=i)) for i in wires] + + res = circuit(state_vector) + assert jnp.allclose(jnp.array(res), jnp.array([0, 1]), atol=tol, rtol=0) + + @pytest.mark.parametrize( + "state_vector", + [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], + ) + def test_qubit_state_vector_jax_jit(self, state_vector, tol): + """Test that Qubit state vector works with a jax.jit""" + dev = qml.device("default.qubit.jax", wires=list(range(2))) + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.QubitStateVector(state_vector, wires=dev.wires) + for w in dev.wires: + qml.RZ(x, wires=w, id="x") + return qml.expval(qml.PauliZ(wires=0)) + + res = circuit(0.1) + assert jnp.allclose(jnp.array(res), 1, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "state_vector", + [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], + ) + def test_qubit_state_vector_jax(self, state_vector, tol): + """Test that Qubit state vector works with a jax""" + dev = qml.device("default.qubit.jax", wires=list(range(2))) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.QubitStateVector(state_vector, wires=dev.wires) + for w in dev.wires: + qml.RZ(x, wires=w, id="x") + return qml.expval(qml.PauliZ(wires=0)) + + res = circuit(0.1) + assert jnp.allclose(jnp.array(res), 1, atol=tol, rtol=0) + + @pytest.mark.parametrize( + "state_vector", + [np.array([0.1 + 0.1j, 0.2 + 0.2j, 0, 0]), jnp.array([0.1 + 0.1j, 0.2 + 0.2j, 0, 0])], + ) + def test_qubit_state_vector_jax_not_normed(self, state_vector): + """Test that an error is raised when Qubit state vector is not normed works with a jax""" + dev = qml.device("default.qubit.jax", wires=list(range(2))) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.QubitStateVector(state_vector, wires=dev.wires) + for w in dev.wires: + qml.RZ(x, wires=w, id="x") + return qml.expval(qml.PauliZ(wires=0)) + + with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): + circuit(0.1) + + def test_sampling_op_by_op(self): + """Test that op-by-op sampling works as a new user would expect""" + dev = qml.device("default.qubit.jax", wires=1, shots=1000) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.Hadamard(0) + return qml.sample(qml.PauliZ(wires=0)) + + a = circuit() + b = circuit() + assert not np.all(a == b) + + def test_sampling_analytic_mode(self): + """Test that when sampling with shots=None an error is raised.""" + dev = qml.device("default.qubit.jax", wires=1, shots=None) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + return qml.sample(qml.PauliZ(wires=0)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The number of shots has to be explicitly set on the device " + "when using sample-based measurements.", + ): + circuit() + + def test_sampling_analytic_mode_with_counts(self): + """Test that when sampling with counts and shots=None an error is raised.""" + dev = qml.device("default.qubit.jax", wires=1, shots=None) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + return qml.counts(qml.PauliZ(wires=0)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The number of shots has to be explicitly set on the device " + "when using sample-based measurements.", + ): + circuit() + + def test_gates_dont_crash(self): + """Test for gates that weren't covered by other tests.""" + dev = qml.device("default.qubit.jax", wires=2, shots=1000) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.CRZ(0.0, wires=[0, 1]) + qml.CRX(0.0, wires=[0, 1]) + qml.PhaseShift(0.0, wires=0) + qml.ControlledPhaseShift(0.0, wires=[1, 0]) + qml.CRot(1.0, 0.0, 0.0, wires=[0, 1]) + qml.CRY(0.0, wires=[0, 1]) + return qml.sample(qml.PauliZ(wires=0)) + + circuit() # Just don't crash. + + def test_diagonal_doesnt_crash(self): + """Test that diagonal gates can be used.""" + dev = qml.device("default.qubit.jax", wires=1, shots=1000) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.DiagonalQubitUnitary(np.array([1.0, 1.0]), wires=0) + return qml.sample(qml.PauliZ(wires=0)) + + circuit() # Just don't crash. + + def test_broadcasted_diagonal_doesnt_crash(self): + """Test that diagonal gates can be used.""" + dev = qml.device("default.qubit.jax", wires=1, shots=1000) + + @qml.qnode(dev, interface="jax", diff_method=None) + def circuit(): + qml.DiagonalQubitUnitary(np.array([[-1, -1], [1j, -1], [1.0, 1.0]]), wires=0) + return qml.sample(qml.PauliZ(wires=0)) + + circuit() # Just don't crash. + + @pytest.mark.parametrize("phi", np.pi * np.array([1e-8, 1 / 8, 1 / 4, 1 / 2, 1])) + def test_parametrized_evolution_state_vector(self, phi, mocker): + """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` + the `_evolve_state_vector_under_parametrized_evolution` method is used.""" + dev = qml.device("default.qubit.jax", wires=1) + H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) + spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(): + qml.evolve(H)(params=[], t=phi / 2) + return qml.expval(qml.PauliZ(0)) + + @qml.qnode(dev) + def true_circuit(): + qml.RX(phi, 0) + return qml.expval(qml.PauliZ(0)) + + res = circuit() + spy.assert_called_once() + assert qml.math.allclose(res, true_circuit(), atol=1e-6) + + @pytest.mark.parametrize("phi", np.pi * np.array([1e-8, 1 / 8, 1 / 4, 1 / 2, 1])) + def test_parametrized_evolution_matrix(self, phi, mocker): + """Test that when executing a ParametrizedEvolution with ``num_wires < device.num_wires/2`` + the `_apply_operation` method is used.""" + dev = qml.device("default.qubit.jax", wires=3) + H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) + spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") + spy2 = mocker.spy(dev, "_apply_operation") + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(): + qml.evolve(H)(params=[], t=phi / 2) # corresponds to a PauliX gate + return qml.expval(qml.PauliZ(0)) + + @qml.qnode(dev) + def true_circuit(): + qml.RX(phi, 0) + return qml.expval(qml.PauliZ(0)) + + res = circuit() + spy.assert_not_called() + spy2.assert_called_once() + assert qml.math.allclose(res, true_circuit(), atol=1e-6) + + def test_parametrized_evolution_state_vector_return_intermediate(self, mocker): + """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` + and ``return_intermediate=True``, the ``_evolve_state_vector_under_parametrized_evolution`` + method is used.""" + dev = qml.device("default.qubit.jax", wires=1) + H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) + spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") + spy2 = mocker.spy(dev, "_apply_operation") + + phi = jnp.linspace(0.3, 0.7, 7) + phi_for_RX = phi - phi[0] + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(): + qml.evolve(H, return_intermediate=True)(params=[], t=phi / 2) + return qml.expval(qml.PauliZ(0)) + + @qml.qnode(dev) + def true_circuit(): + qml.RX(phi_for_RX, 0) + return qml.expval(qml.PauliZ(0)) + + res = circuit() + spy.assert_called_once() + spy2.assert_not_called() + assert qml.math.allclose(res, true_circuit(), atol=1e-6) + + def test_parametrized_evolution_matrix_complementary(self, mocker): + """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` + but with ``complementary=True``, the `_apply_operation` method is used.""" + dev = qml.device("default.qubit.jax", wires=1) + H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) + spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") + spy2 = mocker.spy(dev, "_apply_operation") + + phi = jnp.linspace(0.3, 0.7, 7) + phi_for_RX = phi[-1] - phi + + @jax.jit + @qml.qnode(dev, interface="jax") + def circuit(): + qml.evolve(H, return_intermediate=True, complementary=True)(params=[], t=phi / 2) + return qml.expval(qml.PauliZ(0)) + + @qml.qnode(dev) + def true_circuit(): + qml.RX(phi_for_RX, 0) + return qml.expval(qml.PauliZ(0)) + + res = circuit() + spy.assert_not_called() + spy2.assert_called_once() + assert qml.math.allclose(res, true_circuit(), atol=1e-6) + + +@pytest.mark.jax +class TestPassthruIntegration: + """Tests for integration with the PassthruQNode""" + + @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) + def test_jacobian_variable_multiply(self, tol, jacobian_transform): + """Test that jacobian of a QNode with an attached default.qubit.jax device + gives the correct result in the case of parameters multiplied by scalars""" + x = 0.43316321 + y = 0.2162158 + z = 0.75110998 + weights = jnp.array([x, y, z]) + + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(weights) + + expected = jnp.cos(3 * x) * jnp.cos(y) * jnp.cos(z / 2) - jnp.sin(3 * x) * jnp.sin(z / 2) + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = jacobian_transform(circuit, 0) + res = grad_fn(jnp.array(weights)) + + expected = jnp.array( + [ + -3 + * (jnp.sin(3 * x) * jnp.cos(y) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.sin(z / 2)), + -jnp.cos(3 * x) * jnp.sin(y) * jnp.cos(z / 2), + -0.5 + * (jnp.sin(3 * x) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.cos(y) * jnp.sin(z / 2)), + ] + ) + + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_variable_multiply_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.jax device + gives the correct result in the case of broadcasted parameters multiplied by scalars""" + x = jnp.array([0.43316321, 92.1, -0.5129]) + y = jnp.array([0.2162158, 0.241, -0.51]) + z = jnp.array([0.75110998, 0.12512, 9.12]) + weights = jnp.array([x, y, z]) + + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + assert circuit.gradient_fn == "backprop" + res = circuit(weights) + + expected = jnp.cos(3 * x) * jnp.cos(y) * jnp.cos(z / 2) - jnp.sin(3 * x) * jnp.sin(z / 2) + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = jax.jacobian(circuit, 0) + res = grad_fn(jnp.array(weights)) + + expected = jnp.array( + [ + -3 + * (jnp.sin(3 * x) * jnp.cos(y) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.sin(z / 2)), + -jnp.cos(3 * x) * jnp.sin(y) * jnp.cos(z / 2), + -0.5 + * (jnp.sin(3 * x) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.cos(y) * jnp.sin(z / 2)), + ] + ) + + assert all(jnp.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) + def test_jacobian_repeated(self, tol, jacobian_transform): + """Test that jacobian of a QNode with an attached default.qubit.jax device + gives the correct result in the case of repeated parameters""" + x = 0.43316321 + y = 0.2162158 + z = 0.75110998 + p = jnp.array([x, y, z]) + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + + expected = jnp.cos(y) ** 2 - jnp.sin(x) * jnp.sin(y) ** 2 + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = jacobian_transform(circuit, 0) + res = grad_fn(p) + + expected = jnp.array( + [-jnp.cos(x) * jnp.sin(y) ** 2, -2 * (jnp.sin(x) + 1) * jnp.sin(y) * jnp.cos(y), 0] + ) + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_repeated_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.jax device + gives the correct result in the case of repeated broadcasted parameters""" + p = jnp.array([[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]]) + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + + x, y, _ = p + expected = jnp.cos(y) ** 2 - jnp.sin(x) * jnp.sin(y) ** 2 + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + grad_fn = jax.jacobian(circuit) + res = grad_fn(p) + + expected = jnp.array( + [ + -jnp.cos(x) * jnp.sin(y) ** 2, + -2 * (jnp.sin(x) + 1) * jnp.sin(y) * jnp.cos(y), + jnp.zeros_like(x), + ] + ) + assert all(jnp.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + @pytest.mark.parametrize("wires", [[0], ["abc"]]) + def test_state_differentiability(self, wires, tol): + """Test that the device state can be differentiated""" + dev = qml.device("default.qubit.jax", wires=wires) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a): + qml.RY(a, wires=wires[0]) + return qml.state() + + a = jnp.array(0.54) + + def cost(a): + """A function of the device quantum state, as a function + of input QNode parameters.""" + res = jnp.abs(circuit(a)) ** 2 + return res[1] - res[0] + + grad = jax.grad(cost)(a) + expected = jnp.sin(a) + assert jnp.allclose(grad, expected, atol=tol, rtol=0) + + def test_state_differentiability_broadcasted(self, tol): + """Test that the broadcasted device state can be differentiated""" + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a): + qml.RY(a, wires=0) + return qml.expval(qml.PauliZ(0)) + + a = jnp.array([0.54, 0.32, 1.2]) + + def cost(a): + """A function of the device quantum state, as a function + of input QNode parameters.""" + circuit(a) + res = jnp.abs(dev.state) ** 2 + return res[:, 1] - res[:, 0] + + jac = jax.jacobian(cost)(a) + expected = jnp.diag(jnp.sin(a)) + assert jnp.allclose(jac, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, np.pi, 7)) + def test_CRot_gradient(self, theta, tol): + """Tests that the automatic gradient of a arbitrary controlled Euler-angle-parameterized + gate is correct.""" + dev = qml.device("default.qubit.jax", wires=2) + a, b, c = np.array([theta, theta**3, np.sqrt(2) * theta]) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a, b, c): + qml.QubitStateVector(np.array([1.0, -1.0]) / np.sqrt(2), wires=0) + qml.CRot(a, b, c, wires=[0, 1]) + return qml.expval(qml.PauliX(0)) + + res = circuit(a, b, c) + expected = -np.cos(b / 2) * np.cos(0.5 * (a + c)) + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad = jax.grad(circuit, argnums=(0, 1, 2))(a, b, c) + expected = np.array( + [ + [ + 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), + 0.5 * np.sin(b / 2) * np.cos(0.5 * (a + c)), + 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), + ] + ] + ) + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_prob_differentiability(self, tol): + """Test that the device probability can be differentiated""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = jnp.array(0.54) + b = jnp.array(0.12) + + def cost(a, b): + prob_wire_1 = circuit(a, b).squeeze() # pylint:disable=no-member + return prob_wire_1[1] - prob_wire_1[0] + + res = cost(a, b) + expected = -jnp.cos(a) * jnp.cos(b) + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + grad = jax.jit(jax.grad(cost, argnums=(0, 1)))(a, b) + expected = [jnp.sin(a) * jnp.cos(b), jnp.cos(a) * jnp.sin(b)] + assert jnp.allclose(jnp.array(grad), jnp.array(expected), atol=tol, rtol=0) + + def test_prob_differentiability_broadcasted(self, tol): + """Test that the broadcasted device probability can be differentiated""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = jnp.array([0.54, 0.32, 1.2]) + b = jnp.array(0.12) + + def cost(a, b): + prob_wire_1 = circuit(a, b) + return prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object + + res = cost(a, b) + expected = -jnp.cos(a) * jnp.cos(b) + assert jnp.allclose(res, expected, atol=tol, rtol=0) + + jac = jax.jacobian(cost, argnums=[0, 1])(a, b) + expected = jnp.array([jnp.sin(a) * jnp.cos(b), jnp.cos(a) * jnp.sin(b)]) + expected = (jnp.diag(expected[0]), expected[1]) # Only first parameter is broadcasted + assert all(jnp.allclose(j, e, atol=tol, rtol=0) for j, e in zip(jac, expected)) + + def test_backprop_gradient(self, tol): + """Tests that the gradient of the qnode is correct""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = jnp.array(-0.234) + b = jnp.array(0.654) + + res = circuit(a, b) + expected_cost = 0.5 * (jnp.cos(a) * jnp.cos(b) + jnp.cos(a) - jnp.cos(b) + 1) + assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) + res = jax.grad(circuit, argnums=(0, 1))(a, b) + expected_grad = jnp.array( + [-0.5 * jnp.sin(a) * (jnp.cos(b) + 1), 0.5 * jnp.sin(b) * (1 - jnp.cos(a))] + ) + + assert jnp.allclose(jnp.array(res), jnp.array(expected_grad), atol=tol, rtol=0) + + def test_backprop_gradient_broadcasted(self, tol): + """Tests that the gradient of the broadcasted qnode is correct""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = jnp.array(0.12) + b = jnp.array([0.54, 0.32, 1.2]) + + res = circuit(a, b) + expected_cost = 0.5 * (jnp.cos(a) * jnp.cos(b) + jnp.cos(a) - jnp.cos(b) + 1) + assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) + + res = jax.jacobian(circuit, argnums=[0, 1])(a, b) + expected = jnp.array( + [-0.5 * jnp.sin(a) * (jnp.cos(b) + 1), 0.5 * jnp.sin(b) * (1 - jnp.cos(a))] + ) + expected = (expected[0], jnp.diag(expected[1])) + assert all(jnp.allclose(r, e, atol=tol, rtol=0) for r, e in zip(res, expected)) + + @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) + def test_hessian_at_zero(self, x, shift): + """Tests that the Hessian at vanishing state vector amplitudes + is correct.""" + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, interface="jax", diff_method="backprop") + def circuit(x): + qml.RY(shift, wires=0) + qml.RY(x, wires=0) + return qml.expval(qml.PauliZ(0)) + + assert qml.math.isclose(jax.grad(circuit)(x), 0.0) + assert qml.math.isclose(jax.jacobian(jax.jacobian(circuit))(x), -1.0) + assert qml.math.isclose(jax.grad(jax.grad(circuit))(x), -1.0) + + @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) + @pytest.mark.parametrize("diff_method", ["backprop"]) + def test_jax_interface_gradient(self, operation, diff_method, tol): + """Tests that the gradient of an arbitrary U3 gate is correct + using the Jax interface, using a variety of differentiation methods.""" + dev = qml.device("default.qubit.jax", wires=1) + + @qml.qnode(dev, diff_method=diff_method, interface="jax") + def circuit(x, weights, w=None): + """In this example, a mixture of scalar + arguments, array arguments, and keyword arguments are used.""" + qml.QubitStateVector(1j * jnp.array([1, -1]) / jnp.sqrt(2), wires=w) + operation(x, weights[0], weights[1], wires=w) + return qml.expval(qml.PauliX(w)) + + def cost(params): + """Perform some classical processing""" + return (circuit(params[0], params[1:], w=0) ** 2).reshape(()) + + theta = 0.543 + phi = -0.234 + lam = 0.654 + + params = jnp.array([theta, phi, lam]) + + res = cost(params) + expected_cost = ( + jnp.sin(lam) * jnp.sin(phi) - jnp.cos(theta) * jnp.cos(lam) * jnp.cos(phi) + ) ** 2 + assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) + + res = jax.grad(cost)(params) + expected_grad = ( + jnp.array( + [ + jnp.sin(theta) * jnp.cos(lam) * jnp.cos(phi), + jnp.cos(theta) * jnp.cos(lam) * jnp.sin(phi) + jnp.sin(lam) * jnp.cos(phi), + jnp.cos(theta) * jnp.sin(lam) * jnp.cos(phi) + jnp.cos(lam) * jnp.sin(phi), + ] + ) + * 2 + * (jnp.sin(lam) * jnp.sin(phi) - jnp.cos(theta) * jnp.cos(lam) * jnp.cos(phi)) + ) + assert jnp.allclose(res, expected_grad, atol=tol, rtol=0) + + @pytest.mark.parametrize("interface", ["autograd", "tf", "torch"]) + def test_error_backprop_wrong_interface(self, interface): + """Tests that an error is raised if diff_method='backprop' but not using + the Jax interface""" + dev = qml.device("default.qubit.jax", wires=1) + + def circuit(x, w=None): + qml.RZ(x, wires=w) + return qml.expval(qml.PauliX(w)) + + error_type = qml.QuantumFunctionError + with pytest.raises( + error_type, + match="default.qubit.jax only supports diff_method='backprop' when using the jax interface", + ): + qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) + + def test_no_jax_interface_applied(self): + """Tests that the JAX interface is not applied and no error is raised if qml.probs is used with the Jax + interface when diff_method='backprop' + + When the JAX interface is applied, we can only get the expectation value and the variance of a QNode. + """ + dev = qml.device("default.qubit.jax", wires=1, shots=None) + + def circuit(): + return qml.probs(wires=0) + + qnode = qml.qnode(dev, diff_method="backprop", interface="jax")(circuit) + assert jnp.allclose(qnode(), jnp.array([1, 0])) + + +@pytest.mark.jax +class TestHighLevelIntegration: + """Tests for integration with higher level components of PennyLane.""" + + def test_do_not_split_analytic_jax(self, mocker): + """Tests that the Hamiltonian is not split for shots=None using the jax device.""" + dev = qml.device("default.qubit.jax", wires=2) + H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(): + return qml.expval(H) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_direct_eval_hamiltonian_broadcasted_error_jax(self): + """Tests that an error is raised when attempting to evaluate a Hamiltonian with + broadcasting and shots=None directly via its sparse representation with Jax.""" + dev = qml.device("default.qubit.jax", wires=2) + H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(): + qml.RX(jnp.zeros(5), 0) + return qml.expval(H) + + with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): + circuit() + + def test_template_integration(self): + """Test that a PassthruQNode using default.qubit.jax works with templates.""" + dev = qml.device("default.qubit.jax", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(weights): + qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + weights = jnp.array( + np.random.random(qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=2)) + ) + + grad = jax.grad(circuit)(weights) + assert grad.shape == weights.shape + + +# pylint: disable=protected-access +@pytest.mark.jax +class TestOps: + """Unit tests for operations supported by the default.qubit.jax device""" + + @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) + def test_multirz_jacobian(self, jacobian_transform): + """Test that the patched numpy functions are used for the MultiRZ + operation and the jacobian can be computed.""" + wires = 4 + dev = qml.device("default.qubit.jax", wires=wires) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(param): + qml.MultiRZ(param, wires=[0, 1]) + return qml.probs(wires=list(range(wires))) + + param = 0.3 + res = jacobian_transform(circuit)(param) + assert jnp.allclose(res, jnp.zeros(wires**2)) + + def test_full_subsystem(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubitJax(wires=["a", "b", "c"]) + state = jnp.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert jnp.all(dev._state.flatten() == state) + spy.assert_not_called() + + def test_partial_subsystem(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubitJax(wires=["a", "b", "c"]) + state = jnp.array([1, 0, 1, 0]) / jnp.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = jnp.sum(dev._state, axis=(1,)).flatten() + + assert jnp.all(res == state) + spy.assert_called() + + def test_parametrized_evolution(self): + """Test applying a ParametrizedEvolution to a subset of wires of the full subsystem""" + dev = DefaultQubitJax(wires=["a", "b", "c"]) + state = jnp.array([[[1.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], dtype=complex) + expected_res = jnp.array( + [[[0.0, 0.0], [0.0, 0.0]], [[1.0, 0.0], [0.0, 0.0]]], dtype=complex + ) + # ev corresponds to a PauliX gate + ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX("a")]))(params=[], t=np.pi / 2) + res = qml.math.abs(dev._apply_parametrized_evolution(state=state, operation=ev)) + + assert qml.math.allclose(res, expected_res, atol=1e-5) + + def test_parametrized_evolution_raises_error(self): + """Test applying a ParametrizedEvolution without params or t specified raises an error.""" + dev = DefaultQubitJax(wires=["a"]) + state = jnp.array([[[1.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], dtype=complex) + ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX("a")])) + with pytest.raises( + ValueError, + match="The parameters and the time window are required to execute a ParametrizedEvolution", + ): + dev._apply_parametrized_evolution(state=state, operation=ev) + + +@pytest.mark.jax +class TestOpsBroadcasted: + """Unit tests for broadcasted operations supported by the default.qubit.jax device""" + + @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) + def test_multirz_jacobian_broadcasted(self, jacobian_transform): + """Test that the patched numpy functions are used for the MultiRZ + operation and the jacobian can be computed.""" + wires = 4 + dev = qml.device("default.qubit.jax", wires=wires) + + @qml.qnode(dev, diff_method="backprop", interface="jax") + def circuit(param): + qml.MultiRZ(param, wires=[0, 1]) + return qml.probs(wires=list(range(wires))) + + param = jnp.array([0.3, 0.9, -4.3]) + res = jacobian_transform(circuit)(param) + assert jnp.allclose(res, jnp.zeros((3, wires**2, 3))) + + def test_full_subsystem_broadcasted(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubitJax(wires=["a", "b", "c"]) + state = jnp.array([[1, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 1, 1, 1, 0]]) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert jnp.all(dev._state.reshape((2, 8)) == state) + spy.assert_not_called() + + def test_partial_subsystem_broadcasted(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + + dev = DefaultQubitJax(wires=["a", "b", "c"]) + state = jnp.array([[1, 0, 1, 0], [0, 1, 0, 1], [1, 1, 0, 0]]) / jnp.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = jnp.sum(dev._state, axis=(2,)).reshape((3, 4)) + + assert jnp.allclose(res, state) + spy.assert_called() + + +@pytest.mark.jax +class TestEstimateProb: + """Test the estimate_probability method""" + + @pytest.mark.parametrize( + "wires, expected", [([0], [0.5, 0.5]), (None, [0.5, 0, 0, 0.5]), ([0, 1], [0.5, 0, 0, 0.5])] + ) + def test_estimate_probability(self, wires, expected, monkeypatch): + """Tests the estimate_probability method""" + dev = qml.device("default.qubit.jax", wires=2) + samples = jnp.array([[0, 0], [1, 1], [1, 1], [0, 0]]) + + with monkeypatch.context() as m: + m.setattr(dev, "_samples", samples) + res = dev.estimate_probability(wires=wires) + + assert np.allclose(res, expected) + + @pytest.mark.parametrize( + "wires, expected", + [ + ([0], [[0.0, 0.5], [1.0, 0.5]]), + (None, [[0.0, 0.5], [0, 0], [0, 0.5], [1.0, 0]]), + ([0, 1], [[0.0, 0.5], [0, 0], [0, 0.5], [1.0, 0]]), + ], + ) + def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): + """Tests the estimate_probability method with a bin size""" + dev = qml.device("default.qubit.jax", wires=2) + samples = jnp.array([[1, 1], [1, 1], [1, 0], [0, 0]]) + bin_size = 2 + + with monkeypatch.context() as m: + m.setattr(dev, "_samples", samples) + res = dev.estimate_probability(wires=wires, bin_size=bin_size) + + assert np.allclose(res, expected) + + @pytest.mark.parametrize( + "wires, expected", + [ + ([0], [[0.0, 1.0], [0.5, 0.5], [0.25, 0.75]]), + (None, [[0, 0, 0.25, 0.75], [0.5, 0, 0, 0.5], [0.25, 0, 0.25, 0.5]]), + ([0, 1], [[0, 0, 0.25, 0.75], [0.5, 0, 0, 0.5], [0.25, 0, 0.25, 0.5]]), + ], + ) + def test_estimate_probability_with_broadcasting(self, wires, expected, monkeypatch): + """Tests the estimate_probability method with parameter broadcasting""" + dev = qml.device("default.qubit.jax", wires=2) + samples = jnp.array( + [ + [[1, 0], [1, 1], [1, 1], [1, 1]], + [[0, 0], [1, 1], [1, 1], [0, 0]], + [[1, 0], [1, 1], [1, 1], [0, 0]], + ] + ) + + with monkeypatch.context() as m: + m.setattr(dev, "_samples", samples) + res = dev.estimate_probability(wires=wires) + + assert np.allclose(res, expected) + + @pytest.mark.parametrize( + "wires, expected", + [ + ( + [0], + [ + [[0, 0, 0.5], [1, 1, 0.5]], + [[0.5, 0.5, 0], [0.5, 0.5, 1]], + [[0, 0.5, 1], [1, 0.5, 0]], + ], + ), + ( + None, + [ + [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], + [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], + [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], + ], + ), + ( + [0, 1], + [ + [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], + [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], + [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], + ], + ), + ], + ) + def test_estimate_probability_with_binsize_with_broadcasting( + self, wires, expected, monkeypatch + ): + """Tests the estimate_probability method with a bin size and parameter broadcasting""" + dev = qml.device("default.qubit.jax", wires=2) + bin_size = 2 + samples = jnp.array( + [ + [[1, 0], [1, 1], [1, 1], [1, 1], [1, 1], [0, 1]], + [[0, 0], [1, 1], [1, 1], [0, 0], [1, 1], [1, 1]], + [[1, 0], [1, 1], [1, 1], [0, 0], [0, 1], [0, 0]], + ] + ) + + with monkeypatch.context() as m: + m.setattr(dev, "_samples", samples) + res = dev.estimate_probability(wires=wires, bin_size=bin_size) + + assert np.allclose(res, expected) diff --git a/tests/devices/default_qubit_1/test_default_qubit_tf.py b/tests/devices/default_qubit_1/test_default_qubit_tf.py new file mode 100644 index 00000000000..67df09b3bc6 --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit_tf.py @@ -0,0 +1,2315 @@ +# Copyright 2018-2020 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 and integration tests for the ``default.qubit.tf`` device. +""" +# pylint: disable=too-many-arguments,protected-access,too-many-public-methods +import numpy as np +import pytest + +from gate_data import ( + I, + X, + Y, + Z, + H, + S, + T, + CNOT, + CZ, + CCZ, + SWAP, + Toffoli, + CSWAP, + Rphi, + Rotx, + Roty, + Rotz, + Rot3, + CRotx, + CRoty, + CRotz, + CRot3, + MultiRZ1, + MultiRZ2, + ControlledPhaseShift, + OrbitalRotation, + FermionicSWAP, +) + +import pennylane as qml +from pennylane import numpy as pnp +from pennylane import DeviceError + +tf = pytest.importorskip("tensorflow", minversion="2.0") +from pennylane.devices.default_qubit_tf import ( # pylint: disable=wrong-import-position + DefaultQubitTF, +) + +np.random.seed(42) + + +##################################################### +# Test matrices +##################################################### + +U = np.array( + [ + [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], + [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], + ] +) + +U2 = np.array([[0, 1, 1, 1], [1, 0, 1, -1], [1, -1, 0, 1], [1, 1, -1, 0]]) / np.sqrt(3) +A = np.array([[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]]) + + +##################################################### +# Define standard qubit operations +##################################################### + +single_qubit = [ + (qml.S, S), + (qml.T, T), + (qml.PauliX, X), + (qml.PauliY, Y), + (qml.PauliZ, Z), + (qml.Hadamard, H), +] +single_qubit_param = [ + (qml.PhaseShift, Rphi), + (qml.RX, Rotx), + (qml.RY, Roty), + (qml.RZ, Rotz), + (qml.MultiRZ, MultiRZ1), +] +two_qubit = [(qml.CZ, CZ), (qml.CNOT, CNOT), (qml.SWAP, SWAP)] +two_qubit_param = [ + (qml.CRX, CRotx), + (qml.CRY, CRoty), + (qml.CRZ, CRotz), + (qml.MultiRZ, MultiRZ2), + (qml.ControlledPhaseShift, ControlledPhaseShift), + (qml.FermionicSWAP, FermionicSWAP), +] +three_qubit = [(qml.Toffoli, Toffoli), (qml.CSWAP, CSWAP), (qml.CCZ, CCZ)] +four_qubit_param = [(qml.OrbitalRotation, OrbitalRotation)] + +##################################################### +# Fixtures +##################################################### + + +# pylint: disable=unused-argument +@pytest.fixture(name="init_state") +def init_state_fixture(scope="session"): + """Generates a random initial state""" + + def _init_state(n): + """random initial state""" + np.random.seed(4214152) + state = np.random.random([2**n]) + np.random.random([2**n]) * 1j + state /= np.linalg.norm(state) + return state + + return _init_state + + +# pylint: disable=unused-argument +@pytest.fixture(name="broadcasted_init_state") +def broadcasted_init_state_fixture(scope="session"): + """Generates a random initial state""" + + def _broadcasted_init_state(n, batch_size): + """random initial state""" + np.random.seed(4214152) + state = np.random.random([batch_size, 2**n]) + np.random.random([batch_size, 2**n]) * 1j + return state / np.linalg.norm(state, axis=1)[:, np.newaxis] + + return _broadcasted_init_state + + +##################################################### +# Initialization test +##################################################### + + +@pytest.mark.tf +def test_analytic_deprecation(): + """Tests if the kwarg `analytic` is used and displays error message.""" + msg = "The analytic argument has been replaced by shots=None. " + msg += "Please use shots=None instead of analytic=True." + + with pytest.raises( + DeviceError, + match=msg, + ): + qml.device("default.qubit.tf", wires=1, shots=1, analytic=True) + + +##################################################### +# Device-level matrix creation tests +##################################################### + + +@pytest.mark.tf +class TestTFMatrix: + """Test special case of matrix construction in TensorFlow for + cases where variables must be casted to complex.""" + + @pytest.mark.parametrize( + "op,params,wires", + [ + (qml.PhaseShift, [0.1], 0), + (qml.ControlledPhaseShift, [0.1], [0, 1]), + (qml.CRX, [0.1], [0, 1]), + (qml.CRY, [0.1], [0, 1]), + (qml.CRZ, [0.1], [0, 1]), + (qml.CRot, [0.1, 0.2, 0.3], [0, 1]), + (qml.U1, [0.1], 0), + (qml.U2, [0.1, 0.2], 0), + (qml.U3, [0.1, 0.2, 0.3], 0), + (qml.Rot, [0.1, 0.2, 0.3], 0), + ], + ) + def test_tf_matrix(self, op, params, wires): + tf_params = [tf.Variable(x) for x in params] + expected_mat = op(*params, wires=wires).matrix() + obtained_mat = op(*tf_params, wires=wires).matrix() + assert qml.math.get_interface(obtained_mat) == "tensorflow" + assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) + + @pytest.mark.parametrize( + "op,params,wires", + [ + (qml.PhaseShift, ([0.1, 0.2, 0.5],), 0), + (qml.ControlledPhaseShift, ([0.1],), [0, 1]), + (qml.CRX, ([0.1, -0.6, 0.2],), [0, 1]), + (qml.CRY, ([0.1, -0.4, 6.3],), [0, 1]), + (qml.CRZ, ([0.1, -0.6, 0.2],), [0, 1]), + (qml.CRot, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), [0, 1]), + (qml.U1, ([0.1, 0.2, 0.5],), 0), + (qml.U2, ([0.1, 0.2, 0.5], [0.6, 9.3, 2.1]), 0), + (qml.U3, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), 0), + (qml.Rot, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), 0), + ], + ) + def test_broadcasted_tf_matrix(self, op, params, wires): + params = [np.array(p) for p in params] + tf_params = [tf.Variable(x) for x in params] + expected_mat = op(*params, wires=wires).matrix() + obtained_mat = op(*tf_params, wires=wires).matrix() + assert qml.math.get_interface(obtained_mat) == "tensorflow" + assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) + + @pytest.mark.parametrize( + "param,pauli,wires", + [ + (0.1, "I", "a"), + (0.2, "IX", ["a", "b"]), + (-0.3, "III", [0, 1, 2]), + (0.5, "ZXI", [0, 1, 2]), + # Broadcasted rotations + ([0.1, 0.6], "I", "a"), + ([0.2], "IX", ["a", "b"]), + ([-0.3, 0.0, 0.2], "III", [0, 1, 2]), + ([0.5, 0.2], "ZXI", [0, 1, 2]), + ], + ) + def test_pauli_rot_tf_(self, param, pauli, wires): + param = np.array(param) + op = qml.PauliRot(param, pauli, wires=wires) + expected_mat = op.matrix() + expected_eigvals = op.eigvals() + + tf_op = qml.PauliRot(tf.Variable(param), pauli, wires=wires) + obtained_mat = tf_op.matrix() + obtained_eigvals = tf_op.eigvals() + + assert qml.math.get_interface(obtained_mat) == "tensorflow" + assert qml.math.get_interface(obtained_eigvals) == "tensorflow" + + assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) + assert qml.math.allclose(qml.math.unwrap(obtained_eigvals), expected_eigvals) + + @pytest.mark.parametrize( + "op,param,wires", + [ + (qml.PhaseShift, 0.1, [1]), + (qml.ControlledPhaseShift, 0.1, [1, 2]), + (qml.CRZ, 0.1, [1, 2]), + (qml.U1, 0.1, [1]), + # broadcasted operation matrices + (qml.PhaseShift, np.array([0.1, 0.6]), [1]), + (qml.ControlledPhaseShift, np.array([0.1]), [1, 2]), + (qml.CRZ, np.array([0.1, 0.7, 8.3]), [1, 2]), + (qml.U1, np.array([0.1, 0.7, 8.3]), [1]), + ], + ) + def test_expand_tf_matrix(self, op, param, wires): + reg_mat = op(param, wires=wires).matrix() + + if len(wires) == 1: + expected_mat = qml.math.kron(I, qml.math.kron(reg_mat, qml.math.kron(I, I))) + else: + expected_mat = qml.math.kron(I, qml.math.kron(reg_mat, I)) + + tf_mat = op(tf.Variable(param), wires=wires).matrix() + obtained_mat = qml.math.expand_matrix(tf_mat, wires, list(range(4))) + + assert qml.math.get_interface(obtained_mat) == "tensorflow" + assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) + + +##################################################### +# Device-level integration tests +##################################################### + + +@pytest.mark.tf +class TestApply: + """Test application of PennyLane operations.""" + + def test_basis_state(self, tol): + """Test basis state initialization""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 0]) + + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + res = dev.state + expected = np.zeros([2**4]) + expected[np.ravel_multi_index(state, [2] * 4)] = 1 + + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_invalid_basis_state_length(self): + """Test that an exception is raised if the basis state is the wrong size""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 0]) + + with pytest.raises( + ValueError, match=r"BasisState parameter and wires must be of equal length" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) + + def test_invalid_basis_state(self): + """Test that an exception is raised if the basis state is invalid""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 2]) + + with pytest.raises( + ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + def test_qubit_state_vector(self, init_state, tol): + """Test qubit state vector application""" + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + res = dev.state + expected = state + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_full_subsystem_statevector(self, mocker): + """Test applying a state vector to the full subsystem""" + dev = DefaultQubitTF(wires=["a", "b", "c"]) + state = tf.constant([1, 0, 0, 0, 1, 0, 1, 1], dtype=tf.complex128) / 2.0 + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(tf.reshape(dev._state, [-1]) == state) + spy.assert_not_called() + + def test_partial_subsystem_statevector(self, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + dev = DefaultQubitTF(wires=["a", "b", "c"]) + state = tf.constant([1, 0, 1, 0], dtype=tf.complex128) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = tf.reshape(tf.reduce_sum(dev._state, axis=(1,)), [-1]) + + assert np.all(res == state) + spy.assert_called() + + def test_invalid_qubit_state_vector_size(self): + """Test that an exception is raised if the state + vector is the wrong size""" + dev = DefaultQubitTF(wires=2) + state = np.array([0, 1]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): + dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) + + def test_invalid_qubit_state_vector_norm(self): + """Test that an exception is raised if the state + vector is not normalized""" + dev = DefaultQubitTF(wires=2) + state = np.array([0, 12]) + + with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + def test_invalid_state_prep(self): + """Test that an exception is raised if a state preparation is not the + first operation in the circuit.""" + dev = DefaultQubitTF(wires=2) + state = np.array([0, 1]) + + with pytest.raises( + qml.DeviceError, + match=r"cannot be used after other Operations have already been applied", + ): + dev.apply([qml.PauliZ(0), qml.QubitStateVector(state, wires=[0])]) + + @pytest.mark.parametrize("op,mat", single_qubit) + def test_single_qubit_no_parameters(self, init_state, op, mat, tol): + """Test non-parametrized single qubit operations""" + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(wires=0)] + dev.apply(queue) + + res = dev.state + expected = mat @ state + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters(self, init_state, op, func, theta, tol): + """Test parametrized single qubit operations""" + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(theta, wires=0)] + dev.apply(queue) + + res = dev.state + expected = func(theta) @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation(self, init_state, tol): + """Test three axis rotation gate""" + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + a = 0.542 + b = 1.3432 + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + expected = Rot3(a, b, c) @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation(self, init_state, tol): + """Test three axis controlled-rotation gate""" + dev = DefaultQubitTF(wires=2) + state = init_state(2) + + a = 0.542 + b = 1.3432 + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = CRot3(a, b, c) @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op,mat", two_qubit) + def test_two_qubit_no_parameters(self, init_state, op, mat, tol): + """Test non-parametrized two qubit operations""" + dev = DefaultQubitTF(wires=2) + state = init_state(2) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = mat @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary(self, init_state, mat, tol): + """Test application of arbitrary qubit unitaries""" + N = int(np.log2(len(mat))) + dev = DefaultQubitTF(wires=N) + state = init_state(N) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = mat @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op, mat", three_qubit) + def test_three_qubit_no_parameters(self, init_state, op, mat, tol): + """Test non-parametrized three qubit operations""" + dev = DefaultQubitTF(wires=3) + state = init_state(3) + + queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] + queue += [op(wires=[0, 1, 2])] + dev.apply(queue) + + res = dev.state + expected = mat @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", two_qubit_param) + def test_two_qubit_parameters(self, init_state, op, func, theta, tol): + """Test two qubit parametrized operations""" + dev = DefaultQubitTF(wires=2) + state = init_state(2) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(theta, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = func(theta) @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", four_qubit_param) + def test_four_qubit_parameters(self, init_state, op, func, theta, tol): + """Test four qubit parametrized operations""" + dev = DefaultQubitTF(wires=4) + state = init_state(4) + + queue = [qml.QubitStateVector(state, wires=[0, 1, 2, 3])] + queue += [op(theta, wires=[0, 1, 2, 3])] + dev.apply(queue) + + res = dev.state + expected = func(theta) @ state + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_apply_ops_not_supported(self, mocker, monkeypatch): + """Test that when a version of TensorFlow before 2.3.0 is used, the _apply_ops dictionary is + empty and application of a CNOT gate is performed using _apply_unitary_einsum""" + with monkeypatch.context() as m: + m.setattr("pennylane.devices.default_qubit_tf.SUPPORTS_APPLY_OPS", False) + dev = DefaultQubitTF(wires=3) + assert dev._apply_ops == {} + + spy = mocker.spy(DefaultQubitTF, "_apply_unitary_einsum") + + queue = [qml.CNOT(wires=[1, 2])] + dev.apply(queue) + + spy.assert_called_once() + + def test_apply_ops_above_8_wires(self, mocker): + """Test that when 9 wires are used, the _apply_ops dictionary is empty and application of a + CNOT gate is performed using _apply_unitary_einsum""" + dev = DefaultQubitTF(wires=9) + assert dev._apply_ops == {} + + spy = mocker.spy(DefaultQubitTF, "_apply_unitary_einsum") + + queue = [qml.CNOT(wires=[1, 2])] + dev.apply(queue) + + spy.assert_called_once() + + @pytest.mark.xfail( + raises=tf.errors.UnimplementedError, + reason="Slicing is not supported for more than 8 wires", + strict=True, + ) + def test_apply_ops_above_8_wires_using_special(self): + """Test that special apply methods that involve slicing function correctly when using 9 + wires""" + dev = DefaultQubitTF(wires=9) + dev._apply_ops = {"CNOT": dev._apply_cnot} + + queue = [qml.CNOT(wires=[1, 2])] + dev.apply(queue) + + def test_do_not_split_analytic_tf(self, mocker): + """Tests that the Hamiltonian is not split for shots=None using the tf device.""" + dev = qml.device("default.qubit.tf", wires=2) + ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(): + return qml.expval(ham) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + +@pytest.mark.tf +class TestApplyBroadcasted: + """Test application of broadcasted PennyLane operations.""" + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_basis_state_broadcasted(self, tol): + """Test basis state initialization""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 0]) + + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + res = dev.state + expected = np.zeros([2**4]) + expected[np.ravel_multi_index(state, [2] * 4)] = 1 + + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_invalid_basis_state_length_broadcasted(self): + """Test that an exception is raised if the basis state is the wrong size""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 0]) + + with pytest.raises( + ValueError, match=r"BasisState parameter and wires must be of equal length" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_invalid_basis_state_broadcasted(self): + """Test that an exception is raised if the basis state is invalid""" + dev = DefaultQubitTF(wires=4) + state = np.array([0, 0, 1, 2]) + + with pytest.raises( + ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + @pytest.mark.parametrize("batch_size", [1, 3]) + def test_qubit_state_vector_broadcasted(self, broadcasted_init_state, tol, batch_size): + """Test broadcasted qubit state vector application""" + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, batch_size=batch_size) + + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + res = dev.state + expected = state + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_full_subsystem_statevector_broadcasted(self, mocker): + """Test applying a broadcasted state vector to the full subsystem""" + dev = DefaultQubitTF(wires=["a", "b", "c"]) + state = ( + tf.constant( + [[1, 0, 0, 0, 1, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 1]], + dtype=tf.complex128, + ) + / 2 + ) + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert np.all(tf.reshape(dev._state, [3, 8]) == state) + spy.assert_not_called() + + def test_error_partial_subsystem_statevector_broadcasted(self): + """Test applying a broadcasted state vector to a subset of wires of the full subsystem""" + dev = DefaultQubitTF(wires=["a", "b", "c"]) + state = tf.constant( + [[1, 0, 1, 0], [1, 1, 0, 0], [0, 1, 1, 0]], dtype=tf.complex128 + ) / np.sqrt(2.0) + state_wires = qml.wires.Wires(["a", "c"]) + + with pytest.raises(NotImplementedError, match="Parameter broadcasting is not supported"): + dev._apply_state_vector(state=state, device_wires=state_wires) + + def test_invalid_qubit_state_vector_size_broadcasted(self): + """Test that an exception is raised if the broadcasted state + vector is the wrong size""" + dev = DefaultQubitTF(wires=2) + state = np.array([[0, 1], [1, 0], [1, 1], [0, 0]]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): + dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) + + def test_invalid_qubit_state_vector_norm_broadcasted(self): + """Test that an exception is raised if the broadcasted state + vector is not normalized""" + dev = DefaultQubitTF(wires=2) + state = np.array([[1, 0], [0, 12], [1.3, 1]]) + + with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + @pytest.mark.parametrize("op,mat", single_qubit) + def test_single_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): + """Test non-parametrized single qubit operations""" + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, 3) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(wires=0)] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,kj->ki", mat, state) + assert isinstance(res, tf.Tensor) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_state( + self, broadcasted_init_state, op, func, theta, tol + ): + """Test parametrized single qubit operations with broadcasted initial state""" + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, 3) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(theta, wires=0)] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,kj->ki", func(theta), state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_par(self, init_state, op, func, theta, tol): + """Test parametrized single qubit operations with broadcasted parameters""" + theta = np.array(theta) + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(theta, wires=0)] + dev.apply(queue) + + res = dev.state + mat = np.array([func(t) for t in theta]) + expected = np.einsum("lij,j->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_both( + self, broadcasted_init_state, op, func, theta, tol + ): + """Test parametrized single qubit operations with broadcasted init state and parameters""" + theta = np.array(theta) + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, batch_size=len(theta)) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(theta, wires=0)] + dev.apply(queue) + + res = dev.state + mat = np.array([func(t) for t in theta]) + expected = np.einsum("lij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_state(self, broadcasted_init_state, tol): + """Test three axis rotation gate with broadcasted state""" + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, 3) + + a = 0.542 + b = 1.3432 + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,lj->li", Rot3(a, b, c), state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_par(self, init_state, tol): + """Test three axis rotation gate with broadcasted parameters""" + dev = DefaultQubitTF(wires=1) + state = init_state(1) + + a = np.array([0.542, 0.96, 0.213]) + b = -0.654 + c = np.array([1.3432, 0.6324, 6.32]) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + mat = np.array([Rot3(_a, b, _c) for _a, _c in zip(a, c)]) + expected = np.einsum("lij,j->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_both(self, broadcasted_init_state, tol): + """Test three axis rotation gate with broadcasted state and parameters""" + dev = DefaultQubitTF(wires=1) + state = broadcasted_init_state(1, 3) + + a = np.array([0.542, 0.96, 0.213]) + b = np.array([1.3432, 0.6324, 6.32]) + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + mat = np.array([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) + expected = np.einsum("lij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_state(self, broadcasted_init_state, tol): + """Test controlled three axis rotation gate with broadcasted state""" + dev = DefaultQubitTF(wires=2) + state = broadcasted_init_state(2, 3) + + a = 0.542 + b = 1.3432 + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,lj->li", CRot3(a, b, c), state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_par(self, init_state, tol): + """Test controlled three axis rotation gate with broadcasted parameters""" + dev = DefaultQubitTF(wires=2) + state = init_state(2) + + a = np.array([0.542, 0.96, 0.213]) + b = -0.654 + c = np.array([1.3432, 0.6324, 6.32]) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + mat = np.array([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) + expected = np.einsum("lij,j->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_both(self, broadcasted_init_state, tol): + """Test controlled three axis rotation gate with broadcasted state and parameters""" + dev = DefaultQubitTF(wires=2) + state = broadcasted_init_state(2, 3) + + a = np.array([0.542, 0.96, 0.213]) + b = np.array([1.3432, 0.6324, 6.32]) + c = -0.654 + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + mat = np.array([CRot3(_a, _b, c) for _a, _b in zip(a, b)]) + expected = np.einsum("lij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op,mat", two_qubit) + def test_two_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): + """Test non-parametrized two qubit operations""" + dev = DefaultQubitTF(wires=2) + state = broadcasted_init_state(2, 3) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_state(self, broadcasted_init_state, mat, tol): + """Test application of arbitrary qubit unitaries for broadcasted state""" + N = int(np.log2(len(mat))) + dev = DefaultQubitTF(wires=N) + state = broadcasted_init_state(N, 3) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_par(self, init_state, mat, tol): + """Test application of broadcasted arbitrary qubit unitaries""" + mat = np.array([mat, mat, mat]) + N = int(np.log2(mat.shape[-1])) + dev = DefaultQubitTF(wires=N) + state = init_state(N) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = np.einsum("lij,j->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_both(self, broadcasted_init_state, mat, tol): + """Test application of arbitrary qubit unitaries for broadcasted state and parameters""" + mat = np.array([mat, mat, mat]) + N = int(np.log2(mat.shape[-1])) + dev = DefaultQubitTF(wires=N) + state = broadcasted_init_state(N, 3) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = np.einsum("lij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op, mat", three_qubit) + def test_three_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): + """Test broadcasted non-parametrized three qubit operations""" + dev = DefaultQubitTF(wires=3) + state = broadcasted_init_state(3, 2) + + queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] + queue += [op(wires=[0, 1, 2])] + dev.apply(queue) + + res = dev.state + expected = np.einsum("ij,lj->li", mat, state) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_direct_eval_hamiltonian_broadcasted_error_tf(self): + """Tests that an error is raised when attempting to evaluate a Hamiltonian with + broadcasting and shots=None directly via its sparse representation with TF.""" + dev = qml.device("default.qubit.tf", wires=2) + ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(): + qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity + return qml.expval(ham) + + with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): + circuit() + + +THETA = np.linspace(0.11, 1, 3) +PHI = np.linspace(0.32, 1, 3) +VARPHI = np.linspace(0.02, 1, 3) + +scalar_angles = list(zip(THETA, PHI, VARPHI)) +broadcasted_angles = [(THETA, PHI, VARPHI), (THETA[0], PHI, VARPHI)] +all_angles = scalar_angles + broadcasted_angles + + +# pylint: disable=unused-argument +@pytest.mark.tf +@pytest.mark.parametrize("theta, phi, varphi", all_angles) +class TestExpval: + """Test expectation values""" + + # test data; each tuple is of the form (GATE, OBSERVABLE, EXPECTED) + single_wire_expval_test_data = [ + ( + qml.RX, + qml.Identity, + lambda t, p: np.array( + [np.ones_like(t) * np.ones_like(p), np.ones_like(t) * np.ones_like(p)] + ), + ), + ( + qml.RX, + qml.PauliZ, + lambda t, p: np.array([np.cos(t) * np.ones_like(p), np.cos(t) * np.cos(p)]), + ), + ( + qml.RY, + qml.PauliX, + lambda t, p: np.array([np.sin(t) * np.sin(p), np.sin(p) * np.ones_like(t)]), + ), + ( + qml.RX, + qml.PauliY, + lambda t, p: np.array([np.zeros_like(t) * np.zeros_like(p), -np.cos(t) * np.sin(p)]), + ), + ( + qml.RY, + qml.Hadamard, + lambda t, p: np.array( + [np.sin(t) * np.sin(p) + np.cos(t), np.cos(t) * np.cos(p) + np.sin(p)] + ) + / np.sqrt(2), + ), + ] + + @pytest.mark.parametrize("gate,obs,expected", single_wire_expval_test_data) + def test_single_wire_expectation(self, gate, obs, expected, theta, phi, varphi, tol): + """Test that identity expectation value (i.e. the trace) is 1""" + dev = DefaultQubitTF(wires=2) + + with qml.queuing.AnnotatedQueue() as q: + _ = [gate(theta, wires=0), gate(phi, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(obs(wires=[i])) for i in range(2)] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + assert np.allclose(res, expected(theta, phi), atol=tol, rtol=0) + + def test_hermitian_expectation(self, theta, phi, varphi, tol): + """Test that arbitrary Hermitian expectation values are correct""" + dev = DefaultQubitTF(wires=2) + + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(qml.Hermitian(A, wires=[i])) for i in range(2)] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + ev1 = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + ev2 = ((a - d) * np.cos(theta) * np.cos(phi) + 2 * re_b * np.sin(phi) + a + d) / 2 + expected = np.array([ev1, ev2]) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_multi_mode_hermitian_expectation(self, theta, phi, varphi, tol): + """Test that arbitrary multi-mode Hermitian expectation values are correct""" + _A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + dev = DefaultQubitTF(wires=2) + + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(qml.Hermitian(_A, wires=[0, 1]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + + # below is the analytic expectation value for this circuit with arbitrary + # Hermitian observable A + expected = 0.5 * ( + 6 * np.cos(theta) * np.sin(phi) + - np.sin(theta) * (8 * np.sin(phi) + 7 * np.cos(phi) + 3) + - 2 * np.sin(phi) + - 6 * np.cos(phi) + - 6 + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_paulix_pauliy(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + dev.reset() + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_identity(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and Identity works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + dev.reset() + + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = np.cos(varphi) * np.cos(phi) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + dev.reset() + + _A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(_A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.5 * ( + -6 * np.cos(theta) * (np.cos(varphi) + 1) + - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) + + 3 * np.cos(varphi) * np.sin(phi) + + np.sin(phi) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving two Hermitian matrices works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + + A1 = np.array([[1, 2], [2, 4]]) + + A2 = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.25 * ( + -30 + + 4 * np.cos(phi) * np.sin(theta) + + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) + - 3 * np.sin(phi) + - 2 + * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) + * np.sin(varphi) + + np.cos(theta) + * ( + 18 + + 5 * np.sin(phi) + + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) + + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) + ) + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" + dev = qml.device("default.qubit.tf", wires=2) + + obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" + dev = qml.device("default.qubit.tf", wires=3, shots=None) + Identity = np.array([[1, 0], [0, 1]]) + ham = np.kron(np.kron(Identity, Identity), A) + obs = qml.Hermitian(ham, wires=[2, 1, 0]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + + expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.tf +@pytest.mark.parametrize("theta, phi, varphi", all_angles) +class TestVar: + """Tests for the variance""" + + def test_var(self, theta, phi, varphi, tol): + """Tests for variance calculation""" + dev = DefaultQubitTF(wires=1) + # test correct variance for of a rotated state + + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] + _ = [qml.var(qml.PauliZ(wires=[0]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi)) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_var_hermitian(self, theta, phi, varphi, tol): + """Tests for variance calculation using an arbitrary Hermitian observable""" + dev = DefaultQubitTF(wires=2) + + # test correct variance for of a rotated state + ham = np.array([[4, -1 + 6j], [-1 - 6j, 2]]) + + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] + _ = [qml.var(qml.Hermitian(ham, wires=[0]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + expected = 0.5 * ( + 2 * np.sin(2 * theta) * np.cos(phi) ** 2 + + 24 * np.sin(phi) * np.cos(phi) * (np.sin(theta) - np.cos(theta)) + + 35 * np.cos(2 * phi) + + 39 + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_paulix_pauliy(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 + - np.cos(2 * (theta - phi)) + - np.cos(2 * (theta + phi)) + + 2 * np.cos(2 * theta) + + 2 * np.cos(2 * phi) + + 14 + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 3 + + np.cos(2 * phi) * np.cos(varphi) ** 2 + - np.cos(2 * theta) * np.sin(varphi) ** 2 + - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) + ) / 4 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = qml.device("default.qubit.tf", wires=3) + + _A = np.array( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ] + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(_A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 1057 + - np.cos(2 * phi) + + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) + - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) + + 16 * np.sin(2 * phi) + - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) + - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 + - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) + - 8 + * np.cos(theta) + * ( + 4 + * np.cos(phi) + * ( + 4 + + 8 * np.cos(varphi) + + np.cos(2 * varphi) + - (1 + 6 * np.cos(varphi)) * np.sin(varphi) + ) + + np.sin(phi) + * ( + 15 + + 8 * np.cos(varphi) + - 11 * np.cos(2 * varphi) + + 42 * np.sin(varphi) + + 3 * np.sin(2 * varphi) + ) + ) + ) / 16 + + assert np.allclose(res, expected, atol=tol, rtol=0) + + +##################################################### +# QNode-level integration tests +##################################################### + + +@pytest.mark.tf +class TestQNodeIntegration: + """Integration tests for default.qubit.tf. This test ensures it integrates + properly with the PennyLane UI, in particular the new QNode.""" + + def test_defines_correct_capabilities(self): + """Test that the device defines the right capabilities""" + + dev = qml.device("default.qubit.tf", wires=1) + cap = dev.capabilities() + capabilities = { + "model": "qubit", + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "returns_state": True, + "supports_inverse_operations": True, + "supports_analytic_computation": True, + "supports_broadcasting": True, + "passthru_interface": "tf", + "passthru_devices": { + "torch": "default.qubit.torch", + "tf": "default.qubit.tf", + "autograd": "default.qubit.autograd", + "jax": "default.qubit.jax", + }, + } + assert cap == capabilities + + def test_load_tensornet_tf_device(self): + """Test that the tensor network plugin loads correctly""" + dev = qml.device("default.qubit.tf", wires=2) + assert dev.num_wires == 2 + assert dev.shots is None + assert dev.short_name == "default.qubit.tf" + assert dev.capabilities()["passthru_interface"] == "tf" + + def test_qubit_circuit(self, tol): + """Test that the tensor network plugin provides correct + result for a simple circuit using the old QNode.""" + p = tf.Variable(0.543) + + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -tf.math.sin(p) + + assert circuit.gradient_fn == "backprop" + assert np.isclose(circuit(p), expected, atol=tol, rtol=0) + + def test_qubit_circuit_broadcasted(self, tol): + """Test that the tensor network plugin provides correct + result for a simple circuit with broadcasting using the old QNode.""" + p = tf.Variable([0.543, 0.21, 2.41]) + + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -tf.math.sin(p) + + assert circuit.gradient_fn == "backprop" + assert np.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_correct_state(self, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + + dev = qml.device("default.qubit.tf", wires=2) + + state = dev.state + expected = np.array([1, 0, 0, 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(np.pi / 4, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + amplitude = np.exp(-1j * np.pi / 8) / np.sqrt(2) + + expected = np.array([amplitude, 0, np.conj(amplitude), 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_broadcasted(self, tol): + """Test that the device state is correct after applying a + broadcasted quantum function on the device""" + + dev = qml.device("default.qubit.tf", wires=2) + + state = dev.state + expected = np.array([1, 0, 0, 0]) + assert np.allclose(state, expected, atol=tol, rtol=0) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(tf.constant([np.pi / 4, np.pi / 2]), wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + phase = np.exp(-1j * np.pi / 8) + + expected = np.array( + [ + [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], + [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], + ] + ) + assert np.allclose(state, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_one_qubit_param_gates(self, theta, op, func, init_state, tol): + """Test the integration of the one-qubit single parameter rotations by passing + a TF data structure as a parameter""" + dev = qml.device("default.qubit.tf", wires=1) + state = init_state(1) + + @qml.qnode(dev, interface="tf") + def circuit(params): + qml.QubitStateVector(state, wires=[0]) + op(params[0], wires=[0]) + return qml.expval(qml.PauliZ(0)) + + # Pass a TF Variable to the qfunc + params = tf.Variable(np.array([theta])) + circuit(params) + res = dev.state + expected = func(theta) @ state + assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, 4.213]) + @pytest.mark.parametrize("op,func", two_qubit_param) + def test_two_qubit_param_gates(self, theta, op, func, init_state, tol): + """Test the integration of the two-qubit single parameter rotations by passing + a TF data structure as a parameter""" + dev = qml.device("default.qubit.tf", wires=2) + state = init_state(2) + + @qml.qnode(dev, interface="tf") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1]) + op(params[0], wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + # Pass a TF Variable to the qfunc + params = tf.Variable(np.array([theta])) + circuit(params) + res = dev.state + expected = func(theta) @ state + assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, 4.213]) + @pytest.mark.parametrize("op,func", four_qubit_param) + def test_four_qubit_param_gates(self, theta, op, func, init_state, tol): + """Test the integration of the four-qubit single parameter rotations by passing + a TF data structure as a parameter""" + dev = qml.device("default.qubit.tf", wires=4) + state = init_state(4) + + @qml.qnode(dev, interface="tf") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1, 2, 3]) + op(params[0], wires=[0, 1, 2, 3]) + return qml.expval(qml.PauliZ(0)) + + # Pass a TF Variable to the qfunc + params = tf.Variable(np.array([theta])) + circuit(params) + res = dev.state + expected = func(theta) @ state + assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) + + def test_controlled_rotation_integration(self, init_state, tol): + """Test the integration of the two-qubit controlled rotation by passing + a TF data structure as a parameter""" + dev = qml.device("default.qubit.tf", wires=2) + a = 1.7 + b = 1.3432 + c = -0.654 + state = init_state(2) + + @qml.qnode(dev, interface="tf") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1]) + qml.CRot(params[0], params[1], params[2], wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + # Pass a TF Variable to the qfunc + params = tf.Variable(np.array([a, b, c])) + circuit(params) + res = dev.state + expected = CRot3(a, b, c) @ state + assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) + + +@pytest.mark.tf +class TestPassthruIntegration: + """Tests for integration with the PassthruQNode""" + + def test_jacobian_variable_multiply(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.tf device + gives the correct result in the case of parameters multiplied by scalars""" + x = tf.Variable(0.43316321) + y = tf.Variable(0.2162158) + z = tf.Variable(0.75110998) + + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + with tf.GradientTape() as tape: + res = circuit([x, y, z]) + + expected = tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - tf.math.sin( + 3 * x + ) * tf.math.sin(z / 2) + assert np.allclose(res, expected, atol=tol, rtol=0) + + res = tf.stack(tape.jacobian(res, [x, y, z]), axis=0) + + expected = np.array( + [ + -3 + * ( + tf.math.sin(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) + + tf.math.cos(3 * x) * tf.math.sin(z / 2) + ), + -tf.math.cos(3 * x) * tf.math.sin(y) * tf.math.cos(z / 2), + -0.5 + * ( + tf.math.sin(3 * x) * tf.math.cos(z / 2) + + tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.sin(z / 2) + ), + ] + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_variable_multiply_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.tf device + gives the correct result in the case of broadcasted parameters multiplied by scalars""" + x = tf.Variable([0.43316321, 92.1, -0.5129]) + y = tf.Variable([0.2162158, 0.241, -0.51]) + z = tf.Variable([0.75110998, 0.12512, 9.12]) + + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + with tf.GradientTape() as tape: + res = circuit([x, y, z]) + + expected = tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - tf.math.sin( + 3 * x + ) * tf.math.sin(z / 2) + assert qml.math.shape(res) == (3,) + assert np.allclose(res, expected, atol=tol, rtol=0) + + jac = tape.jacobian(res, [x, y, z]) + res = qml.math.stack([qml.math.diag(j.numpy()) for j in jac]) + + expected = np.array( + [ + -3 + * ( + tf.math.sin(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) + + tf.math.cos(3 * x) * tf.math.sin(z / 2) + ), + -tf.math.cos(3 * x) * tf.math.sin(y) * tf.math.cos(z / 2), + -0.5 + * ( + tf.math.sin(3 * x) * tf.math.cos(z / 2) + + tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.sin(z / 2) + ), + ] + ) + + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_repeated(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.tf device + gives the correct result in the case of repeated parameters""" + x = 0.43316321 + y = 0.2162158 + z = 0.75110998 + p = tf.Variable([x, y, z]) + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + with tf.GradientTape() as tape: + res = circuit(p) + + expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + res = tape.jacobian(res, p) + + expected = np.array( + [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0] + ) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_jacobian_repeated_broadcasted(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.tf device + gives the correct result in the case of repeated broadcasted parameters""" + x = tf.Variable([0.433, 92.1, -0.512]) + y = tf.Variable([0.218, 0.241, -0.51]) + z = tf.Variable([0.71, 0.152, 9.12]) + p = tf.Variable([x, y, z]) + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + with tf.GradientTape() as tape: + res = circuit(p) + + expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + res = tape.jacobian(res, p) + + expected = np.array( + [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0 * x] + ) + assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + def test_backprop_jacobian_agrees_parameter_shift(self, tol): + """Test that jacobian of a QNode with an attached default.qubit.tf device + gives the correct result with respect to the parameter-shift method""" + p = pnp.array([0.43316321, 0.2162158, 0.75110998, 0.94714242]) + p_tf = tf.Variable(p, trainable=True) + + def circuit(x): + for i in range(0, len(p), 2): + qml.RX(x[i], wires=0) + qml.RY(x[i + 1], wires=1) + for i in range(2): + qml.CNOT(wires=[i, i + 1]) + return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) + + dev1 = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=3) + + def cost(x): + return qml.math.stack(circuit(x)) + + circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="tf") + circuit2 = qml.QNode(cost, dev2, diff_method="parameter-shift") + + with tf.GradientTape() as tape: + res = tf.experimental.numpy.hstack(circuit1(p_tf)) + + assert np.allclose(res, circuit2(p), atol=tol, rtol=0) + + assert circuit1.gradient_fn == "backprop" + assert circuit2.gradient_fn is qml.gradients.param_shift + + res = tape.jacobian(res, p_tf) + assert np.allclose(res, qml.jacobian(circuit2)(p), atol=tol, rtol=0) + + @pytest.mark.parametrize("wires", [[0], ["abc"]]) + def test_state_differentiability(self, wires, tol): + """Test that the device state can be differentiated""" + dev = qml.device("default.qubit.tf", wires=wires) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a): + qml.RY(a, wires=wires[0]) + return qml.state() + + a = tf.Variable(0.54) + + with tf.GradientTape() as tape: + res = tf.abs(circuit(a)) ** 2 + res = res[1] - res[0] + + grad = tape.gradient(res, a) + expected = tf.sin(a) + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_state_differentiability_broadcasted(self, tol): + """Test that the broadcasted device state can be differentiated""" + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a): + qml.RY(a, wires=0) + return qml.expval(qml.PauliZ(0)) + + a = tf.Variable([0.54, 0.32, 1.2]) + + with tf.GradientTape() as tape: + circuit(a) + res = tf.abs(dev.state) ** 2 + res = res[:, 1] - res[:, 0] + + jac = tape.jacobian(res, a) + expected = tf.sin(a) + assert np.allclose(qml.math.diag(jac.numpy()), expected, atol=tol, rtol=0) + + def test_prob_differentiability(self, tol): + """Test that the device probability can be differentiated""" + dev = qml.device("default.qubit.tf", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = tf.Variable(0.54) + b = tf.Variable(0.12) + + with tf.GradientTape() as tape: + # 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] # pylint:disable=unsubscriptable-object + + expected = -tf.cos(a) * tf.cos(b) + assert np.allclose(res, expected, atol=tol, rtol=0) + + grad = tape.gradient(res, [a, b]) + expected = [tf.sin(a) * tf.cos(b), tf.cos(a) * tf.sin(b)] + assert np.allclose(grad, expected, atol=tol, rtol=0) + + def test_prob_differentiability_broadcasted(self, tol): + """Test that the broadcasted device probability can be differentiated""" + dev = qml.device("default.qubit.tf", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = tf.Variable([0.54, 0.32, 1.2]) + b = tf.Variable(0.12) + + with tf.GradientTape() as tape: + # 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] # pylint:disable=unsubscriptable-object + + expected = -tf.cos(a) * tf.cos(b) + assert np.allclose(res, expected, atol=tol, rtol=0) + + jac = tape.jacobian(res, [a, b]) + expected = [tf.sin(a) * tf.cos(b), tf.cos(a) * tf.sin(b)] + assert np.allclose(qml.math.diag(jac[0].numpy()), expected[0]) + assert np.allclose(jac[1], expected[1]) + + def test_backprop_gradient(self, tol): + """Tests that the gradient of the qnode is correct""" + # pylint:disable=no-member + dev = qml.device("default.qubit.tf", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = -0.234 + b = 0.654 + + a_tf = tf.Variable(a, dtype=tf.float64) + b_tf = tf.Variable(b, dtype=tf.float64) + + with tf.GradientTape() as tape: + tape.watch([a_tf, b_tf]) + res = circuit(a_tf, b_tf) + + # the analytic result of evaluating circuit(a, b) + expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) + + # the analytic result of evaluating grad(circuit(a, b)) + expected_grad = np.array( + [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] + ) + + assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) + + res = tape.gradient(res, [a_tf, b_tf]) + assert np.allclose(res, expected_grad, atol=tol, rtol=0) + + def test_backprop_gradient_broadcasted(self, tol): + """Tests that the gradient of the broadcasted qnode is correct""" + # pylint:disable=no-member + dev = qml.device("default.qubit.tf", wires=2) + + @qml.qnode(dev, diff_method="backprop", interface="tf") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = np.array(0.12) + b = np.array([0.54, 0.32, 1.2]) + + a_tf = tf.Variable(a, dtype=tf.float64) + b_tf = tf.Variable(b, dtype=tf.float64) + + with tf.GradientTape() as tape: + tape.watch([a_tf, b_tf]) + res = circuit(a_tf, b_tf) + + # the analytic result of evaluating circuit(a, b) + expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) + + # the analytic result of evaluating grad(circuit(a, b)) + expected_jac = np.array( + [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] + ) + + assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) + + jac = tape.jacobian(res, [a_tf, b_tf]) + assert np.allclose(jac[0], expected_jac[0], atol=tol, rtol=0) + assert np.allclose(qml.math.diag(jac[1].numpy()), expected_jac[1], atol=tol, rtol=0) + + @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) + def test_hessian_at_zero(self, x, shift): + """Tests that the Hessian at vanishing state vector amplitudes + is correct.""" + dev = qml.device("default.qubit.tf", wires=1) + + shift = tf.constant(shift) + x = tf.Variable(x) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(x): + qml.RY(shift, wires=0) + qml.RY(x, wires=0) + return qml.expval(qml.PauliZ(0)) + + with tf.GradientTape(persistent=True) as t2: + with tf.GradientTape(persistent=True) as t1: + value = circuit(x) + grad = t1.gradient(value, x) + jac = t1.jacobian(value, x) + hess_grad = t2.gradient(grad, x) + hess_jac = t2.jacobian(jac, x) + + assert qml.math.isclose(grad, 0.0) + assert qml.math.isclose(hess_grad, -1.0) + assert qml.math.isclose(hess_jac, -1.0) + + @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) + @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) + def test_tf_interface_gradient(self, operation, diff_method, tol): + """Tests that the gradient of an arbitrary U3 gate is correct + using the TensorFlow interface, using a variety of differentiation methods.""" + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, diff_method=diff_method, interface="tf") + def circuit(x, weights, w): + """In this example, a mixture of scalar + arguments, array arguments, and keyword arguments are used.""" + qml.QubitStateVector(1j * np.array([1, -1]) / np.sqrt(2), wires=w) + operation(x, weights[0], weights[1], wires=w) + return qml.expval(qml.PauliX(w)) + + # Check that the correct QNode type is being used. + if diff_method == "backprop": + assert circuit.gradient_fn == "backprop" + elif diff_method == "parameter-shift": + assert circuit.gradient_fn is qml.gradients.param_shift + elif diff_method == "finite-diff": + assert circuit.gradient_fn is qml.gradients.finite_diff + + def cost(params): + """Perform some classical processing""" + return circuit(params[0], params[1:], w=0) ** 2 + + theta = 0.543 + phi = -0.234 + lam = 0.654 + + params = tf.Variable([theta, phi, lam], dtype=tf.float64) + + with tf.GradientTape() as tape: + tape.watch(params) + res = cost(params) + + # check that the result is correct + expected_cost = (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) ** 2 + assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) + + res = tape.gradient(res, params) + + # check that the gradient is correct + expected_grad = ( + np.array( + [ + np.sin(theta) * np.cos(lam) * np.cos(phi), + np.cos(theta) * np.cos(lam) * np.sin(phi) + np.sin(lam) * np.cos(phi), + np.cos(theta) * np.sin(lam) * np.cos(phi) + np.cos(lam) * np.sin(phi), + ] + ) + * 2 + * (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) + ) + assert np.allclose(res.numpy(), expected_grad, atol=tol, rtol=0) + + @pytest.mark.parametrize("interface", ["autograd", "torch"]) + def test_error_backprop_wrong_interface(self, interface, tol): + """Tests that an error is raised if diff_method='backprop' but not using + the TF interface""" + dev = qml.device("default.qubit.tf", wires=1) + + def circuit(x, w=None): + qml.RZ(x, wires=w) + return qml.expval(qml.PauliX(w)) + + with pytest.raises( + qml.QuantumFunctionError, + match="default.qubit.tf only supports diff_method='backprop' when using the tf interface", + ): + qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) + + def test_hermitian_backprop(self, tol): + """Test that backprop with qml.Hermitian works correctly""" + dev = qml.device("default.qubit.tf", wires=2) + + K = tf.linalg.diag([1, 2, 3, 4]) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def circuit(op): + qml.PauliX(0) + qml.PauliX(1) + return qml.expval(op) + + res = circuit(qml.Hermitian(K, wires=range(2))) + assert isinstance(res, tf.Tensor) + assert res == 4.0 + + +@pytest.mark.tf +class TestSamples: + """Tests for sampling outputs""" + + def test_sample_observables(self): + """Test that the device allows for sampling from observables.""" + shots = 100 + dev = qml.device("default.qubit.tf", wires=2, shots=shots) + + @qml.qnode(dev, diff_method="best", interface="tf") + def circuit(a): + qml.RX(a, wires=0) + return qml.sample(qml.PauliZ(0)) + + a = tf.Variable(0.54, dtype=tf.float64) + res = circuit(a) + + assert isinstance(res, tf.Tensor) + 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.""" + dev = qml.device("default.qubit.tf", wires=2, shots=1000) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(): + qml.PauliX(0) + return qml.probs(wires=[0]) + + res = circuit() + + assert isinstance(res, tf.Tensor) + + expected = np.array([0, 1]) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_estimating_full_probability(self, tol): + """Test that the probability of all wires is accurately estimated.""" + dev = qml.device("default.qubit.tf", wires=2, shots=1000) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(): + qml.PauliX(0) + qml.PauliX(1) + return qml.probs(wires=[0, 1]) + + res = circuit() + + assert isinstance(res, tf.Tensor) + + expected = np.array([0, 0, 0, 1]) + assert np.allclose(res, expected, atol=tol, rtol=0) + + def test_estimating_expectation_values(self, tol): + """Test that estimating expectation values using a finite number + of shots produces a numeric tensor""" + dev = qml.device("default.qubit.tf", wires=3, shots=1000) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(a, b): + qml.RX(a, wires=[0]) + qml.RX(b, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) + + a = tf.Variable(0.543, dtype=tf.float64) + b = tf.Variable(0.43, dtype=tf.float64) + + res = circuit(a, b) + assert isinstance(res, tuple) + + # We don't check the expected value due to stochasticity, but + # leave it here for completeness. + # expected = [tf.cos(a), tf.cos(a) * tf.cos(b)] + # assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.tf +class TestSamplesBroadcasted: + """Tests for broadcasted sampling outputs""" + + def test_sample_observables_broadcasted(self): + """Test that the device allows for broadcasted sampling from observables.""" + shots = 100 + dev = qml.device("default.qubit.tf", wires=2, shots=shots) + + @qml.qnode(dev, diff_method="best", interface="tf") + def circuit(a): + qml.RX(a, wires=0) + return qml.sample(qml.PauliZ(0)) + + a = tf.Variable([0.54, -0.32, 0.19], dtype=tf.float64) + res = circuit(a) + + assert isinstance(res, tf.Tensor) + 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): + """Test that the broadcasted probability of a subset of wires is accurately estimated.""" + dev = qml.device("default.qubit.tf", wires=2, shots=1000) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(): + qml.RX(tf.zeros(batch_size), 0) + qml.PauliX(0) + return qml.probs(wires=[0]) + + res = circuit() + + assert isinstance(res, tf.Tensor) + assert qml.math.shape(res) == (batch_size, 2) + + expected = np.array([[0, 1]] * batch_size) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("batch_size", [2, 3]) + def test_estimating_full_probability_broadcasted(self, batch_size, tol): + """Test that the broadcasted probability of all wires is accurately estimated.""" + dev = qml.device("default.qubit.tf", wires=2, shots=1000) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(): + qml.RX(tf.zeros(batch_size), 0) + qml.PauliX(0) + qml.PauliX(1) + return qml.probs(wires=[0, 1]) + + res = circuit() + + assert isinstance(res, tf.Tensor) + assert qml.math.shape(res) == (batch_size, 4) + + expected = np.array([[0, 0, 0, 1]] * batch_size) + assert np.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.skip("Parameter broadcasting is not supported for multiple return values yet") + @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) + def test_estimating_expectation_values_broadcasted(self, a, tol): + """Test that estimating broadcasted expectation values using a finite number + of shots produces a numeric tensor""" + batch_size = len(a) + dev = qml.device("default.qubit.tf", wires=3, shots=None) + + @qml.qnode(dev, diff_method=None, interface="tf") + def circuit(a, b): + qml.RX(a, wires=[0]) + qml.RX(b, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) + + a = tf.Variable(a, dtype=tf.float64) + b = tf.Variable(0.43, dtype=tf.float64) + + res = circuit(a, b) + assert isinstance(res, tf.Tensor) + assert qml.math.shape(res) == (batch_size, 2) + + +@pytest.mark.tf +def test_asarray_ragged_dtype_conversion(monkeypatch): + """Test that the _asarray internal method handles ragged arrays well when + the dtype argument was provided.""" + from tensorflow.python.framework.errors_impl import InvalidArgumentError + + dev = qml.device("default.qubit.tf", wires=2) + + def mock_func(arr, dtype): + raise InvalidArgumentError( + None, None, "SomeMessage" + ) # args passed are non-significant for test case + + monkeypatch.setattr(tf, "convert_to_tensor", mock_func) + res = dev._asarray(np.array([1]), tf.float32) + assert res.dtype == tf.float32 + + +@pytest.mark.tf +class TestGetBatchSize: + """Tests for the updated helper method ``_get_batch_size`` of ``DefaultQubitTF``.""" + + @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) + def test_batch_size_None(self, shape): + """Test that a ``batch_size=None`` is reported correctly.""" + dev = qml.device("default.qubit.tf", wires=2) + tensor0 = np.ones(shape, dtype=complex) + assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None + + @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) + @pytest.mark.parametrize("batch_size", [1, 3]) + def test_batch_size_int(self, shape, batch_size): + """Test that an integral ``batch_size`` is reported correctly.""" + dev = qml.device("default.qubit.tf", wires=2) + full_shape = (batch_size,) + shape + tensor0 = np.ones(full_shape, dtype=complex) + assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size + + def test_invalid_tensor(self): + """Test that an error is raised if a tensor is provided that does not + have a proper shape/ndim.""" + dev = qml.device("default.qubit.tf", wires=2) + with pytest.raises(ValueError, match="Can't convert non-rectangular Python"): + dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) + + @pytest.mark.parametrize("jit_compile", [True, False]) + def test_no_error_abstract_tensor(self, jit_compile): + """Test that no error is raised if an abstract tensor is provided""" + dev = qml.device("default.qubit.tf", wires=2) + signature = (tf.TensorSpec(shape=None, dtype=tf.float32),) + + @tf.function(jit_compile=jit_compile, input_signature=signature) + def get_batch_size(tensor): + return dev._get_batch_size(tensor, (2,), 2) + + assert get_batch_size(tf.Variable(0.2)) is None diff --git a/tests/devices/default_qubit_1/test_default_qubit_torch.py b/tests/devices/default_qubit_1/test_default_qubit_torch.py new file mode 100644 index 00000000000..de01e303d5f --- /dev/null +++ b/tests/devices/default_qubit_1/test_default_qubit_torch.py @@ -0,0 +1,2492 @@ +# Copyright 2018-2021 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 and integration tests for the ``default.qubit.torch`` device. +""" +# pylint: disable=too-many-arguments,too-many-public-methods,too-few-public-methods,protected-access +import math + +import numpy as np +import pytest +from gate_data import ( + CNOT, + CSWAP, + CZ, + CH, + SWAP, + ControlledPhaseShift, + CRot3, + CRotx, + CRoty, + CRotz, + DoubleExcitation, + DoubleExcitationMinus, + DoubleExcitationPlus, + H, + IsingXX, + IsingYY, + IsingZZ, + MultiRZ1, + MultiRZ2, + OrbitalRotation, + FermionicSWAP, + Rot3, + Rotx, + Roty, + Rotz, + Rphi, + S, + SingleExcitation, + SingleExcitationMinus, + SingleExcitationPlus, + T, + Toffoli, + CCZ, + X, + Y, + Z, +) + +import pennylane as qml +from pennylane import DeviceError +from pennylane import numpy as pnp + +torch = pytest.importorskip("torch", minversion="1.8.1") +from pennylane.devices.default_qubit_torch import ( # pylint: disable=wrong-import-position + DefaultQubitTorch, +) + +pytestmark = pytest.mark.gpu + +torch_devices = [None] + +if torch.cuda.is_available(): + torch_devices.append("cuda") + + +np.random.seed(42) + +##################################################### +# Test matrices +##################################################### + +U = np.array( + [ + [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], + [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], + ] +) + +U2 = np.array([[0, 1, 1, 1], [1, 0, 1, -1], [1, -1, 0, 1], [1, 1, -1, 0]]) / np.sqrt(3) + +################################## +# Define standard qubit operations +################################## + +# Note: determining the torch device of the input parameters is done in the +# test cases + +single_qubit = [ + (qml.S, S), + (qml.T, T), + (qml.PauliX, X), + (qml.PauliY, Y), + (qml.PauliZ, Z), + (qml.Hadamard, H), +] + +single_qubit_param = [ + (qml.PhaseShift, Rphi), + (qml.RX, Rotx), + (qml.RY, Roty), + (qml.RZ, Rotz), + (qml.MultiRZ, MultiRZ1), +] +two_qubit = [(qml.CZ, CZ), (qml.CNOT, CNOT), (qml.SWAP, SWAP), (qml.CH, CH)] +two_qubit_param = [ + (qml.CRX, CRotx), + (qml.CRY, CRoty), + (qml.CRZ, CRotz), + (qml.IsingXX, IsingXX), + (qml.IsingYY, IsingYY), + (qml.IsingZZ, IsingZZ), + (qml.MultiRZ, MultiRZ2), + (qml.ControlledPhaseShift, ControlledPhaseShift), + (qml.SingleExcitation, SingleExcitation), + (qml.SingleExcitationPlus, SingleExcitationPlus), + (qml.SingleExcitationMinus, SingleExcitationMinus), + (qml.FermionicSWAP, FermionicSWAP), +] +three_qubit = [(qml.Toffoli, Toffoli), (qml.CSWAP, CSWAP), (qml.CCZ, CCZ)] +four_qubit_param = [ + (qml.DoubleExcitation, DoubleExcitation), + (qml.DoubleExcitationPlus, DoubleExcitationPlus), + (qml.DoubleExcitationMinus, DoubleExcitationMinus), + (qml.OrbitalRotation, OrbitalRotation), +] + + +##################################################### +# Fixtures +##################################################### + + +# pylint: disable=unused-argument +@pytest.fixture(name="init_state") +def init_state_fixture(scope="session"): + """Generates a random initial state""" + + def _init_state(n, torch_device): + """random initial state""" + torch.manual_seed(42) + state = torch.rand([2**n], dtype=torch.complex128) + torch.rand([2**n]) * 1j + state /= torch.linalg.norm(state) + return state.to(torch_device) + + return _init_state + + +# pylint: disable=unused-argument +@pytest.fixture(name="broadcasted_init_state") +def broadcasted_init_state_fixture(scope="session"): + """Generates a broadcasted random initial state""" + + def _broadcasted_init_state(n, batch_size, torch_device): + """random initial state""" + torch.manual_seed(42) + state = ( + torch.rand([batch_size, 2**n], dtype=torch.complex128) + + torch.rand([batch_size, 2**n]) * 1j + ) + state /= torch.linalg.norm(state, axis=1)[:, np.newaxis] + return state.to(torch_device) + + return _broadcasted_init_state + + +# pylint: disable=unused-argument +@pytest.fixture(name="device") +def device_fixture(scope="function"): + """Creates a Torch device""" + + def _dev(wires, torch_device=None): + """Torch device""" + dev = DefaultQubitTorch(wires=wires, torch_device=torch_device) + return dev + + return _dev + + +##################################################### +# Initialization test +##################################################### + + +@pytest.mark.torch +def test_analytic_deprecation(): + """Tests if the kwarg `analytic` is used and displays error message.""" + msg = "The analytic argument has been replaced by shots=None. " + msg += "Please use shots=None instead of analytic=True." + + with pytest.raises(DeviceError, match=msg): + qml.device("default.qubit.torch", wires=1, shots=1, analytic=True) + + +##################################################### +# Helper Method Test +##################################################### + + +def test_conj_helper_method(): + """Unittests the _conj helper method.""" + + dev = qml.device("default.qubit.torch", wires=1) + + x = qml.numpy.array(1.0 + 1j) + conj_x = dev._conj(x) + assert qml.math.allclose(conj_x, qml.math.conj(x)) + + +##################################################### +# Device-level integration tests +##################################################### + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestApply: + """Test application of PennyLane operations.""" + + def test_conj_array(self, device, torch_device, tol): + """Test using conj method from the device.""" + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([-1.0 + 1j, 1.0 + 1j], dtype=torch.complex128, device=torch_device) + assert torch.allclose( + dev._conj(state), + torch.tensor([-1.0 - 1j, 1.0 - 1j], dtype=torch.complex128, device=torch_device), + atol=tol, + rtol=0, + ) + + def test_basis_state(self, device, torch_device, tol): + """Test basis state initialization""" + + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([0, 0, 1, 0], dtype=torch.complex128, device=torch_device) + + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + res = dev.state + expected = torch.zeros([2**4], dtype=torch.complex128, device=torch_device) + expected[2] = 1 + + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_invalid_basis_state_length(self, device, torch_device): + """Test that an exception is raised if the basis state is the wrong size""" + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([0, 0, 1, 0]) + + with pytest.raises( + ValueError, match=r"BasisState parameter and wires must be of equal length" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) + + def test_invalid_basis_state(self, device, torch_device): + """Test that an exception is raised if the basis state is invalid""" + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([0, 0, 1, 2]) + + with pytest.raises( + ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + def test_qubit_state_vector(self, device, torch_device, init_state, tol): + """Test qubit state vector application""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + res = dev.state + expected = state + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_full_subsystem_statevector(self, device, torch_device, mocker): + """Test applying a state vector to the full subsystem""" + dev = device(wires=["a", "b", "c"], torch_device=torch_device) + state = ( + torch.tensor([1, 0, 0, 0, 1, 0, 1, 1], dtype=torch.complex128, device=torch_device) + / 2.0 + ) + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert torch.allclose(torch.reshape(dev._state, (-1,)), state) + spy.assert_not_called() + + def test_partial_subsystem_statevector(self, device, torch_device, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + dev = device(wires=["a", "b", "c"], torch_device=torch_device) + state = torch.tensor( + [1, 0, 1, 0], dtype=torch.complex128, device=torch_device + ) / torch.tensor(math.sqrt(2.0)) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = torch.reshape(torch.sum(dev._state, axis=(1,)), [-1]) + + assert torch.allclose(res, state) + spy.assert_called() + + def test_invalid_qubit_state_vector_size(self, device, torch_device): + """Test that an exception is raised if the state + vector is the wrong size""" + dev = device(wires=2, torch_device=torch_device) + state = torch.tensor([0, 1]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): + dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) + + @pytest.mark.parametrize( + "state", [torch.tensor([0, 12]), torch.tensor([1.0, -1.0], requires_grad=True)] + ) + def test_invalid_qubit_state_vector_norm(self, device, torch_device, state): + """Test that an exception is raised if the state + vector is not normalized""" + dev = device(wires=2, torch_device=torch_device) + + with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + def test_invalid_state_prep(self, device, torch_device): + """Test that an exception is raised if a state preparation is not the + first operation in the circuit.""" + dev = device(wires=2, torch_device=torch_device) + state = torch.tensor([0, 1]) + + with pytest.raises( + qml.DeviceError, + match=r"cannot be used after other Operations have already been applied", + ): + dev.apply([qml.PauliZ(0), qml.QubitStateVector(state, wires=[0])]) + + @pytest.mark.parametrize("op,mat", single_qubit) + def test_single_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): + """Test non-parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(wires=0)] + dev.apply(queue) + + res = dev.state + # assert mat.dtype == state.dtype + mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + expected = torch.matmul(mat, state) + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): + """Test parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(par, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) + expected = torch.matmul(op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation(self, device, torch_device, init_state, tol): + """Test three axis rotation gate""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) + b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(Rot3(a, b, c), dtype=torch.complex128, device=torch_device) + expected = op_mat @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation(self, device, torch_device, init_state, tol): + """Test three axis controlled-rotation gate""" + dev = device(wires=2, torch_device=torch_device) + state = init_state(2, torch_device=torch_device) + + a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) + b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) + expected = op_mat @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op,mat", two_qubit) + def test_two_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): + """Test non-parametrized two qubit operations""" + dev = device(wires=2, torch_device=torch_device) + state = init_state(2, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(wires=[0, 1])] + dev.apply(queue) + + res = dev.state + expected = torch.tensor(mat, dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary(self, device, torch_device, init_state, mat, tol): + """Test application of arbitrary qubit unitaries""" + N = int(math.log(len(mat), 2)) + + mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + dev = device(wires=N, torch_device=torch_device) + state = init_state(N, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = mat @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_diagonal_qubit_unitary(self, device, torch_device, init_state, tol): + """Tests application of a diagonal qubit unitary""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + diag = torch.tensor( + [-1.0 + 1j, 1.0 + 1j], requires_grad=True, dtype=torch.complex128, device=torch_device + ) / math.sqrt(2) + + queue = [qml.QubitStateVector(state, wires=0), qml.DiagonalQubitUnitary(diag, wires=0)] + dev.apply(queue) + + res = dev.state + expected = torch.diag(diag) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op, mat", three_qubit) + def test_three_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): + """Test non-parametrized three qubit operations""" + dev = device(wires=3, torch_device=torch_device) + state = init_state(3, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] + queue += [op(wires=[0, 1, 2])] + dev.apply(queue) + + res = dev.state + expected = torch.tensor(mat, dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", two_qubit_param) + def test_two_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): + """Test two qubit parametrized operations""" + dev = device(wires=2, torch_device=torch_device) + state = init_state(2, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(theta, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) + expected = op_mat @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", four_qubit_param) + def test_four_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): + """Test two qubit parametrized operations""" + dev = device(wires=4, torch_device=torch_device) + state = init_state(4, torch_device=torch_device) + + par = torch.tensor(theta, device=torch_device) + queue = [qml.QubitStateVector(state, wires=[0, 1, 2, 3])] + queue += [op(par, wires=[0, 1, 2, 3])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) + expected = op_mat @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_apply_ops_above_8_wires_using_special(self, device, torch_device): + """Test that special apply methods that involve slicing function correctly when using 9 + wires""" + dev = device(wires=9, torch_device=torch_device) + dev._apply_ops = {"CNOT": dev._apply_cnot} + + queue = [qml.CNOT(wires=[1, 2])] + dev.apply(queue) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestApplyBroadcasted: + """Test application of broadcasted PennyLane operations.""" + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_basis_state_broadcasted(self, device, torch_device, tol): + """Test basis state initialization""" + + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor( + [[0, 0, 1, 0], [1, 0, 0, 0]], dtype=torch.complex128, device=torch_device + ) + + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + res = dev.state + expected = torch.zeros([2**4], dtype=torch.complex128, device=torch_device) + expected[0, 2] = expected[1, 0] = 1 + + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_invalid_basis_state_length_broadcasted(self, device, torch_device): + """Test that an exception is raised if the basis state is the wrong size""" + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([0, 0, 1, 0, 1]) + + with pytest.raises( + ValueError, match=r"BasisState parameter and wires must be of equal length" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) + + @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") + def test_invalid_basis_state_broadcasted(self, device, torch_device): + """Test that an exception is raised if the basis state is invalid""" + dev = device(wires=4, torch_device=torch_device) + state = torch.tensor([0, 0, 1, 2]) + + with pytest.raises( + ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" + ): + dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) + + @pytest.mark.parametrize("batch_size", [1, 3]) + def test_qubit_state_vector_broadcasted( + self, device, torch_device, broadcasted_init_state, batch_size, tol + ): + """Test broadcasted qubit state vector application""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, batch_size, torch_device=torch_device) + + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + res = dev.state + expected = state + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_full_subsystem_statevector_broadcasted(self, device, torch_device, mocker): + """Test applying a state vector to the full subsystem""" + dev = device(wires=["a", "b", "c"], torch_device=torch_device) + state = ( + torch.tensor( + [[1, 0, 0, 0, 1, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 1]], + dtype=torch.complex128, + device=torch_device, + ) + / 2 + ) + state_wires = qml.wires.Wires(["a", "b", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + + assert torch.allclose(torch.reshape(dev._state, [3, 8]), state) + spy.assert_not_called() + + def test_partial_subsystem_statevector_broadcasted(self, device, torch_device, mocker): + """Test applying a state vector to a subset of wires of the full subsystem""" + dev = device(wires=["a", "b", "c"], torch_device=torch_device) + state = torch.tensor( + [[1, 0, 1, 0], [1, 1, 0, 0], [0, 1, 1, 0]], dtype=torch.complex128, device=torch_device + ) / torch.tensor(math.sqrt(2.0)) + state_wires = qml.wires.Wires(["a", "c"]) + + spy = mocker.spy(dev, "_scatter") + dev._apply_state_vector(state=state, device_wires=state_wires) + res = torch.reshape(torch.sum(dev._state, axis=(2,)), [3, 4]) + + assert torch.allclose(res, state) + spy.assert_called() + + def test_invalid_qubit_state_vector_size_broadcasted(self, device, torch_device): + """Test that an exception is raised if the state + vector is the wrong size""" + dev = device(wires=2, torch_device=torch_device) + state = torch.tensor([[0, 1], [1, 0], [1, 1], [0, 0]]) + + with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): + dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) + + def test_invalid_qubit_state_vector_norm_broadcasted(self, device, torch_device): + """Test that an exception is raised if the state + vector is not normalized""" + dev = device(wires=2, torch_device=torch_device) + state = torch.tensor([[1, 0], [0, 12], [1.3, 1]], requires_grad=True) + + with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): + dev.apply([qml.QubitStateVector(state, wires=[0])]) + + @pytest.mark.parametrize("op,mat", single_qubit) + def test_single_qubit_no_parameters_broadcasted( + self, device, torch_device, broadcasted_init_state, op, mat, tol + ): + """Test non-parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, 3, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(wires=0)] + dev.apply(queue) + + res = dev.state + mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,kj->ki", mat, state) + assert isinstance(res, torch.Tensor) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_state( + self, device, torch_device, broadcasted_init_state, op, func, theta, tol + ): + """Test parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, 3, torch_device=torch_device) + + par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(par, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,kj->ki", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_par( + self, device, torch_device, init_state, op, func, theta, tol + ): + """Test parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(par, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor( + np.array([func(t) for t in theta]), dtype=torch.complex128, device=torch_device + ) + expected = qml.math.einsum("lij,j->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_broadcasted_both( + self, device, torch_device, broadcasted_init_state, op, func, theta, tol + ): + """Test parametrized single qubit operations""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, 3, torch_device=torch_device) + + par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [op(par, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor( + np.array([func(t) for t in theta]), dtype=torch.complex128, device=torch_device + ) + expected = qml.math.einsum("lij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_state(self, device, torch_device, broadcasted_init_state, tol): + """Test three axis rotation gate""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, 3, torch_device=torch_device) + + a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) + b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(Rot3(a, b, c), dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_par(self, device, torch_device, init_state, tol): + """Test three axis rotation gate""" + dev = device(wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) + b = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.stack([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) + expected = qml.math.einsum("lij,j->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_rotation_broadcasted_both(self, device, torch_device, broadcasted_init_state, tol): + """Test three axis rotation gate""" + dev = device(wires=1, torch_device=torch_device) + state = broadcasted_init_state(1, 3, torch_device=torch_device) + + a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) + b = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0])] + queue += [qml.Rot(a, b, c, wires=0)] + dev.apply(queue) + + res = dev.state + op_mat = torch.stack([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) + expected = qml.math.einsum("lij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_state( + self, device, torch_device, broadcasted_init_state, tol + ): + """Test three axis controlled-rotation gate""" + dev = device(wires=2, torch_device=torch_device) + state = broadcasted_init_state(2, 3, torch_device=torch_device) + + a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) + b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) + c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_par(self, device, torch_device, init_state, tol): + """Test three axis controlled-rotation gate""" + dev = device(wires=2, torch_device=torch_device) + state = init_state(2, torch_device=torch_device) + + a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) + b = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + c = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.stack([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) + expected = qml.math.einsum("lij,j->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_broadcasted_both( + self, device, torch_device, broadcasted_init_state, tol + ): + """Test three axis controlled-rotation gate""" + dev = device(wires=2, torch_device=torch_device) + state = broadcasted_init_state(2, 3, torch_device=torch_device) + + a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) + b = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) + c = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [qml.CRot(a, b, c, wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.stack([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) + expected = qml.math.einsum("lij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op,mat", two_qubit) + def test_two_qubit_no_parameters_broadcasted( + self, device, torch_device, broadcasted_init_state, op, mat, tol + ): + """Test non-parametrized two qubit operations""" + dev = device(wires=2, torch_device=torch_device) + state = broadcasted_init_state(2, 3, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1])] + queue += [op(wires=[0, 1])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_state( + self, device, torch_device, broadcasted_init_state, mat, tol + ): + """Test application of arbitrary qubit unitaries""" + N = int(math.log(len(mat), 2)) + + mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + dev = device(wires=N, torch_device=torch_device) + state = broadcasted_init_state(N, 3, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = qml.math.einsum("ij,lj->li", mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_par(self, device, torch_device, init_state, mat, tol): + """Test application of arbitrary qubit unitaries""" + N = int(math.log(len(mat), 2)) + + mat = torch.tensor([mat, mat, mat], dtype=torch.complex128, device=torch_device) + dev = device(wires=N, torch_device=torch_device) + state = init_state(N, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = qml.math.einsum("lij,j->li", mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("mat", [U, U2]) + def test_qubit_unitary_broadcasted_both( + self, device, torch_device, broadcasted_init_state, mat, tol + ): + """Test application of arbitrary qubit unitaries""" + N = int(math.log(len(mat), 2)) + + mat = torch.tensor([mat, mat, mat], dtype=torch.complex128, device=torch_device) + dev = device(wires=N, torch_device=torch_device) + state = broadcasted_init_state(N, 3, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=range(N))] + queue += [qml.QubitUnitary(mat, wires=range(N))] + dev.apply(queue) + + res = dev.state + expected = qml.math.einsum("lij,lj->li", mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("op, mat", three_qubit) + def test_three_qubit_no_parameters_broadcasted( + self, device, torch_device, broadcasted_init_state, op, mat, tol + ): + """Test non-parametrized three qubit operations""" + dev = device(wires=3, torch_device=torch_device) + state = broadcasted_init_state(3, 2, torch_device=torch_device) + + queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] + queue += [op(wires=[0, 1, 2])] + dev.apply(queue) + + res = dev.state + op_mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) + expected = qml.math.einsum("ij,lj->li", op_mat, state) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_direct_eval_hamiltonian_broadcasted_error_torch(self, device, torch_device, mocker): + """Tests that an error is raised when attempting to evaluate a Hamiltonian with + broadcasting and shots=None directly via its sparse representation with torch.""" + + dev = device(wires=2, torch_device=torch_device) + ham = qml.Hamiltonian( + torch.tensor([0.1, 0.2], requires_grad=True), [qml.PauliX(0), qml.PauliZ(1)] + ) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(): + qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity + return qml.expval(ham) + + with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): + circuit() + + +THETA = torch.linspace(0.11, 1, 3, dtype=torch.float64) +PHI = torch.linspace(0.32, 1, 3, dtype=torch.float64) +VARPHI = torch.linspace(0.02, 1, 3, dtype=torch.float64) + +scalar_angles = list(zip(THETA, PHI, VARPHI)) +broadcasted_angles = [(THETA, PHI, VARPHI), (THETA[0], PHI, VARPHI)] +all_angles = scalar_angles + broadcasted_angles + + +# pylint: disable=unused-argument +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +@pytest.mark.parametrize("theta, phi, varphi", all_angles) +class TestExpval: + """Test expectation values""" + + # test data; each tuple is of the form (GATE, OBSERVABLE, EXPECTED) + single_wire_expval_test_data = [ + ( + qml.RX, + qml.Identity, + lambda t, p, t_device: torch.tensor( + qml.math.stack([torch.ones_like(t) * torch.ones_like(p)] * 2), + dtype=torch.float64, + device=t_device, + ), + ), + ( + qml.RX, + qml.PauliZ, + lambda t, p, t_device: torch.tensor( + qml.math.stack([torch.cos(t) * torch.ones_like(p), torch.cos(t) * torch.cos(p)]), + dtype=torch.float64, + device=t_device, + ), + ), + ( + qml.RY, + qml.PauliX, + lambda t, p, t_device: torch.tensor( + qml.math.stack([torch.sin(t) * torch.sin(p), torch.sin(p) * torch.ones_like(t)]), + dtype=torch.float64, + device=t_device, + ), + ), + ( + qml.RX, + qml.PauliY, + lambda t, p, t_device: torch.tensor( + qml.math.stack( + [torch.zeros_like(p) * torch.zeros_like(t), -torch.cos(t) * torch.sin(p)] + ), + dtype=torch.float64, + device=t_device, + ), + ), + ( + qml.RY, + qml.Hadamard, + lambda t, p, t_device: torch.tensor( + qml.math.stack( + [ + torch.sin(t) * torch.sin(p) + torch.cos(t), + torch.cos(t) * torch.cos(p) + torch.sin(p), + ] + ), + dtype=torch.float64, + device=t_device, + ) + / math.sqrt(2), + ), + ] + + @pytest.mark.parametrize("gate,obs,expected", single_wire_expval_test_data) + def test_single_wire_expectation( + self, device, torch_device, gate, obs, expected, theta, phi, varphi, tol + ): + """Test that single qubit gates with single qubit expectation values""" + dev = device(wires=2, torch_device=torch_device) + if qml.math.ndim(theta) == 1 or qml.math.ndim(phi) == 1: + pytest.skip("Multiple return values are not supported with broadcasting") + + par1 = theta.to(device=torch_device) + par2 = phi.to(device=torch_device) + with qml.queuing.AnnotatedQueue() as q: + _ = [gate(par1, wires=0), gate(par2, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(obs(wires=[i])) for i in range(2)] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + + expected_res = expected(theta, phi, torch_device) + assert torch.allclose(qml.math.stack(res), expected_res, atol=tol, rtol=0) + + def test_hermitian_expectation(self, device, torch_device, theta, phi, varphi, tol): + """Test that arbitrary Hermitian expectation values are correct""" + if qml.math.ndim(theta) == 1 or qml.math.ndim(phi) == 1: + pytest.skip("Multiple return values are not supported with broadcasting") + dev = device(wires=2, torch_device=torch_device) + + Hermitian_mat = torch.tensor( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], + dtype=torch.complex128, + device=torch_device, + ) + + par1 = theta.to(device=torch_device) + par2 = phi.to(device=torch_device) + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RY(par1, wires=0), qml.RY(par2, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(qml.Hermitian(Hermitian_mat, wires=[i])) for i in range(2)] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + + a = Hermitian_mat[0, 0] + re_b = Hermitian_mat[0, 1].real + d = Hermitian_mat[1, 1] + ev1 = ( + (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d + ) / 2 + ev2 = ((a - d) * torch.cos(theta) * torch.cos(phi) + 2 * re_b * torch.sin(phi) + a + d) / 2 + expected = torch.tensor([ev1, ev2], dtype=torch.float64, device=torch_device) + + assert torch.allclose(qml.math.stack(res), expected, atol=tol, rtol=0) + + def test_do_not_split_analytic_torch( + self, device, torch_device, theta, phi, varphi, tol, mocker + ): + """Tests that the Hamiltonian is not split for shots=None using the Torch device.""" + + dev = device(wires=2, torch_device=torch_device) + ham = qml.Hamiltonian( + torch.tensor([0.1, 0.2], requires_grad=True), [qml.PauliX(0), qml.PauliZ(1)] + ) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(): + return qml.expval(ham) + + spy = mocker.spy(dev, "expval") + + circuit() + # evaluated one expval altogether + assert spy.call_count == 1 + + def test_multi_mode_hermitian_expectation(self, device, torch_device, theta, phi, varphi, tol): + """Test that arbitrary multi-mode Hermitian expectation values are correct""" + Hermit_mat2 = torch.tensor( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ], + dtype=torch.complex128, + ) + + dev = device(wires=2, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] + _ = [qml.expval(qml.Hermitian(Hermit_mat2, wires=[0, 1]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + + # below is the analytic expectation value for this circuit with arbitrary + # Hermitian observable Hermit_mat2 + expected = 0.5 * ( + 6 * torch.cos(theta) * torch.sin(phi) + - torch.sin(theta) * (8 * torch.sin(phi) + 7 * torch.cos(phi) + 3) + - 2 * torch.sin(phi) + - 6 * torch.cos(phi) + - 6 + ) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_paulix_pauliy(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = device(wires=3, torch_device=torch_device) + dev.reset() + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = torch.sin(theta) * torch.sin(phi) * torch.sin(varphi) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_identity(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and Identity works correctly""" + dev = device(wires=3, torch_device=torch_device) + dev.reset() + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = torch.cos(varphi) * torch.cos(phi) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = device(wires=3, torch_device=torch_device) + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = -( + torch.cos(varphi) * torch.sin(phi) + torch.sin(varphi) * torch.cos(theta) + ) / math.sqrt(2) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = device(wires=3, torch_device=torch_device) + dev.reset() + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + Hermit_mat3 = torch.tensor( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ], + dtype=torch.complex128, + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(Hermit_mat3, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.5 * ( + -6 * torch.cos(theta) * (torch.cos(varphi) + 1) + - 2 * torch.sin(varphi) * (torch.cos(theta) + torch.sin(phi) - 2 * torch.cos(phi)) + + 3 * torch.cos(varphi) * torch.sin(phi) + + torch.sin(phi) + ) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_hermitian(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving two Hermitian matrices works correctly""" + dev = device(wires=3, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + A1 = torch.tensor([[1, 2], [2, 4]], dtype=torch.complex128) + + A2 = torch.tensor( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ], + dtype=torch.complex128, + ) + A1 = A1.to(device=torch_device) + A2 = A2.to(device=torch_device) + + obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + expected = 0.25 * ( + -30 + + 4 * torch.cos(phi) * torch.sin(theta) + + 3 + * torch.cos(varphi) + * (-10 + 4 * torch.cos(phi) * torch.sin(theta) - 3 * torch.sin(phi)) + - 3 * torch.sin(phi) + - 2 + * ( + 5 + + torch.cos(phi) * (6 + 4 * torch.sin(theta)) + + (-3 + 8 * torch.sin(theta)) * torch.sin(phi) + ) + * torch.sin(varphi) + + torch.cos(theta) + * ( + 18 + + 5 * torch.sin(phi) + + 3 * torch.cos(varphi) * (6 + 5 * torch.sin(phi)) + + 2 * (3 + 10 * torch.cos(phi) - 5 * torch.sin(phi)) * torch.sin(varphi) + ) + ) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian_identity_expectation(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" + dev = device(wires=2, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + + A = torch.tensor( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], + dtype=torch.complex128, + ) + A = A.to(device=torch_device) + + obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + expected = ( + (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d + ) / 2 + + assert torch.allclose(res, torch.real(expected), atol=tol, rtol=0) + + def test_hermitian_two_wires_identity_expectation( + self, device, torch_device, theta, phi, varphi, tol + ): + """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" + dev = device(wires=3, torch_device=torch_device) + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + + A = torch.tensor( + [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], + dtype=torch.complex128, + ) + A = A.to(device=torch_device) + + Identity = torch.tensor([[1, 0], [0, 1]]) + Identity = Identity.to(device=torch_device) + + ham = torch.kron(torch.kron(Identity, Identity), A) + obs = qml.Hermitian(ham, wires=[2, 1, 0]) + + dev.apply( + [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], + obs.diagonalizing_gates(), + ) + res = dev.expval(obs) + + a = A[0, 0] + re_b = A[0, 1].real + d = A[1, 1] + + expected = ( + (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d + ) / 2 + assert torch.allclose(res, torch.real(expected), atol=tol, rtol=0) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +@pytest.mark.parametrize("theta, phi, varphi", all_angles) +class TestVar: + """Tests for the variance + + Note: the following tests use DefaultQubitTorch.execute that contains logic + to transfer tensors created by default on the CPU to the GPU. Therefore, gate + parameters do not have to explicitly be put on the GPU, it suffices to + specify torch_device='cuda' when creating the PennyLane device. + """ + + def test_var(self, device, torch_device, theta, phi, varphi, tol): + """Tests for variance calculation""" + dev = device(wires=1, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + + # test correct variance for of a rotated state + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RX(theta, wires=0), qml.RY(phi, wires=0)] + _ = [qml.var(qml.PauliZ(wires=[0]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + expected = 0.25 * ( + 3 - torch.cos(2 * theta) - 2 * torch.cos(theta) ** 2 * torch.cos(2 * phi) + ) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_var_hermitian(self, device, torch_device, theta, phi, varphi, tol): + """Tests for variance calculation using an arbitrary Hermitian observable""" + dev = device(wires=2, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + + # test correct variance for of a rotated state + ham = torch.tensor( + [[4, -1 + 6j], [-1 - 6j, 2]], dtype=torch.complex128, device=torch_device + ) + + with qml.queuing.AnnotatedQueue() as q: + _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] + _ = [qml.var(qml.Hermitian(ham, wires=[0]))] + + tape = qml.tape.QuantumScript.from_queue(q) + res = dev.execute(tape) + expected = 0.5 * ( + 2 * torch.sin(2 * theta) * torch.cos(phi) ** 2 + + 24 * torch.sin(phi) * torch.cos(phi) * (torch.sin(theta) - torch.cos(theta)) + + 35 * torch.cos(2 * phi) + + 39 + ) + expected = expected.to(device=torch_device) + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_paulix_pauliy(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving PauliX and PauliY works correctly""" + dev = device(wires=3, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + obs = qml.PauliX(0) @ qml.PauliY(2) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 8 * torch.sin(theta) ** 2 * torch.cos(2 * varphi) * torch.sin(phi) ** 2 + - torch.cos(2 * (theta - phi)) + - torch.cos(2 * (theta + phi)) + + 2 * torch.cos(2 * theta) + + 2 * torch.cos(2 * phi) + + 14 + ) / 16 + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_pauliz_hadamard(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" + dev = device(wires=3, torch_device=torch_device) + obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + dev.reset() + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 3 + + torch.cos(2 * phi) * torch.cos(varphi) ** 2 + - torch.cos(2 * theta) * torch.sin(varphi) ** 2 + - 2 * torch.cos(theta) * torch.sin(phi) * torch.sin(2 * varphi) + ) / 4 + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_hermitian(self, device, torch_device, theta, phi, varphi, tol): + """Test that a tensor product involving qml.Hermitian works correctly""" + dev = device(wires=3, torch_device=torch_device) + + theta = theta.to(device=torch_device) + phi = phi.to(device=torch_device) + varphi = varphi.to(device=torch_device) + + A = torch.tensor( + [ + [-6, 2 + 1j, -3, -5 + 2j], + [2 - 1j, 0, 2 - 1j, -5 + 4j], + [-3, 2 + 1j, 0, -4 + 3j], + [-5 - 2j, -5 - 4j, -4 - 3j, -6], + ], + dtype=torch.complex128, + device=torch_device, + ) + + obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) + + dev.apply( + [ + qml.RX(theta, wires=[0]), + qml.RX(phi, wires=[1]), + qml.RX(varphi, wires=[2]), + qml.CNOT(wires=[0, 1]), + qml.CNOT(wires=[1, 2]), + ], + obs.diagonalizing_gates(), + ) + + res = dev.var(obs) + + expected = ( + 1057 + - torch.cos(2 * phi) + + 12 * (27 + torch.cos(2 * phi)) * torch.cos(varphi) + - 2 + * torch.cos(2 * varphi) + * torch.sin(phi) + * (16 * torch.cos(phi) + 21 * torch.sin(phi)) + + 16 * torch.sin(2 * phi) + - 8 * (-17 + torch.cos(2 * phi) + 2 * torch.sin(2 * phi)) * torch.sin(varphi) + - 8 * torch.cos(2 * theta) * (3 + 3 * torch.cos(varphi) + torch.sin(varphi)) ** 2 + - 24 * torch.cos(phi) * (torch.cos(phi) + 2 * torch.sin(phi)) * torch.sin(2 * varphi) + - 8 + * torch.cos(theta) + * ( + 4 + * torch.cos(phi) + * ( + 4 + + 8 * torch.cos(varphi) + + torch.cos(2 * varphi) + - (1 + 6 * torch.cos(varphi)) * torch.sin(varphi) + ) + + torch.sin(phi) + * ( + 15 + + 8 * torch.cos(varphi) + - 11 * torch.cos(2 * varphi) + + 42 * torch.sin(varphi) + + 3 * torch.sin(2 * varphi) + ) + ) + ) / 16 + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + +##################################################### +# QNode-level integration tests +##################################################### + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestQNodeIntegration: + """Integration tests for default.qubit.torch. This test ensures it integrates + properly with the PennyLane UI, in particular the new QNode.""" + + def test_defines_correct_capabilities(self, torch_device): + """Test that the device defines the right capabilities""" + + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + cap = dev.capabilities() + capabilities = { + "model": "qubit", + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "returns_state": True, + "supports_inverse_operations": True, + "supports_analytic_computation": True, + "supports_broadcasting": True, + "passthru_interface": "torch", + "passthru_devices": { + "torch": "default.qubit.torch", + "tf": "default.qubit.tf", + "autograd": "default.qubit.autograd", + "jax": "default.qubit.jax", + }, + } + assert cap == capabilities + + def test_load_torch_device(self, torch_device): + """Test that the torch device plugin loads correctly""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + assert dev.num_wires == 2 + assert dev.shots is None + assert dev.short_name == "default.qubit.torch" + assert dev.capabilities()["passthru_interface"] == "torch" + assert dev._torch_device == torch_device + + def test_qubit_circuit(self, torch_device, tol): + """Test that the torch device provides correct + result for a simple circuit using the old QNode.""" + p = torch.tensor(0.543, dtype=torch.float64, device=torch_device) + + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -torch.sin(p) + + assert circuit.gradient_fn == "backprop" + assert torch.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_qubit_circuit_broadcasted(self, torch_device, tol): + """Test that the torch device provides correct + result for a simple circuit using the old QNode.""" + p = torch.tensor([0.543, 0.21, 2.41], dtype=torch.float64, device=torch_device) + + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + expected = -torch.sin(p) + + assert circuit.gradient_fn == "backprop" + assert torch.allclose(circuit(p), expected, atol=tol, rtol=0) + + def test_correct_state(self, torch_device, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + state = dev.state + expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) + assert torch.allclose(state, expected, atol=tol, rtol=0) + + input_param = torch.tensor(math.pi / 4, device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(input_param, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + amplitude = np.exp(-1j * math.pi / 8) / math.sqrt(2) + + expected = torch.tensor( + [amplitude, 0, amplitude.conjugate(), 0], dtype=torch.complex128, device=torch_device + ) + assert torch.allclose(state, expected, atol=tol, rtol=0) + + def test_correct_state_broadcasted(self, torch_device, tol): + """Test that the device state is correct after applying a + quantum function on the device""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + state = dev.state + expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) + assert torch.allclose(state, expected, atol=tol, rtol=0) + + input_param = torch.tensor([math.pi / 4, math.pi / 2], device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(): + qml.Hadamard(wires=0) + qml.RZ(input_param, wires=0) + return qml.expval(qml.PauliZ(0)) + + circuit() + state = dev.state + + phase = np.exp(-1j * np.pi / 8) + + expected = torch.tensor( + [ + [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], + [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], + ], + dtype=torch.complex128, + device=torch_device, + ) + assert torch.allclose(state, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_one_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): + """Test the integration of the one-qubit single parameter rotations by passing + a Torch data structure as a parameter""" + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + state = init_state(1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(params): + qml.QubitStateVector(state, wires=[0]) + op(params[0], wires=[0]) + return qml.expval(qml.PauliZ(0)) + + params = torch.tensor([theta]) + circuit(params) + res = dev.state + expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, 4.213]) + @pytest.mark.parametrize("op,func", two_qubit_param) + def test_two_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): + """Test the integration of the two-qubit single parameter rotations by passing + a Torch data structure as a parameter""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + state = init_state(2, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1]) + op(params[0], wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + # Pass a Torch Variable to the qfunc + params = torch.tensor([theta], device=torch_device) + params = params.to(device=torch_device) + circuit(params) + res = dev.state + expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("theta", [0.5432, 4.213]) + @pytest.mark.parametrize("op,func", four_qubit_param) + def test_four_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): + """Test the integration of the four-qubit single parameter rotations by passing + a Torch data structure as a parameter""" + dev = qml.device("default.qubit.torch", wires=4, torch_device=torch_device) + state = init_state(4, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1, 2, 3]) + op(params[0], wires=[0, 1, 2, 3]) + return qml.expval(qml.PauliZ(0)) + + # Pass a Torch Variable to the qfunc + params = torch.tensor([theta], device=torch_device) + circuit(params) + res = dev.state + expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_controlled_rotation_integration(self, torch_device, init_state, tol): + """Test the integration of the two-qubit controlled rotation by passing + a Torch data structure as a parameter""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + a = torch.tensor(1.7, device=torch_device) + b = torch.tensor(1.3432, device=torch_device) + c = torch.tensor(-0.654, device=torch_device) + state = init_state(2, torch_device=torch_device) + + @qml.qnode(dev, interface="torch") + def circuit(params): + qml.QubitStateVector(state, wires=[0, 1]) + qml.CRot(params[0], params[1], params[2], wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + # Pass a Torch Variable to the qfunc + params = torch.tensor([a, b, c], device=torch_device) + circuit(params) + res = dev.state + expected = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) @ state + assert torch.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestPassthruIntegration: + """Tests for integration with the PassthruQNode""" + + def test_jacobian_variable_multiply(self, torch_device, tol): + """Test that jacobian of a QNode with an attached default.qubit.torch device + gives the correct result in the case of parameters multiplied by scalars""" + x = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) + y = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) + z = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) + + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit([x, y, z]) + res.backward() # pylint:disable=no-member + + expected = torch.cos(3 * x) * torch.cos(y) * torch.cos(z / 2) - torch.sin( + 3 * x + ) * torch.sin(z / 2) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + x_grad = -3 * ( + torch.sin(3 * x) * torch.cos(y) * torch.cos(z / 2) + torch.cos(3 * x) * torch.sin(z / 2) + ) + y_grad = -torch.cos(3 * x) * torch.sin(y) * torch.cos(z / 2) + z_grad = -0.5 * ( + torch.sin(3 * x) * torch.cos(z / 2) + torch.cos(3 * x) * torch.cos(y) * torch.sin(z / 2) + ) + + assert torch.allclose(x.grad, x_grad) + assert torch.allclose(y.grad, y_grad) + assert torch.allclose(z.grad, z_grad) + + def test_jacobian_variable_multiply_broadcasted(self, torch_device, tol): + """Test that jacobian of a QNode with an attached default.qubit.torch device + gives the correct result in the case of parameters multiplied by scalars""" + x = torch.tensor( + [0.431, 92.1, -0.5129], dtype=torch.float64, requires_grad=True, device=torch_device + ) + y = torch.tensor( + [0.2162158, 0.241, -0.51], dtype=torch.float64, requires_grad=True, device=torch_device + ) + z = torch.tensor( + [0.75110998, 0.12512, 9.12], + dtype=torch.float64, + requires_grad=True, + device=torch_device, + ) + + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(p): + qml.RX(3 * p[0], wires=0) + qml.RY(p[1], wires=0) + qml.RX(p[2] / 2, wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit([x, y, z]) + + expected = torch.cos(3 * x) * torch.cos(y) * torch.cos(z / 2) - torch.sin( + 3 * x + ) * torch.sin(z / 2) + assert qml.math.shape(res) == (3,) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + jac = torch.autograd.functional.jacobian(circuit, (qml.math.stack([x, y, z]),))[0] + expected = qml.math.stack( + [ + -3 + * ( + torch.sin(3 * x) * torch.cos(y) * torch.cos(z / 2) + + torch.cos(3 * x) * torch.sin(z / 2) + ), + -torch.cos(3 * x) * torch.sin(y) * torch.cos(z / 2), + -0.5 + * ( + torch.sin(3 * x) * torch.cos(z / 2) + + torch.cos(3 * x) * torch.cos(y) * torch.sin(z / 2) + ), + ] + ) + + assert all(torch.allclose(jac[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) + + def test_jacobian_repeated(self, torch_device, tol): + """Test that jacobian of a QNode with an attached default.qubit.torch device + gives the correct result in the case of repeated parameters""" + x = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) + y = torch.tensor(0.2162158, dtype=torch.float64, requires_grad=True, device=torch_device) + z = torch.tensor(0.75110998, dtype=torch.float64, requires_grad=True, device=torch_device) + p = torch.tensor([x, y, z], requires_grad=True, device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + res.backward() # pylint:disable=no-member + + expected = torch.cos(y) ** 2 - torch.sin(x) * torch.sin(y) ** 2 + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + expected_grad = torch.tensor( + [ + -torch.cos(x) * torch.sin(y) ** 2, + -2 * (torch.sin(x) + 1) * torch.sin(y) * torch.cos(y), + 0, + ], + dtype=torch.float64, + device=torch_device, + ) + assert torch.allclose(p.grad, expected_grad, atol=tol, rtol=0) + + def test_jacobian_repeated_broadcasted(self, torch_device, tol): + """Test that jacobian of a QNode with an attached default.qubit.torch device + gives the correct result in the case of repeated parameters""" + p = torch.tensor( + [[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]], + dtype=torch.float64, + device=torch_device, + requires_grad=True, + ) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(x): + qml.RX(x[1], wires=0) + qml.Rot(x[0], x[1], x[2], wires=0) + return qml.expval(qml.PauliZ(0)) + + res = circuit(p) + + x, y, _ = p + expected = torch.cos(y) ** 2 - torch.sin(x) * torch.sin(y) ** 2 + + assert torch.allclose(res, expected, atol=tol, rtol=0) + + jac = torch.autograd.functional.jacobian(circuit, (p,))[0] + expected_jac = torch.stack( + [ + -torch.cos(x) * torch.sin(y) ** 2, + -2 * (torch.sin(x) + 1) * torch.sin(y) * torch.cos(y), + torch.zeros_like(x) * torch.zeros_like(y), + ], + ) + assert all( + torch.allclose(jac[i, :, i], expected_jac[:, i], atol=tol, rtol=0) for i in range(3) + ) + + def test_jacobian_agrees_backprop_parameter_shift(self, torch_device, tol): + """Test that jacobian of a QNode with an attached default.qubit.torch device + gives the correct result with respect to the parameter-shift method""" + p = pnp.array([0.43316321, 0.2162158, 0.75110998, 0.94714242], requires_grad=True) + + def circuit(x): + for i in range(0, len(p), 2): + qml.RX(x[i], wires=0) + qml.RY(x[i + 1], wires=1) + for i in range(2): + qml.CNOT(wires=[i, i + 1]) + return qml.expval(qml.PauliZ(0)) # , qml.var(qml.PauliZ(1)) + + dev1 = qml.device("default.qubit.torch", wires=3, torch_device=torch_device) + dev2 = qml.device("default.qubit", wires=3) + + circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="torch") + circuit2 = qml.QNode(circuit, dev2, diff_method="parameter-shift") + + p_torch = torch.tensor(p, requires_grad=True, device=torch_device) + res = circuit1(p_torch) + res.backward() + + assert qml.math.allclose(res, circuit2(p), atol=tol, rtol=0) + + p_grad = p_torch.grad + assert qml.math.allclose(p_grad, qml.jacobian(circuit2)(p), atol=tol, rtol=0) + + @pytest.mark.parametrize("wires", [[0], ["abc"]]) + def test_state_differentiability(self, torch_device, wires, tol): + """Test that the device state can be differentiated""" + dev = qml.device("default.qubit.torch", wires=wires, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a): + qml.RY(a, wires=wires[0]) + return qml.state() + + a = torch.tensor(0.54, requires_grad=True, device=torch_device) + + res = torch.abs(circuit(a)) ** 2 + res = res[1] - res[0] + res.backward() + + grad = a.grad + expected = torch.sin(a) + assert torch.allclose(grad, expected, atol=tol, rtol=0) + + def test_state_differentiability_broadcasted(self, torch_device, tol): + """Test that the device state can be differentiated""" + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a): + qml.RY(a, wires=0) + return qml.expval(qml.PauliZ(0)) + + a = torch.tensor([0.54, 0.32, 1.2], requires_grad=True, device=torch_device) + + def cost(a): + circuit(a) + res = torch.abs(dev.state) ** 2 + return res[:, 1] - res[:, 0] + + jac = torch.autograd.functional.jacobian(cost, (a,))[0] + expected = torch.sin(a) + assert torch.allclose(qml.math.diag(jac), expected, atol=tol, rtol=0) + + def test_prob_differentiability(self, torch_device, tol): + """Test that the device probability can be differentiated""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = torch.tensor(0.54, requires_grad=True, dtype=torch.float64, device=torch_device) + b = torch.tensor(0.12, requires_grad=True, dtype=torch.float64, device=torch_device) + + # 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] # pylint:disable=unsubscriptable-object + res.backward() + + expected = -torch.cos(a) * torch.cos(b) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + assert torch.allclose(a.grad, torch.sin(a) * torch.cos(b), atol=tol, rtol=0) + assert torch.allclose(b.grad, torch.cos(a) * torch.sin(b), atol=tol, rtol=0) + + def test_prob_differentiability_broadcasted(self, torch_device, tol): + """Test that the device probability can be differentiated""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a, b): + qml.RX(a, wires=0) + qml.RY(b, wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[1]) + + a = torch.tensor( + [0.54, 0.32, 1.2], requires_grad=True, dtype=torch.float64, device=torch_device + ) + b = torch.tensor(0.12, requires_grad=True, dtype=torch.float64, device=torch_device) + + 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] # pylint:disable=unsubscriptable-object + return res + + res = cost(a, b) + expected = -torch.cos(a) * torch.cos(b) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + jac = torch.autograd.functional.jacobian(cost, (a, b)) + assert torch.allclose(qml.math.diag(jac[0]), torch.sin(a) * torch.cos(b), atol=tol, rtol=0) + assert torch.allclose(jac[1], torch.cos(a) * torch.sin(b), atol=tol, rtol=0) + + def test_backprop_gradient(self, torch_device, tol): + """Tests that the gradient of the qnode is correct""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = torch.tensor(-0.234, dtype=torch.float64, requires_grad=True, device=torch_device) + b = torch.tensor(0.654, dtype=torch.float64, requires_grad=True, device=torch_device) + + res = circuit(a, b) + 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) + + assert torch.allclose(res, expected_cost, atol=tol, rtol=0) + + assert torch.allclose(a.grad, -0.5 * torch.sin(a) * (torch.cos(b) + 1), atol=tol, rtol=0) + assert torch.allclose(b.grad, 0.5 * torch.sin(b) * (1 - torch.cos(a))) + + def test_backprop_gradient_broadcasted(self, torch_device, tol): + """Tests that the gradient of the qnode is correct""" + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + + @qml.qnode(dev, diff_method="backprop", interface="torch") + def circuit(a, b): + qml.RX(a, wires=0) + qml.CRX(b, wires=[0, 1]) + return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) + + a = torch.tensor(-0.234, dtype=torch.float64, requires_grad=True, device=torch_device) + b = torch.tensor( + [0.54, 0.32, 1.2], dtype=torch.float64, requires_grad=True, device=torch_device + ) + + res = circuit(a, b) + # 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) + + assert torch.allclose(res, expected_cost, atol=tol, rtol=0) + + jac = torch.autograd.functional.jacobian(circuit, (a, b)) + assert torch.allclose(jac[0], -0.5 * torch.sin(a) * (torch.cos(b) + 1), atol=tol, rtol=0) + assert torch.allclose(qml.math.diag(jac[1]), 0.5 * torch.sin(b) * (1 - torch.cos(a))) + + @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) + def test_hessian_at_zero(self, torch_device, x, shift): + """Tests that the Hessian at vanishing state vector amplitudes + is correct.""" + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + x = torch.tensor(x, requires_grad=True) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(x): + qml.RY(shift, wires=0) + qml.RY(x, wires=0) + return qml.expval(qml.PauliZ(0)) + + grad = torch.autograd.functional.jacobian(circuit, x) + hess = torch.autograd.functional.hessian(circuit, x) + + assert qml.math.isclose(grad, torch.tensor(0.0)) + assert qml.math.isclose(hess, torch.tensor(-1.0)) + + @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) + @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) + def test_torch_interface_gradient(self, torch_device, operation, diff_method, tol): + """Tests that the gradient of an arbitrary U3 gate is correct + using the PyTorch interface, using a variety of differentiation methods.""" + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + input_state = torch.tensor(1j * np.array([1, -1]) / math.sqrt(2), device=torch_device) + + @qml.qnode(dev, diff_method=diff_method, interface="torch") + def circuit(x, weights, w): + """In this example, a mixture of scalar + arguments, array arguments, and keyword arguments are used.""" + qml.QubitStateVector(input_state, wires=w) + operation(x, weights[0], weights[1], wires=w) + return qml.expval(qml.PauliX(w)) + + # Check that the correct QNode type is being used. + if diff_method == "backprop": + assert circuit.gradient_fn == "backprop" + elif diff_method == "finite-diff": + assert circuit.gradient_fn is qml.gradients.finite_diff + + def cost(params): + """Perform some classical processing""" + return circuit(params[0], params[1:], w=0) ** 2 + + theta = torch.tensor(0.543, dtype=torch.float64, device=torch_device) + phi = torch.tensor(-0.234, dtype=torch.float64, device=torch_device) + lam = torch.tensor(0.654, dtype=torch.float64, device=torch_device) + + params = torch.tensor( + [theta, phi, lam], dtype=torch.float64, requires_grad=True, device=torch_device + ) + + res = cost(params) + res.backward() + + # check that the result is correct + expected_cost = ( + torch.sin(lam) * torch.sin(phi) - torch.cos(theta) * torch.cos(lam) * torch.cos(phi) + ) ** 2 + assert torch.allclose(res, expected_cost, atol=tol, rtol=0) + + # check that the gradient is correct + expected_grad = ( + torch.tensor( + [ + torch.sin(theta) * torch.cos(lam) * torch.cos(phi), + torch.cos(theta) * torch.cos(lam) * torch.sin(phi) + + torch.sin(lam) * torch.cos(phi), + torch.cos(theta) * torch.sin(lam) * torch.cos(phi) + + torch.cos(lam) * torch.sin(phi), + ], + device=torch_device, + ) + * 2 + * (torch.sin(lam) * torch.sin(phi) - torch.cos(theta) * torch.cos(lam) * torch.cos(phi)) + ) + assert torch.allclose(params.grad, expected_grad, atol=tol, rtol=0) + + @pytest.mark.parametrize("interface", ["autograd", "torch"]) + def test_error_backprop_wrong_interface(self, torch_device, interface): + """Tests that an error is raised if diff_method='backprop' but not using + the torch interface""" + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + + def circuit(x, w=None): + qml.RZ(x, wires=w) + return qml.expval(qml.PauliX(w)) + + with pytest.raises(Exception) as e: + assert qml.qnode(dev, diff_method="autograd", interface=interface)(circuit) + assert str(e.value) == ( + "Differentiation method autograd not recognized. Allowed options are ('best', " + "'parameter-shift', 'backprop', 'finite-diff', 'device', 'adjoint', 'spsa', 'hadamard')." + ) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestSamples: + """Tests for sampling outputs""" + + def test_sample_observables(self, torch_device): + """Test that the device allows for sampling from observables.""" + shots = 100 + dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(a): + qml.RX(a, wires=0) + return qml.sample(qml.PauliZ(0)) + + a = torch.tensor(0.54, dtype=torch.float64, device=torch_device) + res = circuit(a) + + assert torch.is_tensor(res) + 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) + ) + + def test_estimating_marginal_probability(self, torch_device, tol): + """Test that the probability of a subset of wires is accurately estimated.""" + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(): + qml.PauliX(0) + return qml.probs(wires=[0]) + + res = circuit() + + assert torch.is_tensor(res) + + expected = torch.tensor([0, 1], dtype=torch.float64, device=torch_device) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_estimating_full_probability(self, torch_device, tol): + """Test that the probability of a subset of wires is accurately estimated.""" + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(): + qml.PauliX(0) + qml.PauliX(1) + return qml.probs(wires=[0, 1]) + + res = circuit() + + assert torch.is_tensor(res) + + expected = torch.tensor([0, 0, 0, 1], dtype=torch.float64, device=torch_device) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + def test_estimating_expectation_values(self, torch_device): + """Test that estimating expectation values using a finite number + of shots produces a numeric tensor""" + dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(a, b): + qml.RX(a, wires=[0]) + qml.RX(b, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) + + a = torch.tensor(0.543, dtype=torch.float64, device=torch_device) + b = torch.tensor(0.43, dtype=torch.float64, device=torch_device) + + res = circuit(a, b) + assert isinstance(res, tuple) + + # We don't check the expected value due to stochasticity, but + # leave it here for completeness. + # expected = [torch.cos(a), torch.cos(a) * torch.cos(b)] + # assert np.allclose(res, expected, atol=tol, rtol=0) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestSamplesBroadcasted: + """Tests for sampling outputs""" + + @pytest.mark.skip("Sampling from observables is not supported with broadcasting") + @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) + def test_sample_observables_broadcasted(self, torch_device, a): + """Test that the device allows for sampling from observables.""" + batch_size = len(a) + shots = 100 + dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(a): + qml.RX(a, wires=0) + return qml.sample(qml.PauliZ(0)) + + a = torch.tensor(a, dtype=torch.float64, device=torch_device) + res = circuit(a) + + assert torch.is_tensor(res) + 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) + ) + + @pytest.mark.parametrize("batch_size", [2, 3]) + def test_estimating_marginal_probability_broadcasted(self, torch_device, batch_size, tol): + """Test that the probability of a subset of wires is accurately estimated.""" + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(): + qml.RX(torch.zeros(batch_size), 0) + qml.PauliX(0) + return qml.probs(wires=[0]) + + res = circuit() + + assert torch.is_tensor(res) + assert qml.math.shape(res) == (batch_size, 2) + + expected = torch.tensor([[0, 1]] * batch_size, dtype=torch.float64, device=torch_device) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.parametrize("batch_size", [2, 3]) + def test_estimating_full_probability_broadcasted(self, torch_device, batch_size, tol): + """Test that the probability of a subset of wires is accurately estimated.""" + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(): + qml.RX(torch.zeros(batch_size), 0) + qml.PauliX(0) + qml.PauliX(1) + return qml.probs(wires=[0, 1]) + + res = circuit() + + assert torch.is_tensor(res) + assert qml.math.shape(res) == (batch_size, 4) + + expected = torch.tensor( + [[0, 0, 0, 1]] * batch_size, dtype=torch.float64, device=torch_device + ) + assert torch.allclose(res, expected, atol=tol, rtol=0) + + @pytest.mark.skip("Multiple return values are not supported with broadcasting") + @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) + def test_estimating_expectation_values_broadcasted(self, torch_device, a): + """Test that estimating expectation values using a finite number + of shots produces a numeric tensor""" + batch_size = len(a) + dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) + + @qml.qnode(dev, diff_method=None, interface="torch") + def circuit(a, b): + qml.RX(a, wires=[0]) + qml.RX(b, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) + + a = torch.tensor(a, dtype=torch.float64, device=torch_device) + b = torch.tensor(0.43, dtype=torch.float64, device=torch_device) + + res = circuit(a, b) + assert torch.is_tensor(res) + assert qml.math.shape(res) == (batch_size, 2) + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestHighLevelIntegration: + """Tests for integration with higher level components of PennyLane.""" + + def test_sampling_analytic_mode(self, torch_device): + """Test that when sampling with shots=None, dev uses 1000 shots and + raises an error. + """ + dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(): + return qml.sample(qml.PauliZ(wires=0)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The number of shots has to be explicitly set on the device", + ): + circuit() + + def test_sampling_analytic_mode_with_counts(self, torch_device): + """Test that when sampling with counts and shots=None an error is raised.""" + dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(): + return qml.counts(qml.PauliZ(wires=0)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The number of shots has to be explicitly set on the device " + "when using sample-based measurements.", + ): + circuit() + + +@pytest.mark.torch +@pytest.mark.parametrize("torch_device", torch_devices) +class TestCtrlOperator: + """Test-case for qml.ctrl operator with in-built parametric gates.""" + + @pytest.mark.parametrize( + "ops", + [ + ( + qml.RX, + torch.tensor( + [ + 0.70172985 - 0.08687008j, + -0.0053667 + 0.0j, + 0.70039457 - 0.08703569j, + 0.0 - 0.04326927j, + ], + dtype=torch.complex128, + ), + ), + ( + qml.RY, + torch.tensor( + [ + 0.70172985 - 0.08687008j, + 0.0 - 0.0053667j, + 0.70039457 - 0.08703569j, + 0.04326927 + 0.0j, + ], + dtype=torch.complex128, + ), + ), + ( + qml.RZ, + torch.tensor( + [0.69636316 - 0.08687008j, 0.0 + 0.0j, 0.70039457 - 0.13030496j, 0.0 + 0.0j], + dtype=torch.complex128, + ), + ), + ], + ) + def test_ctrl_r_operators(self, torch_device, ops, tol): + """Test qml.ctrl using R-gate targets""" + dev = qml.device("default.qubit.torch", wires=2, shots=None, torch_device=torch_device) + par = torch.tensor([0.12345, 0.2468], dtype=torch.float64, device=torch_device) + + @qml.qnode(dev, interface="torch", diff_method="backprop") + def circuit(params): + qml.Hadamard(0) + qml.ctrl(op=ops[0](params[0], wires=1), control=0) + qml.RX(params[1], wires=0) + return qml.state() + + result = circuit(par) + assert torch.allclose( + result, + ops[1].to(device=torch_device), + atol=tol, + rtol=0, + ) From de4e5fa53cda43b1be6bf1409f9b29365c21d749 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 31 Jul 2023 16:19:14 -0400 Subject: [PATCH 02/78] remove tests for old device; use explicit constructor for DQ1 --- .../default_qubit_1/test_default_qubit.py | 112 +- .../test_default_qubit_autograd.py | 63 +- .../test_default_qubit_broadcasting.py | 69 +- .../default_qubit_1/test_default_qubit_jax.py | 112 +- .../default_qubit_1/test_default_qubit_tf.py | 105 +- .../test_default_qubit_torch.py | 77 +- tests/devices/test_default_qubit.py | 2496 ----------------- tests/devices/test_default_qubit_autograd.py | 802 ------ .../test_default_qubit_broadcasting.py | 2023 ------------- tests/devices/test_default_qubit_jax.py | 1311 --------- tests/devices/test_default_qubit_tf.py | 2313 --------------- tests/devices/test_default_qubit_torch.py | 2492 ---------------- 12 files changed, 272 insertions(+), 11703 deletions(-) delete mode 100644 tests/devices/test_default_qubit.py delete mode 100644 tests/devices/test_default_qubit_autograd.py delete mode 100644 tests/devices/test_default_qubit_broadcasting.py delete mode 100644 tests/devices/test_default_qubit_jax.py delete mode 100644 tests/devices/test_default_qubit_tf.py delete mode 100644 tests/devices/test_default_qubit_torch.py diff --git a/tests/devices/default_qubit_1/test_default_qubit.py b/tests/devices/default_qubit_1/test_default_qubit.py index 153a7a1aeb9..214eee42e7d 100644 --- a/tests/devices/default_qubit_1/test_default_qubit.py +++ b/tests/devices/default_qubit_1/test_default_qubit.py @@ -98,17 +98,17 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - qml.device("default.qubit", wires=1, shots=1, analytic=True) + DefaultQubit(wires=1, shots=1, analytic=True) def test_dtype_errors(): """Test that if an incorrect dtype is provided to the device then an error is raised.""" with pytest.raises(DeviceError, match="Real datatype must be a floating point type."): - qml.device("default.qubit", wires=1, r_dtype=np.complex128) + DefaultQubit(wires=1, r_dtype=np.complex128) with pytest.raises( DeviceError, match="Complex datatype must be a complex floating point type." ): - qml.device("default.qubit", wires=1, c_dtype=np.float64) + DefaultQubit(wires=1, c_dtype=np.float64) def test_custom_op_with_matrix(): @@ -125,7 +125,7 @@ def compute_matrix(self): # pylint:disable=arguments-differ qml.state() tape = qml.tape.QuantumScript.from_queue(q) - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) assert qml.math.allclose(dev.execute(tape), np.array([1, 0])) @@ -775,7 +775,7 @@ def test_expval_two_wires_with_parameters( def test_expval_estimate(self): """Test that the expectation value is not analytically calculated""" - dev = qml.device("default.qubit", wires=1, shots=3) + dev = DefaultQubit(wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -902,7 +902,7 @@ def test_var_two_wires_with_parameters( def test_var_estimate(self): """Test that the variance is not analytically calculated""" - dev = qml.device("default.qubit", wires=1, shots=3) + dev = DefaultQubit(wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -926,7 +926,7 @@ def test_sample_dimensions(self): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) dev.apply([qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])]) @@ -958,7 +958,7 @@ def test_sample_values(self, tol): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) dev.apply([qml.RX(1.5708, wires=[0])]) dev._wires_measured = {0} @@ -978,7 +978,7 @@ class TestDefaultQubitIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1035,7 +1035,7 @@ def test_nonzero_shots(self, tol): """Test that the default qubit plugin provides correct result for high shot number""" shots = 10**5 - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = DefaultQubit(wires=1, shots=shots) p = 0.543 @@ -1178,7 +1178,7 @@ def test_multi_samples_return_correlated_results(self): the correct dimensions """ - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -1198,7 +1198,7 @@ def test_multi_samples_return_correlated_results_more_wires_than_size_of_observa the correct dimensions """ - dev = qml.device("default.qubit", wires=num_wires, shots=1000) + dev = DefaultQubit(wires=num_wires, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -1218,7 +1218,7 @@ class TestTensorExpval: def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1242,7 +1242,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1266,7 +1266,7 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1289,7 +1289,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() A = np.array( @@ -1327,7 +1327,7 @@ def test_hermitian(self, theta, phi, varphi, tol): def test_hermitian_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1376,7 +1376,7 @@ def test_hermitian_hermitian(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1400,7 +1400,7 @@ def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1429,7 +1429,7 @@ class TestTensorVar: def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1459,7 +1459,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1487,7 +1487,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A = np.array( [ @@ -1553,7 +1553,7 @@ class TestTensorSample: def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1595,7 +1595,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.apply( [ @@ -1633,7 +1633,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): def test_hermitian(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) A = 0.1 * np.array( [ @@ -1748,7 +1748,7 @@ def test_state_dtype_after_op(self, r_dtype, c_dtype, op): examples. """ - dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=4, r_dtype=r_dtype, c_dtype=c_dtype) n_wires = op.num_wires n_params = op.num_params @@ -1779,7 +1779,7 @@ def test_measurement_real_dtype(self, r_dtype, c_dtype, measurement): """Test that the default qubit plugin provides correct result for a simple circuit""" p = 0.543 - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1797,7 +1797,7 @@ def test_measurement_complex_dtype(self, r_dtype, c_dtype, measurement): """Test that the default qubit plugin provides correct result for a simple circuit""" p = 0.543 - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1819,8 +1819,8 @@ def mock_analytic_counter(self, wires=None): @pytest.mark.parametrize("x", [[0.2, 0.5], [0.4, 0.9], [0.8, 0.3]]) def test_probability(self, x, tol): """Test that the probability function works for finite and infinite shots""" - dev = qml.device("default.qubit", wires=2, shots=1000) - dev_analytic = qml.device("default.qubit", wires=2, shots=None) + dev = DefaultQubit(wires=2, shots=1000) + dev_analytic = DefaultQubit(wires=2, shots=None) def circuit(x): qml.RX(x[0], wires=0) @@ -1840,7 +1840,7 @@ def test_call_generate_samples(self, monkeypatch): """Test analytic_probability call when generating samples""" self.analytic_counter = False - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) monkeypatch.setattr(dev, "analytic_probability", self.mock_analytic_counter) # generate samples through `generate_samples` (using 'analytic_probability') @@ -1851,7 +1851,7 @@ def test_call_generate_samples(self, monkeypatch): def test_stateless_analytic_return(self): """Test that analytic_probability returns None if device is stateless""" - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) dev._state = None assert dev.analytic_probability() is None @@ -1862,7 +1862,7 @@ class TestWiresIntegration: def make_circuit_probs(self, wires): """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = qml.device("default.qubit", wires=wires) + dev = DefaultQubit(wires=wires) n_wires = len(wires) @qml.qnode(dev, diff_method="parameter-shift") @@ -1895,7 +1895,7 @@ def test_wires_probs(self, wires1, wires2, tol): def test_wires_not_found_exception(self): """Tests that an exception is raised when wires not present on the device are adressed.""" - dev = qml.device("default.qubit", wires=["a", "b"]) + dev = DefaultQubit(wires=["a", "b"]) with qml.queuing.AnnotatedQueue() as q: qml.RX(0.5, wires="c") @@ -1914,7 +1914,8 @@ def test_wires_not_found_exception(self): @pytest.mark.parametrize("dev_wires, wires_to_map", wires_to_try) def test_map_wires_caches(self, dev_wires, wires_to_map): """Test that multiple calls to map_wires will use caching.""" - dev = qml.device("default.qubit", wires=dev_wires) + # pylint:disable=no-value-for-parameter + dev = DefaultQubit(wires=dev_wires) original_hits = dev.map_wires.cache_info().hits original_misses = dev.map_wires.cache_info().misses @@ -1985,7 +1986,7 @@ class TestApplyOps: gates in DefaultQubit.""" state = np.arange(2**4, dtype=np.complex128).reshape((2, 2, 2, 2)) - dev = qml.device("default.qubit", wires=4) + dev = DefaultQubit(wires=4) single_qubit_ops = [ (qml.PauliX, dev._apply_x), @@ -2137,7 +2138,7 @@ def test_internal_apply_ops_case(self, monkeypatch): This test provides a new internal function that `default.qubit` uses to apply `PauliX` (rather than redefining the gate itself). """ - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) # Create a dummy operation expected_test_output = np.ones(1) @@ -2156,7 +2157,7 @@ def test_internal_apply_ops_case(self, monkeypatch): def test_diagonal_operation_case(self, monkeypatch): """Tests the case when the operation to be applied is diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) par = 0.3 test_state = np.array([1, 0]) @@ -2169,6 +2170,7 @@ def test_diagonal_operation_case(self, monkeypatch): mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) with monkeypatch.context() as m: m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) + # pylint:disable=comparison-with-callable assert dev._apply_diagonal_unitary == mock_apply_diag dev._apply_operation(test_state, op) @@ -2182,7 +2184,7 @@ def test_diagonal_operation_case(self, monkeypatch): def test_apply_einsum_case(self, monkeypatch): """Tests the case when np.einsum is used to apply an operation in default.qubit.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) test_state = np.array([1, 0]) wires = 0 @@ -2220,7 +2222,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_tensordot_case(self, monkeypatch): """Tests the case when np.tensordot is used to apply an operation in default.qubit.""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) test_state = np.array([1, 0]) wires = [0, 1, 2] @@ -2259,7 +2261,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_unitary_tensordot_double_broadcasting_error(self): """Tests that an error is raised if attempting to use _apply_unitary with a broadcasted matrix and a broadcasted state simultaneously.""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) class BroadcastedToffoli(qml.operation.Operation): num_wires = 3 @@ -2280,7 +2282,7 @@ def compute_matrix(*params, **hyperparams): def test_identity_skipped(self, mocker): """Test that applying the identity operation does not perform any additional computations.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) starting_state = np.array([1, 0]) op = qml.Identity(0) @@ -2302,7 +2304,7 @@ class TestHamiltonianSupport: def test_do_not_split_analytic(self, mocker): """Tests that the Hamiltonian is not split for shots=None.""" - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="parameter-shift", interface=None) @@ -2317,7 +2319,7 @@ def circuit(): def test_split_finite_shots(self, mocker): """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = DefaultQubit(wires=2, shots=10) spy = mocker.spy(dev, "expval") H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @@ -2333,7 +2335,7 @@ def circuit(): def test_error_hamiltonian_expval_finite_shots(self): """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = DefaultQubit(wires=2, shots=10) H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) with pytest.raises(AssertionError, match="Hamiltonian must be used with shots=None"): @@ -2341,7 +2343,7 @@ def test_error_hamiltonian_expval_finite_shots(self): def test_error_hamiltonian_expval_wrong_wires(self): """Tests that expval fails if Hamiltonian uses non-device wires.""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = DefaultQubit(wires=2, shots=None) H = qml.Hamiltonian([0.1, 0.2, 0.3], [qml.PauliX(0), qml.PauliZ(1), qml.PauliY(2)]) with pytest.raises( @@ -2352,7 +2354,7 @@ def test_error_hamiltonian_expval_wrong_wires(self): def test_Hamiltonian_filtered_from_rotations(self, mocker): """Tests that the device does not attempt to get rotations for Hamiltonians.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = DefaultQubit(wires=2, shots=10) H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) spy = mocker.spy(qml.QubitDevice, "_get_diagonalizing_gates") @@ -2392,7 +2394,7 @@ def circuit(y, z, is_state_batched): def test_super_expval_not_called(self, is_state_batched, mocker): """Tests basic expval result, and ensures QubitDevice.expval is not called.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) spy = mocker.spy(qml.QubitDevice, "expval") obs = qml.sum(qml.s_prod(0.1, qml.PauliX(0)), qml.s_prod(0.2, qml.PauliZ(0))) assert np.isclose(dev.expval(obs), 0.2) @@ -2403,7 +2405,7 @@ def test_trainable_autograd(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with autograd.""" if is_state_batched: pytest.skip(msg="Broadcasting, qml.jacobian and new return types do not work together") - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) qnode = qml.QNode(self.circuit, dev, interface="autograd") y, z = np.array([1.1, 2.2]) actual = qml.grad(qnode, argnum=[0, 1])(y, z, is_state_batched) @@ -2414,7 +2416,7 @@ def test_trainable_torch(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with torch.""" import torch - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) qnode = qml.QNode(self.circuit, dev, interface="torch") y, z = torch.tensor(1.1, requires_grad=True), torch.tensor(2.2, requires_grad=True) _qnode = partial(qnode, is_state_batched=is_state_batched) @@ -2426,7 +2428,7 @@ def test_trainable_tf(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with tf.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) qnode = qml.QNode(self.circuit, dev, interface="tensorflow") y, z = tf.Variable(1.1, dtype=tf.float64), tf.Variable(2.2, dtype=tf.float64) with tf.GradientTape() as tape: @@ -2439,7 +2441,7 @@ def test_trainable_jax(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with jax.""" import jax - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) qnode = qml.QNode(self.circuit, dev, interface="jax") y, z = jax.numpy.array([1.1, 2.2]) actual = jax.jacobian(qnode, argnums=[0, 1])(y, z, is_state_batched) @@ -2452,7 +2454,7 @@ class TestGetBatchSize: @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) def test_batch_size_None(self, shape): """Test that a ``batch_size=None`` is reported correctly.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) tensor0 = np.ones(shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None tensor1 = np.arange(np.prod(shape)).reshape(shape) @@ -2462,7 +2464,7 @@ def test_batch_size_None(self, shape): @pytest.mark.parametrize("batch_size", [1, 3]) def test_batch_size_int(self, shape, batch_size): """Test that an integral ``batch_size`` is reported correctly.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) full_shape = (batch_size,) + shape tensor0 = np.ones(full_shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size @@ -2473,7 +2475,7 @@ def test_batch_size_int(self, shape, batch_size): def test_invalid_tensor(self): """Test that an error is raised if a tensor is provided that does not have a proper shape/ndim.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) with pytest.raises(ValueError, match="could not broadcast"): dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) diff --git a/tests/devices/default_qubit_1/test_default_qubit_autograd.py b/tests/devices/default_qubit_1/test_default_qubit_autograd.py index d1e01f99cc3..180b8987fd6 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_autograd.py +++ b/tests/devices/default_qubit_1/test_default_qubit_autograd.py @@ -18,6 +18,7 @@ import pennylane as qml from pennylane import numpy as np +from pennylane.devices import DefaultQubit from pennylane.devices.default_qubit_autograd import DefaultQubitAutograd from pennylane import DeviceError @@ -32,7 +33,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - qml.device("default.qubit.autograd", wires=1, shots=1, analytic=True) + DefaultQubitAutograd(wires=1, shots=1, analytic=True) @pytest.mark.autograd @@ -43,7 +44,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -66,7 +67,7 @@ def test_defines_correct_capabilities(self): def test_load_device(self): """Test that the plugin device loads correctly""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.autograd" @@ -77,7 +78,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit.""" p = np.array(0.543) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd") def circuit(x): @@ -94,7 +95,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple broadcasted circuit.""" p = np.array([0.543, 0.21, 1.5]) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd") def circuit(x): @@ -110,7 +111,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -134,7 +135,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -180,7 +181,7 @@ def test_real_dtype(self, r_dtype, measurement): real data type for a simple circuit""" p = 0.543 - dev = qml.device("default.qubit.autograd", wires=3) + dev = DefaultQubitAutograd(wires=3) dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="backprop") @@ -206,7 +207,7 @@ def test_real_dtype_broadcasted(self, r_dtype, measurement): real data type for a simple broadcasted circuit""" p = np.array([0.543, 0.21, 1.6]) - dev = qml.device("default.qubit.autograd", wires=3) + dev = DefaultQubitAutograd(wires=3) dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="backprop") @@ -227,7 +228,7 @@ def test_complex_dtype(self, c_dtype, measurement): complex data type for a simple circuit""" p = 0.543 - dev = qml.device("default.qubit.autograd", wires=3) + dev = DefaultQubitAutograd(wires=3) dev.C_DTYPE = c_dtype @qml.qnode(dev, diff_method="backprop") @@ -244,7 +245,7 @@ def test_complex_dtype_broadcasted(self, c_dtype): complex data type for a simple broadcasted circuit""" p = np.array([0.543, 0.21, 1.6]) - dev = qml.device("default.qubit.autograd", wires=3) + dev = DefaultQubitAutograd(wires=3) dev.C_DTYPE = c_dtype measurement = qml.state() @@ -270,7 +271,7 @@ def test_jacobian_variable_multiply(self, tol): z = 0.75110998 weights = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(p): @@ -306,7 +307,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): z = np.array([0.75110998, 0.12512, 9.12]) weights = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(p): @@ -341,7 +342,7 @@ def test_jacobian_repeated(self, tol): y = 0.2162158 z = 0.75110998 p = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -369,7 +370,7 @@ def test_jacobian_repeated_broadcasted(self, tol): y = np.array([0.2162158, 0.241, -0.51]) z = np.array([0.75110998, 0.12512, 9.12]) p = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -407,8 +408,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - dev1 = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=3) + dev1 = DefaultQubit(wires=3) + dev2 = DefaultQubit(wires=3) def cost(x): return qml.math.stack(circuit(x)) @@ -430,7 +431,7 @@ def cost(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=wires) + dev = DefaultQubitAutograd(wires=wires) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a): @@ -451,7 +452,7 @@ def cost(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a): @@ -473,7 +474,7 @@ def cost(a): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -499,7 +500,7 @@ def cost(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -526,7 +527,7 @@ def cost(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -549,7 +550,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -576,7 +577,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -593,7 +594,7 @@ def circuit(x): def test_autograd_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the Autograd interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) state = np.array(1j * np.array([1, -1]) / np.sqrt(2), requires_grad=False) @qml.qnode(dev, diff_method=diff_method, interface="autograd") @@ -644,7 +645,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface): """Tests that an error is raised if diff_method='backprop' but not using the Autograd interface""" - dev = qml.device("default.qubit.autograd", wires=1) + dev = DefaultQubitAutograd(wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -663,7 +664,7 @@ class TestHighLevelIntegration: def test_do_not_split_analytic_autograd(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the autograd device.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="autograd") @@ -679,7 +680,7 @@ def circuit(): def test_do_not_split_analytic_autograd_broadcasted(self, mocker): """Tests that the Hamiltonian is not split for shots=None and broadcasting using the autograd device.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="autograd") @@ -695,7 +696,7 @@ def circuit(): def test_template_integration(self): """Test that a PassthruQNode default.qubit.autograd works with templates.""" - dev = qml.device("default.qubit.autograd", wires=2) + dev = DefaultQubitAutograd(wires=2) @qml.qnode(dev, diff_method="backprop") def circuit(weights): @@ -718,7 +719,7 @@ def test_multirz_jacobian(self): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = qml.device("default.qubit.autograd", wires=wires) + dev = DefaultQubitAutograd(wires=wires) @qml.qnode(dev, diff_method="backprop") def circuit(param): @@ -764,7 +765,7 @@ def test_multirz_jacobian_broadcasted(self): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = qml.device("default.qubit.autograd", wires=wires) + dev = DefaultQubitAutograd(wires=wires) @qml.qnode(dev, diff_method="backprop") def circuit(param): diff --git a/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py b/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py index 4fb4bd2a84a..01108402691 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py +++ b/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py @@ -595,7 +595,7 @@ def test_expval_two_wires_with_parameters_broadcasted( def test_expval_estimate_broadcasted(self): """Test that the expectation value is not analytically calculated""" - dev = qml.device("default.qubit", wires=1, shots=3) + dev = DefaultQubit(wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -695,7 +695,7 @@ def test_var_two_wires_with_parameters_broadcasted( def test_var_estimate_broadcasted(self): """Test that the variance is not analytically calculated""" - dev = qml.device("default.qubit", wires=1, shots=3) + dev = DefaultQubit(wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -720,7 +720,7 @@ def test_sample_dimensions_broadcasted(self): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) dev.apply([qml.RX(np.array([np.pi / 2, 0.0]), 0), qml.RX(np.array([np.pi / 2, 0.0]), 1)]) @@ -756,7 +756,7 @@ def test_sample_values_broadcasted(self, tol): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) dev.apply([qml.RX(np.ones(3), wires=[0])]) dev._wires_measured = {0} @@ -810,7 +810,7 @@ def test_nonzero_shots_broadcasted(self, tol): """Test that the default qubit plugin provides correct result for high shot number""" shots = 10**5 - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = DefaultQubit(wires=1, shots=shots) p = np.array([0.543, np.pi / 2, 0.0, 1.0]) @@ -916,7 +916,7 @@ def test_multi_samples_return_correlated_results_broadcasted(self): correctly for correlated observables. """ - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = DefaultQubit(wires=2, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -937,7 +937,7 @@ def test_multi_samples_correlated_results_more_wires_than_observable_broadcasted correctly for correlated observables on larger devices than the observables """ - dev = qml.device("default.qubit", wires=num_wires, shots=1000) + dev = DefaultQubit(wires=num_wires, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -960,7 +960,7 @@ class TestTensorExpvalBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -984,7 +984,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1008,7 +1008,7 @@ def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1031,7 +1031,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) dev.reset() A = np.array( @@ -1069,7 +1069,7 @@ def test_hermitian_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1118,7 +1118,7 @@ def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1142,7 +1142,7 @@ def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, to def test_hermitian_two_wires_identity_expectation_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1173,7 +1173,7 @@ class TestTensorVarBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1203,7 +1203,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1231,7 +1231,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) A = np.array( [ @@ -1299,7 +1299,7 @@ class TestTensorSampleBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1341,7 +1341,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.apply( [ @@ -1379,7 +1379,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): def test_hermitian_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) + dev = DefaultQubit(wires=3, shots=int(1e6)) A = 0.1 * np.array( [ @@ -1494,7 +1494,7 @@ def test_state_dtype_after_op_broadcasted(self, r_dtype, c_dtype, op): examples. """ - dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=4, r_dtype=r_dtype, c_dtype=c_dtype) n_wires = op.num_wires n_params = op.num_params @@ -1526,7 +1526,7 @@ def test_measurement_real_dtype_broadcasted(self, r_dtype, c_dtype, measurement) """Test that the default qubit plugin provides correct result for a simple circuit""" p = np.array([0.543, 0.622, 1.3]) - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1541,7 +1541,7 @@ def test_measurement_complex_dtype_broadcasted(self, r_dtype, c_dtype): p = np.array([0.543, 0.622, 1.3]) m = qml.state() - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1562,8 +1562,8 @@ def mock_analytic_counter(self, wires=None): def test_probability_broadcasted(self, tol): """Test that the probability function works for finite and infinite shots""" - dev = qml.device("default.qubit", wires=2, shots=1000) - dev_analytic = qml.device("default.qubit", wires=2, shots=None) + dev = DefaultQubit(wires=2, shots=1000) + dev_analytic = DefaultQubit(wires=2, shots=None) x = np.array([[0.2, 0.5, 0.4], [0.9, 0.8, 0.3]]) @@ -1586,7 +1586,7 @@ class TestWiresIntegrationBroadcasted: def make_circuit_probs(self, wires): """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = qml.device("default.qubit", wires=wires) + dev = DefaultQubit(wires=wires) n_wires = len(wires) @qml.qnode(dev, diff_method="parameter-shift") @@ -1623,7 +1623,7 @@ class TestApplyOpsBroadcasted: gates in DefaultQubit.""" broadcasted_state = np.arange(2**4 * 3, dtype=np.complex128).reshape((3, 2, 2, 2, 2)) - dev = qml.device("default.qubit", wires=4) + dev = DefaultQubit(wires=4) single_qubit_ops = [ (qml.PauliX, dev._apply_x), @@ -1750,7 +1750,7 @@ def test_internal_apply_ops_case_broadcasted(self, monkeypatch): This test provides a new internal function that `default.qubit` uses to apply `PauliX` (rather than redefining the gate itself). """ - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) # Create a dummy operation @@ -1769,7 +1769,7 @@ def test_internal_apply_ops_case_broadcasted(self, monkeypatch): def test_diagonal_operation_case_broadcasted(self, monkeypatch): """Tests the case when the operation to be applied is diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) par = 0.3 test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) @@ -1782,6 +1782,7 @@ def test_diagonal_operation_case_broadcasted(self, monkeypatch): mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) with monkeypatch.context() as m: m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) + # pylint:disable=comparison-with-callable assert dev._apply_diagonal_unitary == mock_apply_diag dev._apply_operation(test_state, op) @@ -1795,7 +1796,7 @@ def test_diagonal_operation_case_broadcasted(self, monkeypatch): def test_apply_einsum_case_broadcasted(self, monkeypatch): """Tests the case when np.einsum is used to apply an operation in default.qubit.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) wires = 0 @@ -1834,7 +1835,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_tensordot_case_broadcasted(self, monkeypatch): """Tests the case when np.tensordot is used to apply an operation in default.qubit.""" - dev = qml.device("default.qubit", wires=3) + dev = DefaultQubit(wires=3) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) wires = [0, 1, 2] @@ -1873,7 +1874,7 @@ def compute_matrix(*params, **hyperparams): def test_identity_skipped_broadcasted(self, mocker): """Test that applying the identity operation does not perform any additional computations.""" - dev = qml.device("default.qubit", wires=1) + dev = DefaultQubit(wires=1) starting_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) op = qml.Identity(0) @@ -1895,7 +1896,7 @@ class TestHamiltonianSupportBroadcasted: def test_do_not_split_analytic_broadcasted(self, mocker): """Tests that the Hamiltonian is not split for shots=None.""" - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) Ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="parameter-shift", interface=None) @@ -1911,7 +1912,7 @@ def circuit(): def test_split_finite_shots_broadcasted(self, mocker): """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = DefaultQubit(wires=2, shots=10) spy = mocker.spy(dev, "expval") ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) diff --git a/tests/devices/default_qubit_1/test_default_qubit_jax.py b/tests/devices/default_qubit_1/test_default_qubit_jax.py index b805b2d1772..2e0689c9309 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_jax.py +++ b/tests/devices/default_qubit_1/test_default_qubit_jax.py @@ -39,7 +39,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - qml.device("default.qubit.jax", wires=1, shots=1, analytic=True) + DefaultQubitJax(wires=1, shots=1, analytic=True) # pylint: disable=too-many-public-methods @@ -51,7 +51,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -81,7 +81,7 @@ def test_defines_correct_capabilities_directly_from_class(self): def test_load_device(self): """Test that the plugin device loads correctly""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.jax" @@ -94,7 +94,7 @@ def test_load_device(self): def test_float_precision(self, jax_enable_x64, c_dtype, r_dtype): """Test that the plugin device uses the same float precision as the jax config.""" jax.config.update("jax_enable_x64", jax_enable_x64) - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) assert dev.state.dtype == c_dtype assert dev.state.real.dtype == r_dtype @@ -103,7 +103,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit.""" p = jnp.array(0.543) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -118,7 +118,7 @@ def test_qubit_circuit_with_jit(self, tol): result for a simple circuit under a jax.jit.""" p = jnp.array(0.543) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @jax.jit @qml.qnode(dev, interface="jax") @@ -141,7 +141,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple broadcasted circuit.""" p = jnp.array([0.543, 0.21, 1.5]) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -156,7 +156,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) state = dev.state expected = jnp.array([1, 0, 0, 0]) @@ -180,7 +180,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) state = dev.state expected = jnp.array([1, 0, 0, 0]) @@ -208,7 +208,7 @@ def circuit(): def test_correct_state_returned(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(): @@ -226,7 +226,7 @@ def circuit(): def test_correct_state_returned_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(): @@ -248,7 +248,7 @@ def circuit(): def test_probs_jax(self, tol): """Test that returning probs works with jax""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) + dev = DefaultQubitJax(wires=1, shots=100) expected = jnp.array([0.0, 1.0]) @qml.qnode(dev, interface="jax", diff_method=None) @@ -261,7 +261,7 @@ def circuit(): def test_probs_jax_broadcasted(self, tol): """Test that returning probs works with jax""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) + dev = DefaultQubitJax(wires=1, shots=100) expected = jnp.array([[0.0, 1.0]] * 3) @qml.qnode(dev, interface="jax", diff_method=None) @@ -275,7 +275,7 @@ def circuit(): def test_probs_jax_jit(self, tol): """Test that returning probs works with jax and jit""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) + dev = DefaultQubitJax(wires=1, shots=100) expected = jnp.array([0.0, 1.0]) @qml.qnode(dev, interface="jax", diff_method=None) @@ -295,7 +295,7 @@ def circuit(z): def test_custom_shots_probs_jax_jit(self, tol): """Test that returning probs works with jax and jit when using custom shot vector""" # pylint:disable=unsubscriptable-object - dev = qml.device("default.qubit.jax", wires=1, shots=(3, 2)) + dev = DefaultQubitJax(wires=1, shots=(3, 2)) expected = jnp.array([[0.0, 1.0], [0.0, 1.0]]) @jax.jit @@ -312,7 +312,7 @@ def circuit(): def test_custom_shots_probs_jax_jit_broadcasted(self, tol): """Test that returning probs works with jax and jit when using a custom shot vector and broadcasting""" - dev = qml.device("default.qubit.jax", wires=1, shots=(2, 2)) + dev = DefaultQubitJax(wires=1, shots=(2, 2)) expected = jnp.array([[[0.0, 1.0], [0.0, 1.0]]] * 5) @jax.jit @@ -330,7 +330,7 @@ def test_sampling_with_jit(self): @jax.jit def circuit(x, key): - dev = qml.device("default.qubit.jax", wires=1, shots=1000, prng_key=key) + dev = DefaultQubitJax(wires=1, shots=1000, prng_key=key) @qml.qnode(dev, interface="jax", diff_method=None) def inner_circuit(): @@ -356,7 +356,7 @@ def inner_circuit(): ) def test_qubit_state_vector_arg_jax_jit(self, state_vector, tol): """Test that Qubit state vector as argument works with a jax.jit""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) + dev = DefaultQubitJax(wires=list(range(2))) @jax.jit @qml.qnode(dev, interface="jax") @@ -374,7 +374,7 @@ def circuit(x): ) def test_qubit_state_vector_arg_jax(self, state_vector, tol): """Test that Qubit state vector as argument works with jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) + dev = DefaultQubitJax(wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -391,7 +391,7 @@ def circuit(x): ) def test_qubit_state_vector_jax_jit(self, state_vector, tol): """Test that Qubit state vector works with a jax.jit""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) + dev = DefaultQubitJax(wires=list(range(2))) @jax.jit @qml.qnode(dev, interface="jax") @@ -410,7 +410,7 @@ def circuit(x): ) def test_qubit_state_vector_jax(self, state_vector, tol): """Test that Qubit state vector works with a jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) + dev = DefaultQubitJax(wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -428,7 +428,7 @@ def circuit(x): ) def test_qubit_state_vector_jax_not_normed(self, state_vector): """Test that an error is raised when Qubit state vector is not normed works with a jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) + dev = DefaultQubitJax(wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -442,7 +442,7 @@ def circuit(x): def test_sampling_op_by_op(self): """Test that op-by-op sampling works as a new user would expect""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) + dev = DefaultQubitJax(wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -455,7 +455,7 @@ def circuit(): def test_sampling_analytic_mode(self): """Test that when sampling with shots=None an error is raised.""" - dev = qml.device("default.qubit.jax", wires=1, shots=None) + dev = DefaultQubitJax(wires=1, shots=None) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -470,7 +470,7 @@ def circuit(): def test_sampling_analytic_mode_with_counts(self): """Test that when sampling with counts and shots=None an error is raised.""" - dev = qml.device("default.qubit.jax", wires=1, shots=None) + dev = DefaultQubitJax(wires=1, shots=None) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -485,7 +485,7 @@ def circuit(): def test_gates_dont_crash(self): """Test for gates that weren't covered by other tests.""" - dev = qml.device("default.qubit.jax", wires=2, shots=1000) + dev = DefaultQubitJax(wires=2, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -501,7 +501,7 @@ def circuit(): def test_diagonal_doesnt_crash(self): """Test that diagonal gates can be used.""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) + dev = DefaultQubitJax(wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -512,7 +512,7 @@ def circuit(): def test_broadcasted_diagonal_doesnt_crash(self): """Test that diagonal gates can be used.""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) + dev = DefaultQubitJax(wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -525,7 +525,7 @@ def circuit(): def test_parametrized_evolution_state_vector(self, phi, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` the `_evolve_state_vector_under_parametrized_evolution` method is used.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") @@ -548,7 +548,7 @@ def true_circuit(): def test_parametrized_evolution_matrix(self, phi, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires < device.num_wires/2`` the `_apply_operation` method is used.""" - dev = qml.device("default.qubit.jax", wires=3) + dev = DefaultQubitJax(wires=3) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -573,7 +573,7 @@ def test_parametrized_evolution_state_vector_return_intermediate(self, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` and ``return_intermediate=True``, the ``_evolve_state_vector_under_parametrized_evolution`` method is used.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -600,7 +600,7 @@ def true_circuit(): def test_parametrized_evolution_matrix_complementary(self, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` but with ``complementary=True``, the `_apply_operation` method is used.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -638,7 +638,7 @@ def test_jacobian_variable_multiply(self, tol, jacobian_transform): z = 0.75110998 weights = jnp.array([x, y, z]) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax") def circuit(p): @@ -675,7 +675,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): z = jnp.array([0.75110998, 0.12512, 9.12]) weights = jnp.array([x, y, z]) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(p): @@ -713,7 +713,7 @@ def test_jacobian_repeated(self, tol, jacobian_transform): y = 0.2162158 z = 0.75110998 p = jnp.array([x, y, z]) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -738,7 +738,7 @@ def test_jacobian_repeated_broadcasted(self, tol): """Test that jacobian of a QNode with an attached default.qubit.jax device gives the correct result in the case of repeated broadcasted parameters""" p = jnp.array([[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]]) - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(x): @@ -767,7 +767,7 @@ def circuit(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.jax", wires=wires) + dev = DefaultQubitJax(wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a): @@ -788,7 +788,7 @@ def cost(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a): @@ -812,7 +812,7 @@ def cost(a): def test_CRot_gradient(self, theta, tol): """Tests that the automatic gradient of a arbitrary controlled Euler-angle-parameterized gate is correct.""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) a, b, c = np.array([theta, theta**3, np.sqrt(2) * theta]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -839,7 +839,7 @@ def circuit(a, b, c): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -865,7 +865,7 @@ def cost(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -892,7 +892,7 @@ def cost(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -915,7 +915,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -941,7 +941,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(x): @@ -958,7 +958,7 @@ def circuit(x): def test_jax_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the Jax interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) @qml.qnode(dev, diff_method=diff_method, interface="jax") def circuit(x, weights, w=None): @@ -1002,7 +1002,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface): """Tests that an error is raised if diff_method='backprop' but not using the Jax interface""" - dev = qml.device("default.qubit.jax", wires=1) + dev = DefaultQubitJax(wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -1021,7 +1021,7 @@ def test_no_jax_interface_applied(self): When the JAX interface is applied, we can only get the expectation value and the variance of a QNode. """ - dev = qml.device("default.qubit.jax", wires=1, shots=None) + dev = DefaultQubitJax(wires=1, shots=None) def circuit(): return qml.probs(wires=0) @@ -1036,7 +1036,7 @@ class TestHighLevelIntegration: def test_do_not_split_analytic_jax(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the jax device.""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -1052,7 +1052,7 @@ def circuit(): def test_direct_eval_hamiltonian_broadcasted_error_jax(self): """Tests that an error is raised when attempting to evaluate a Hamiltonian with broadcasting and shots=None directly via its sparse representation with Jax.""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -1065,7 +1065,7 @@ def circuit(): def test_template_integration(self): """Test that a PassthruQNode using default.qubit.jax works with templates.""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(weights): @@ -1090,7 +1090,7 @@ def test_multirz_jacobian(self, jacobian_transform): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = qml.device("default.qubit.jax", wires=wires) + dev = DefaultQubitJax(wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(param): @@ -1161,7 +1161,7 @@ def test_multirz_jacobian_broadcasted(self, jacobian_transform): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = qml.device("default.qubit.jax", wires=wires) + dev = DefaultQubitJax(wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(param): @@ -1208,7 +1208,7 @@ class TestEstimateProb: ) def test_estimate_probability(self, wires, expected, monkeypatch): """Tests the estimate_probability method""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) samples = jnp.array([[0, 0], [1, 1], [1, 1], [0, 0]]) with monkeypatch.context() as m: @@ -1227,7 +1227,7 @@ def test_estimate_probability(self, wires, expected, monkeypatch): ) def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): """Tests the estimate_probability method with a bin size""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) samples = jnp.array([[1, 1], [1, 1], [1, 0], [0, 0]]) bin_size = 2 @@ -1247,7 +1247,7 @@ def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): ) def test_estimate_probability_with_broadcasting(self, wires, expected, monkeypatch): """Tests the estimate_probability method with parameter broadcasting""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) samples = jnp.array( [ [[1, 0], [1, 1], [1, 1], [1, 1]], @@ -1295,7 +1295,7 @@ def test_estimate_probability_with_binsize_with_broadcasting( self, wires, expected, monkeypatch ): """Tests the estimate_probability method with a bin size and parameter broadcasting""" - dev = qml.device("default.qubit.jax", wires=2) + dev = DefaultQubitJax(wires=2) bin_size = 2 samples = jnp.array( [ diff --git a/tests/devices/default_qubit_1/test_default_qubit_tf.py b/tests/devices/default_qubit_1/test_default_qubit_tf.py index 67df09b3bc6..7a54129c54c 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_tf.py +++ b/tests/devices/default_qubit_1/test_default_qubit_tf.py @@ -51,6 +51,7 @@ import pennylane as qml from pennylane import numpy as pnp from pennylane import DeviceError +from pennylane.devices import DefaultQubit tf = pytest.importorskip("tensorflow", minversion="2.0") from pennylane.devices.default_qubit_tf import ( # pylint: disable=wrong-import-position @@ -155,7 +156,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - qml.device("default.qubit.tf", wires=1, shots=1, analytic=True) + DefaultQubitTF(wires=1, shots=1, analytic=True) ##################################################### @@ -563,7 +564,7 @@ def test_apply_ops_above_8_wires_using_special(self): def test_do_not_split_analytic_tf(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the tf device.""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="tf") @@ -930,7 +931,7 @@ def test_three_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, def test_direct_eval_hamiltonian_broadcasted_error_tf(self): """Tests that an error is raised when attempting to evaluate a Hamiltonian with broadcasting and shots=None directly via its sparse representation with TF.""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="tf") @@ -1058,7 +1059,7 @@ def test_multi_mode_hermitian_expectation(self, theta, phi, varphi, tol): def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1082,7 +1083,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1106,7 +1107,7 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1129,7 +1130,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) dev.reset() _A = np.array( @@ -1167,7 +1168,7 @@ def test_hermitian(self, theta, phi, varphi, tol): def test_hermitian_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1216,7 +1217,7 @@ def test_hermitian_hermitian(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) @@ -1236,7 +1237,7 @@ def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit.tf", wires=3, shots=None) + dev = DefaultQubitTF(wires=3, shots=None) Identity = np.array([[1, 0], [0, 1]]) ham = np.kron(np.kron(Identity, Identity), A) obs = qml.Hermitian(ham, wires=[2, 1, 0]) @@ -1298,7 +1299,7 @@ def test_var_hermitian(self, theta, phi, varphi, tol): def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1328,7 +1329,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1356,7 +1357,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=3) + dev = DefaultQubitTF(wires=3) _A = np.array( [ @@ -1429,7 +1430,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1452,7 +1453,7 @@ def test_defines_correct_capabilities(self): def test_load_tensornet_tf_device(self): """Test that the tensor network plugin loads correctly""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.tf" @@ -1463,7 +1464,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit using the old QNode.""" p = tf.Variable(0.543) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf") def circuit(x): @@ -1480,7 +1481,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple circuit with broadcasting using the old QNode.""" p = tf.Variable([0.543, 0.21, 2.41]) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf") def circuit(x): @@ -1496,7 +1497,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -1520,7 +1521,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -1550,7 +1551,7 @@ def circuit(): def test_one_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the one-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) state = init_state(1) @qml.qnode(dev, interface="tf") @@ -1571,7 +1572,7 @@ def circuit(params): def test_two_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the two-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) state = init_state(2) @qml.qnode(dev, interface="tf") @@ -1592,7 +1593,7 @@ def circuit(params): def test_four_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the four-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=4) + dev = DefaultQubitTF(wires=4) state = init_state(4) @qml.qnode(dev, interface="tf") @@ -1611,7 +1612,7 @@ def circuit(params): def test_controlled_rotation_integration(self, init_state, tol): """Test the integration of the two-qubit controlled rotation by passing a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) a = 1.7 b = 1.3432 c = -0.654 @@ -1642,7 +1643,7 @@ def test_jacobian_variable_multiply(self, tol): y = tf.Variable(0.2162158) z = tf.Variable(0.75110998) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(p): @@ -1686,7 +1687,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): y = tf.Variable([0.2162158, 0.241, -0.51]) z = tf.Variable([0.75110998, 0.12512, 9.12]) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(p): @@ -1732,7 +1733,7 @@ def test_jacobian_repeated(self, tol): y = 0.2162158 z = 0.75110998 p = tf.Variable([x, y, z]) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(x): @@ -1760,7 +1761,7 @@ def test_jacobian_repeated_broadcasted(self, tol): y = tf.Variable([0.218, 0.241, -0.51]) z = tf.Variable([0.71, 0.152, 9.12]) p = tf.Variable([x, y, z]) - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(x): @@ -1795,8 +1796,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - dev1 = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=3) + dev1 = DefaultQubit(wires=3) + dev2 = DefaultQubit(wires=3) def cost(x): return qml.math.stack(circuit(x)) @@ -1818,7 +1819,7 @@ def cost(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.tf", wires=wires) + dev = DefaultQubitTF(wires=wires) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a): @@ -1837,7 +1838,7 @@ def circuit(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a): @@ -1857,7 +1858,7 @@ def circuit(a): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1884,7 +1885,7 @@ def circuit(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1913,7 +1914,7 @@ def circuit(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" # pylint:disable=no-member - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1947,7 +1948,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" # pylint:disable=no-member - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1983,7 +1984,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) shift = tf.constant(shift) x = tf.Variable(x) @@ -2011,7 +2012,7 @@ def circuit(x): def test_tf_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the TensorFlow interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) @qml.qnode(dev, diff_method=diff_method, interface="tf") def circuit(x, weights, w): @@ -2067,7 +2068,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface, tol): """Tests that an error is raised if diff_method='backprop' but not using the TF interface""" - dev = qml.device("default.qubit.tf", wires=1) + dev = DefaultQubitTF(wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -2081,7 +2082,7 @@ def circuit(x, w=None): def test_hermitian_backprop(self, tol): """Test that backprop with qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) K = tf.linalg.diag([1, 2, 3, 4]) @@ -2103,7 +2104,7 @@ class TestSamples: def test_sample_observables(self): """Test that the device allows for sampling from observables.""" shots = 100 - dev = qml.device("default.qubit.tf", wires=2, shots=shots) + dev = DefaultQubitTF(wires=2, shots=shots) @qml.qnode(dev, diff_method="best", interface="tf") def circuit(a): @@ -2119,7 +2120,7 @@ def circuit(a): def test_estimating_marginal_probability(self, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) + dev = DefaultQubitTF(wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2135,7 +2136,7 @@ def circuit(): def test_estimating_full_probability(self, tol): """Test that the probability of all wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) + dev = DefaultQubitTF(wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2153,7 +2154,7 @@ def circuit(): def test_estimating_expectation_values(self, tol): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" - dev = qml.device("default.qubit.tf", wires=3, shots=1000) + dev = DefaultQubitTF(wires=3, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(a, b): @@ -2181,7 +2182,7 @@ class TestSamplesBroadcasted: def test_sample_observables_broadcasted(self): """Test that the device allows for broadcasted sampling from observables.""" shots = 100 - dev = qml.device("default.qubit.tf", wires=2, shots=shots) + dev = DefaultQubitTF(wires=2, shots=shots) @qml.qnode(dev, diff_method="best", interface="tf") def circuit(a): @@ -2198,7 +2199,7 @@ def circuit(a): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_marginal_probability_broadcasted(self, batch_size, tol): """Test that the broadcasted probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) + dev = DefaultQubitTF(wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2217,7 +2218,7 @@ def circuit(): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_full_probability_broadcasted(self, batch_size, tol): """Test that the broadcasted probability of all wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) + dev = DefaultQubitTF(wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2240,7 +2241,7 @@ def test_estimating_expectation_values_broadcasted(self, a, tol): """Test that estimating broadcasted expectation values using a finite number of shots produces a numeric tensor""" batch_size = len(a) - dev = qml.device("default.qubit.tf", wires=3, shots=None) + dev = DefaultQubitTF(wires=3, shots=None) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(a, b): @@ -2263,7 +2264,7 @@ def test_asarray_ragged_dtype_conversion(monkeypatch): the dtype argument was provided.""" from tensorflow.python.framework.errors_impl import InvalidArgumentError - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) def mock_func(arr, dtype): raise InvalidArgumentError( @@ -2282,7 +2283,7 @@ class TestGetBatchSize: @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) def test_batch_size_None(self, shape): """Test that a ``batch_size=None`` is reported correctly.""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) tensor0 = np.ones(shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None @@ -2290,7 +2291,7 @@ def test_batch_size_None(self, shape): @pytest.mark.parametrize("batch_size", [1, 3]) def test_batch_size_int(self, shape, batch_size): """Test that an integral ``batch_size`` is reported correctly.""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) full_shape = (batch_size,) + shape tensor0 = np.ones(full_shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size @@ -2298,14 +2299,14 @@ def test_batch_size_int(self, shape, batch_size): def test_invalid_tensor(self): """Test that an error is raised if a tensor is provided that does not have a proper shape/ndim.""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) with pytest.raises(ValueError, match="Can't convert non-rectangular Python"): dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) @pytest.mark.parametrize("jit_compile", [True, False]) def test_no_error_abstract_tensor(self, jit_compile): """Test that no error is raised if an abstract tensor is provided""" - dev = qml.device("default.qubit.tf", wires=2) + dev = DefaultQubitTF(wires=2) signature = (tf.TensorSpec(shape=None, dtype=tf.float32),) @tf.function(jit_compile=jit_compile, input_signature=signature) diff --git a/tests/devices/default_qubit_1/test_default_qubit_torch.py b/tests/devices/default_qubit_1/test_default_qubit_torch.py index de01e303d5f..e1d1174c58a 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_torch.py +++ b/tests/devices/default_qubit_1/test_default_qubit_torch.py @@ -61,6 +61,7 @@ import pennylane as qml from pennylane import DeviceError from pennylane import numpy as pnp +from pennylane.devices import DefaultQubit torch = pytest.importorskip("torch", minversion="1.8.1") from pennylane.devices.default_qubit_torch import ( # pylint: disable=wrong-import-position @@ -200,7 +201,7 @@ def test_analytic_deprecation(): msg += "Please use shots=None instead of analytic=True." with pytest.raises(DeviceError, match=msg): - qml.device("default.qubit.torch", wires=1, shots=1, analytic=True) + DefaultQubitTorch(wires=1, shots=1, analytic=True) ##################################################### @@ -211,7 +212,7 @@ def test_analytic_deprecation(): def test_conj_helper_method(): """Unittests the _conj helper method.""" - dev = qml.device("default.qubit.torch", wires=1) + dev = DefaultQubitTorch(wires=1) x = qml.numpy.array(1.0 + 1j) conj_x = dev._conj(x) @@ -1576,7 +1577,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self, torch_device): """Test that the device defines the right capabilities""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1599,7 +1600,7 @@ def test_defines_correct_capabilities(self, torch_device): def test_load_torch_device(self, torch_device): """Test that the torch device plugin loads correctly""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.torch" @@ -1611,7 +1612,7 @@ def test_qubit_circuit(self, torch_device, tol): result for a simple circuit using the old QNode.""" p = torch.tensor(0.543, dtype=torch.float64, device=torch_device) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch") def circuit(x): @@ -1628,7 +1629,7 @@ def test_qubit_circuit_broadcasted(self, torch_device, tol): result for a simple circuit using the old QNode.""" p = torch.tensor([0.543, 0.21, 2.41], dtype=torch.float64, device=torch_device) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch") def circuit(x): @@ -1643,7 +1644,7 @@ def circuit(x): def test_correct_state(self, torch_device, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) state = dev.state expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) @@ -1670,7 +1671,7 @@ def circuit(): def test_correct_state_broadcasted(self, torch_device, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) state = dev.state expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) @@ -1704,7 +1705,7 @@ def circuit(): def test_one_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the one-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) state = init_state(1, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1724,7 +1725,7 @@ def circuit(params): def test_two_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the two-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) state = init_state(2, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1746,7 +1747,7 @@ def circuit(params): def test_four_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the four-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=4, torch_device=torch_device) + dev = DefaultQubitTorch(wires=4, torch_device=torch_device) state = init_state(4, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1765,7 +1766,7 @@ def circuit(params): def test_controlled_rotation_integration(self, torch_device, init_state, tol): """Test the integration of the two-qubit controlled rotation by passing a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) a = torch.tensor(1.7, device=torch_device) b = torch.tensor(1.3432, device=torch_device) @@ -1798,7 +1799,7 @@ def test_jacobian_variable_multiply(self, torch_device, tol): y = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) z = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(p): @@ -1843,7 +1844,7 @@ def test_jacobian_variable_multiply_broadcasted(self, torch_device, tol): device=torch_device, ) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(p): @@ -1886,7 +1887,7 @@ def test_jacobian_repeated(self, torch_device, tol): y = torch.tensor(0.2162158, dtype=torch.float64, requires_grad=True, device=torch_device) z = torch.tensor(0.75110998, dtype=torch.float64, requires_grad=True, device=torch_device) p = torch.tensor([x, y, z], requires_grad=True, device=torch_device) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(x): @@ -1921,7 +1922,7 @@ def test_jacobian_repeated_broadcasted(self, torch_device, tol): device=torch_device, requires_grad=True, ) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(x): @@ -1961,8 +1962,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)) # , qml.var(qml.PauliZ(1)) - dev1 = qml.device("default.qubit.torch", wires=3, torch_device=torch_device) - dev2 = qml.device("default.qubit", wires=3) + dev1 = DefaultQubitTorch(wires=3, torch_device=torch_device) + dev2 = DefaultQubit(wires=3) circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="torch") circuit2 = qml.QNode(circuit, dev2, diff_method="parameter-shift") @@ -1979,7 +1980,7 @@ def circuit(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, torch_device, wires, tol): """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.torch", wires=wires, torch_device=torch_device) + dev = DefaultQubitTorch(wires=wires, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a): @@ -1998,7 +1999,7 @@ def circuit(a): def test_state_differentiability_broadcasted(self, torch_device, tol): """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a): @@ -2018,7 +2019,7 @@ def cost(a): def test_prob_differentiability(self, torch_device, tol): """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2044,7 +2045,7 @@ def circuit(a, b): def test_prob_differentiability_broadcasted(self, torch_device, tol): """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2075,7 +2076,7 @@ def cost(a, b): def test_backprop_gradient(self, torch_device, tol): """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2099,7 +2100,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, torch_device, tol): """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2126,7 +2127,7 @@ def circuit(a, b): def test_hessian_at_zero(self, torch_device, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) x = torch.tensor(x, requires_grad=True) @@ -2147,7 +2148,7 @@ def circuit(x): def test_torch_interface_gradient(self, torch_device, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the PyTorch interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) input_state = torch.tensor(1j * np.array([1, -1]) / math.sqrt(2), device=torch_device) @@ -2207,7 +2208,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, torch_device, interface): """Tests that an error is raised if diff_method='backprop' but not using the torch interface""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, torch_device=torch_device) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -2229,7 +2230,7 @@ class TestSamples: def test_sample_observables(self, torch_device): """Test that the device allows for sampling from observables.""" shots = 100 - dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=shots, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a): @@ -2247,7 +2248,7 @@ def circuit(a): def test_estimating_marginal_probability(self, torch_device, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2263,7 +2264,7 @@ def circuit(): def test_estimating_full_probability(self, torch_device, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2281,7 +2282,7 @@ def circuit(): def test_estimating_expectation_values(self, torch_device): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" - dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=3, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a, b): @@ -2313,7 +2314,7 @@ def test_sample_observables_broadcasted(self, torch_device, a): """Test that the device allows for sampling from observables.""" batch_size = len(a) shots = 100 - dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=shots, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a): @@ -2332,7 +2333,7 @@ def circuit(a): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_marginal_probability_broadcasted(self, torch_device, batch_size, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2351,7 +2352,7 @@ def circuit(): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_full_probability_broadcasted(self, torch_device, batch_size, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2376,7 +2377,7 @@ def test_estimating_expectation_values_broadcasted(self, torch_device, a): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" batch_size = len(a) - dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) + dev = DefaultQubitTorch(wires=3, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a, b): @@ -2402,7 +2403,7 @@ def test_sampling_analytic_mode(self, torch_device): """Test that when sampling with shots=None, dev uses 1000 shots and raises an error. """ - dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, shots=None, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(): @@ -2416,7 +2417,7 @@ def circuit(): def test_sampling_analytic_mode_with_counts(self, torch_device): """Test that when sampling with counts and shots=None an error is raised.""" - dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) + dev = DefaultQubitTorch(wires=1, shots=None, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(): @@ -2473,7 +2474,7 @@ class TestCtrlOperator: ) def test_ctrl_r_operators(self, torch_device, ops, tol): """Test qml.ctrl using R-gate targets""" - dev = qml.device("default.qubit.torch", wires=2, shots=None, torch_device=torch_device) + dev = DefaultQubitTorch(wires=2, shots=None, torch_device=torch_device) par = torch.tensor([0.12345, 0.2468], dtype=torch.float64, device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") diff --git a/tests/devices/test_default_qubit.py b/tests/devices/test_default_qubit.py deleted file mode 100644 index b44555d650c..00000000000 --- a/tests/devices/test_default_qubit.py +++ /dev/null @@ -1,2496 +0,0 @@ -# Copyright 2018-2020 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 :mod:`pennylane.plugin.DefaultQubit` device. -""" -# pylint: disable=too-many-arguments,too-few-public-methods -# pylint: disable=protected-access,cell-var-from-loop -import cmath - -import math - -from functools import partial -import pytest - -import pennylane as qml -from pennylane import DeviceError -from pennylane import numpy as np -from pennylane.devices.default_qubit import DefaultQubit, _get_slice -from pennylane.pulse import ParametrizedHamiltonian -from pennylane.wires import WireError, Wires - -U = np.array( - [ - [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], - [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], - ] -) - -U2 = np.array( - [ - [ - -0.07843244 - 3.57825948e-01j, - 0.71447295 - 5.38069384e-02j, - 0.20949966 + 6.59100734e-05j, - -0.50297381 + 2.35731613e-01j, - ], - [ - -0.26626692 + 4.53837083e-01j, - 0.27771991 - 2.40717436e-01j, - 0.41228017 - 1.30198687e-01j, - 0.01384490 - 6.33200028e-01j, - ], - [ - -0.69254712 - 2.56963068e-02j, - -0.15484858 + 6.57298384e-02j, - -0.53082141 + 7.18073414e-02j, - -0.41060450 - 1.89462315e-01j, - ], - [ - -0.09686189 - 3.15085273e-01j, - -0.53241387 - 1.99491763e-01j, - 0.56928622 + 3.97704398e-01j, - -0.28671074 - 6.01574497e-02j, - ], - ] -) - -U_toffoli = np.diag([1 for i in range(8)]) -U_toffoli[6:8, 6:8] = np.array([[0, 1], [1, 0]]) - -U_swap = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) - -U_cswap = np.array( - [ - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - ] -) - -THETA = np.linspace(0.11, 1, 3) -PHI = np.linspace(0.32, 1, 3) -VARPHI = np.linspace(0.02, 1, 3) - - -def test_analytic_deprecation(): - """Tests if the kwarg `analytic` is used and displays error message.""" - msg = "The analytic argument has been replaced by shots=None. " - msg += "Please use shots=None instead of analytic=True." - - with pytest.raises( - DeviceError, - match=msg, - ): - qml.device("default.qubit", wires=1, shots=1, analytic=True) - - -def test_dtype_errors(): - """Test that if an incorrect dtype is provided to the device then an error is raised.""" - with pytest.raises(DeviceError, match="Real datatype must be a floating point type."): - qml.device("default.qubit", wires=1, r_dtype=np.complex128) - with pytest.raises( - DeviceError, match="Complex datatype must be a complex floating point type." - ): - qml.device("default.qubit", wires=1, c_dtype=np.float64) - - -def test_custom_op_with_matrix(): - """Test that a dummy op with a matrix is supported.""" - - class DummyOp(qml.operation.Operation): - num_wires = 1 - - def compute_matrix(self): - return np.eye(2) - - with qml.queuing.AnnotatedQueue() as q: - DummyOp(0) - qml.state() - - tape = qml.tape.QuantumScript.from_queue(q) - dev = qml.device("default.qubit", wires=1) - assert qml.math.allclose(dev.execute(tape), np.array([1, 0])) - - -class TestApply: - """Tests that operations and inverses of certain operations are applied correctly or that the proper - errors are raised. - """ - - test_data_no_parameters = [ - (qml.PauliX, [1, 0], np.array([0, 1])), - (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1 / math.sqrt(2)]), - (qml.PauliY, [1, 0], [0, 1j]), - (qml.PauliY, [1 / math.sqrt(2), 1 / math.sqrt(2)], [-1j / math.sqrt(2), 1j / math.sqrt(2)]), - (qml.PauliZ, [1, 0], [1, 0]), - (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), -1 / math.sqrt(2)]), - (qml.S, [1, 0], [1, 0]), - (qml.S, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1j / math.sqrt(2)]), - (qml.T, [1, 0], [1, 0]), - ( - qml.T, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / math.sqrt(2), np.exp(1j * np.pi / 4) / math.sqrt(2)], - ), - (qml.Hadamard, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)]), - (qml.Hadamard, [1 / math.sqrt(2), -1 / math.sqrt(2)], [0, 1]), - (qml.Identity, [1, 0], [1, 0]), - (qml.Identity, [1 / math.sqrt(2), 1 / math.sqrt(2)], [1 / math.sqrt(2), 1 / math.sqrt(2)]), - ] - - @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) - def test_apply_operation_single_wire_no_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have no parameters.""" - - qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) - qubit_device_1_wire.apply([operation(wires=[0])]) - - assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) - assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE - - test_data_two_wires_no_parameters = [ - (qml.CNOT, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.CNOT, [0, 0, 1, 0], [0, 0, 0, 1]), - ( - qml.CNOT, - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - [1 / math.sqrt(2), 0, 1 / math.sqrt(2), 0], - ), - (qml.SWAP, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.SWAP, [0, 0, 1, 0], [0, 1, 0, 0]), - ( - qml.SWAP, - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - [1 / math.sqrt(2), -1 / math.sqrt(2), 0, 0], - ), - (qml.CZ, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.CZ, [0, 0, 0, 1], [0, 0, 0, -1]), - ( - qml.CZ, - [1 / math.sqrt(2), 0, 0, -1 / math.sqrt(2)], - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - ), - ] - - test_data_iswap = [ - (qml.ISWAP, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.ISWAP, [0, 0, 1, 0], [0, 1j, 0, 0]), - ( - qml.ISWAP, - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - [1 / math.sqrt(2), -1j / math.sqrt(2), 0, 0], - ), - ] - - test_data_siswap = [ - (qml.SISWAP, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.SISWAP, [0, 1, 0, 0], [0, 1 / math.sqrt(2), 1 / math.sqrt(2) * 1j, 0]), - ( - qml.SISWAP, - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [1 / math.sqrt(2), 0.5, 0.5 * 1j, 0], - ), - ] - - test_data_sqisw = [ - (qml.SQISW, [1, 0, 0, 0], [1, 0, 0, 0]), - (qml.SQISW, [0, 1, 0, 0], [0, 1 / math.sqrt(2), 1 / math.sqrt(2) * 1j, 0]), - ( - qml.SQISW, - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [1 / math.sqrt(2), 0.5, 0.5 * 1j, 0], - ), - ] - - all_two_wires_no_parameters = ( - test_data_two_wires_no_parameters + test_data_iswap + test_data_siswap + test_data_sqisw - ) - - @pytest.mark.parametrize("operation,input,expected_output", all_two_wires_no_parameters) - def test_apply_operation_two_wires_no_parameters( - self, qubit_device_2_wires, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for two wire - operations that have no parameters.""" - - qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( - (2, 2) - ) - qubit_device_2_wires.apply([operation(wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 - ) - assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE - - test_data_three_wires_no_parameters = [ - (qml.CSWAP, [1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0]), - (qml.CSWAP, [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0]), - (qml.CSWAP, [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0, 0]), - ] - - @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) - def test_apply_operation_three_wires_no_parameters( - self, qubit_device_3_wires, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for three wire - operations that have no parameters.""" - - qubit_device_3_wires._state = np.array(input, dtype=qubit_device_3_wires.C_DTYPE).reshape( - (2, 2, 2) - ) - qubit_device_3_wires.apply([operation(wires=[0, 1, 2])]) - - assert np.allclose( - qubit_device_3_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 - ) - assert qubit_device_3_wires._state.dtype == qubit_device_3_wires.C_DTYPE - - @pytest.mark.parametrize( - "operation,expected_output,par", - [ - (qml.BasisState, [0, 0, 1, 0], [1, 0]), - (qml.BasisState, [0, 0, 1, 0], [1, 0]), - (qml.BasisState, [0, 0, 0, 1], [1, 1]), - (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), - (qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]), - (qml.QubitStateVector, [0, 0, 0, 1], [0, 0, 0, 1]), - ( - qml.QubitStateVector, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ( - qml.QubitStateVector, - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - [1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)], - ), - ], - ) - def test_apply_operation_state_preparation( - self, qubit_device_2_wires, tol, operation, expected_output, par - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have no parameters.""" - - par = np.array(par) - qubit_device_2_wires.reset() - qubit_device_2_wires.apply([operation(par, wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 - ) - - test_data_single_wire_with_parameters = [ - (qml.PhaseShift, [1, 0], [1, 0], [math.pi / 2]), - (qml.PhaseShift, [0, 1], [0, 1j], [math.pi / 2]), - ( - qml.PhaseShift, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / math.sqrt(2), 1 / 2 + 1j / 2], - [math.pi / 4], - ), - (qml.RX, [1, 0], [1 / math.sqrt(2), -1j * 1 / math.sqrt(2)], [math.pi / 2]), - (qml.RX, [1, 0], [0, -1j], [math.pi]), - ( - qml.RX, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / 2 - 1j / 2, 1 / 2 - 1j / 2], - [math.pi / 2], - ), - (qml.RY, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)], [math.pi / 2]), - (qml.RY, [1, 0], [0, 1], [math.pi]), - (qml.RY, [1 / math.sqrt(2), 1 / math.sqrt(2)], [0, 1], [math.pi / 2]), - (qml.RZ, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2]), - (qml.RZ, [0, 1], [0, 1j], [math.pi]), - ( - qml.RZ, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], - [math.pi / 2], - ), - (qml.MultiRZ, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2]), - (qml.MultiRZ, [0, 1], [0, 1j], [math.pi]), - ( - qml.MultiRZ, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], - [math.pi / 2], - ), - (qml.Rot, [1, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0], [math.pi / 2, 0, 0]), - (qml.Rot, [1, 0], [1 / math.sqrt(2), 1 / math.sqrt(2)], [0, math.pi / 2, 0]), - ( - qml.Rot, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / 2 - 1j / 2, 1 / 2 + 1j / 2], - [0, 0, math.pi / 2], - ), - ( - qml.Rot, - [1, 0], - [-1j / math.sqrt(2), -1 / math.sqrt(2)], - [math.pi / 2, -math.pi / 2, math.pi / 2], - ), - ( - qml.Rot, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / 2 + 1j / 2, -1 / 2 + 1j / 2], - [-math.pi / 2, math.pi, math.pi], - ), - ( - qml.QubitUnitary, - [1, 0], - [1j / math.sqrt(2), 1j / math.sqrt(2)], - [ - np.array( - [ - [1j / math.sqrt(2), 1j / math.sqrt(2)], - [1j / math.sqrt(2), -1j / math.sqrt(2)], - ] - ) - ], - ), - ( - qml.QubitUnitary, - [0, 1], - [1j / math.sqrt(2), -1j / math.sqrt(2)], - [ - np.array( - [ - [1j / math.sqrt(2), 1j / math.sqrt(2)], - [1j / math.sqrt(2), -1j / math.sqrt(2)], - ] - ) - ], - ), - ( - qml.QubitUnitary, - [1 / math.sqrt(2), -1 / math.sqrt(2)], - [0, 1j], - [ - np.array( - [ - [1j / math.sqrt(2), 1j / math.sqrt(2)], - [1j / math.sqrt(2), -1j / math.sqrt(2)], - ] - ) - ], - ), - (qml.DiagonalQubitUnitary, [1, 0], [-1, 0], [np.array([-1, 1])]), - ( - qml.DiagonalQubitUnitary, - [1 / math.sqrt(2), 1 / math.sqrt(2)], - [1 / math.sqrt(2), 1j / math.sqrt(2)], - [np.array([1, 1j])], - ), - ( - qml.DiagonalQubitUnitary, - [1 / 2, math.sqrt(3) / 4], - [cmath.exp(1j * 0.4) / 2, cmath.exp(1j * -0.4) * math.sqrt(3) / 4], - [np.array([cmath.exp(1j * 0.4), cmath.exp(1j * -0.4)])], - ), - (qml.SpecialUnitary, [1, 0], [0, 1j], [np.array([np.pi / 2, 0, 0])]), - (qml.SpecialUnitary, [1, 0], [0, -1], [np.array([0, np.pi / 2, 0])]), - (qml.SpecialUnitary, [1, 0], [1j, 0], [np.array([0, 0, np.pi / 2])]), - (qml.SpecialUnitary, [0.6, 0.8], [0.573 + 0.236j, 0.764 + 0.177j], [np.array([0.3, 0, 0])]), - ( - qml.SpecialUnitary, - [0.8j, -0.6], - [-0.808 + 0.049j, -0.411 + 0.419j], - [np.array([0.4, 0.2, 1.2])], - ), - ] - - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_single_wire_with_parameters - ) - def test_apply_operation_single_wire_with_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have parameters.""" - - qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) - - qubit_device_1_wire.apply([operation(*par, wires=[0])]) - - assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) - assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE - - test_data_two_wires_with_parameters = [ - (qml.CRX, [0, 1, 0, 0], [0, 1, 0, 0], [math.pi / 2]), - (qml.CRX, [0, 0, 0, 1], [0, 0, -1j, 0], [math.pi]), - ( - qml.CRX, - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [0, 1 / math.sqrt(2), 1 / 2, -1j / 2], - [math.pi / 2], - ), - (qml.CRY, [0, 0, 0, 1], [0, 0, -1 / math.sqrt(2), 1 / math.sqrt(2)], [math.pi / 2]), - (qml.CRY, [0, 0, 0, 1], [0, 0, -1, 0], [math.pi]), - ( - qml.CRY, - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [math.pi / 2], - ), - (qml.CRZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2)], [math.pi / 2]), - (qml.CRZ, [0, 0, 0, 1], [0, 0, 0, 1j], [math.pi]), - ( - qml.CRZ, - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [math.pi / 2], - ), - (qml.MultiRZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], [math.pi / 2]), - (qml.MultiRZ, [0, 0, 1, 0], [0, 0, 1j, 0], [math.pi]), - ( - qml.MultiRZ, - [1 / math.sqrt(2), 1 / math.sqrt(2), 0, 0], - [1 / 2 - 1j / 2, 1 / 2 + 1j / 2, 0, 0], - [math.pi / 2], - ), - ( - qml.CRot, - [0, 0, 0, 1], - [0, 0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2)], - [math.pi / 2, 0, 0], - ), - (qml.CRot, [0, 0, 0, 1], [0, 0, -1 / math.sqrt(2), 1 / math.sqrt(2)], [0, math.pi / 2, 0]), - ( - qml.CRot, - [0, 0, 1 / math.sqrt(2), 1 / math.sqrt(2)], - [0, 0, 1 / 2 - 1j / 2, 1 / 2 + 1j / 2], - [0, 0, math.pi / 2], - ), - ( - qml.CRot, - [0, 0, 0, 1], - [0, 0, 1 / math.sqrt(2), 1j / math.sqrt(2)], - [math.pi / 2, -math.pi / 2, math.pi / 2], - ), - ( - qml.CRot, - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [0, 1 / math.sqrt(2), 0, -1 / 2 + 1j / 2], - [-math.pi / 2, math.pi, math.pi], - ), - ( - qml.QubitUnitary, - [1, 0, 0, 0], - [1, 0, 0, 0], - [ - np.array( - [ - [1, 0, 0, 0], - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - [0, 0, 0, 1], - ] - ) - ], - ), - ( - qml.QubitUnitary, - [0, 1, 0, 0], - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [ - np.array( - [ - [1, 0, 0, 0], - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - [0, 0, 0, 1], - ] - ) - ], - ), - ( - qml.QubitUnitary, - [1 / 2, 1 / 2, -1 / 2, 1 / 2], - [1 / 2, 0, 1 / math.sqrt(2), 1 / 2], - [ - np.array( - [ - [1, 0, 0, 0], - [0, 1 / math.sqrt(2), 1 / math.sqrt(2), 0], - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - [0, 0, 0, 1], - ] - ) - ], - ), - (qml.DiagonalQubitUnitary, [1, 0, 0, 0], [-1, 0, 0, 0], [np.array([-1, 1, 1, -1])]), - ( - qml.DiagonalQubitUnitary, - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - [1 / math.sqrt(2), 0, 0, -1 / math.sqrt(2)], - [np.array([1, 1, 1, -1])], - ), - (qml.DiagonalQubitUnitary, [0, 0, 1, 0], [0, 0, 1j, 0], [np.array([-1, 1j, 1j, -1])]), - ( - qml.SpecialUnitary, - [0.5, -0.5j, 0.5j, -0.5], - [0.382 - 0.322j, -0.322 - 0.382j, 0.322 + 0.382j, -0.382 + 0.322j], - [np.eye(15)[4] * 0.7], - ), - ( - qml.SpecialUnitary, - [0.6, 0, 0, -0.8], - [0.553, 0.312, -0.234, -0.737], - [np.eye(15)[10] * 0.4], - ), - ( - qml.SpecialUnitary, - [0, 0, 1, 0], - [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], - [-np.eye(15)[4] * np.pi / 4], - ), # Like Ising XX - ( - qml.SpecialUnitary, - [0, 0, 1, 0], - [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], - [-np.eye(15)[9] * np.pi / 4], - ), # Like Ising YY - ( - qml.SpecialUnitary, - [0, 0, 0, 1], - [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], - [-np.eye(15)[14] * np.pi / 4], - ), # Like Ising ZZ - ( - qml.SpecialUnitary, - [0.5, -0.5j, -0.5, -0.5], - [-0.616 - 0.018j, 0.316 + 0.243j, 0.427 + 0.437j, 0.294 + 0.043j], - [np.linspace(0.1, 3, 15)], - ), - (qml.IsingXX, [0, 0, 1, 0], [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], [math.pi / 2]), - (qml.IsingXX, [0, 0, 0, 1], [-1j / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], [math.pi / 2]), - (qml.IsingXX, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, -1j / math.sqrt(2)], [math.pi / 2]), - (qml.IsingYY, [0, 0, 1, 0], [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], [math.pi / 2]), - (qml.IsingYY, [0, 0, 0, 1], [1j / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], [math.pi / 2]), - (qml.IsingYY, [1, 0, 0, 0], [1 / math.sqrt(2), 0, 0, 1j / math.sqrt(2)], [math.pi / 2]), - (qml.IsingZZ, [0, 0, 1, 0], [0, 0, 1 / math.sqrt(2) + 1j / math.sqrt(2), 0], [math.pi / 2]), - (qml.IsingZZ, [0, 0, 0, 1], [0, 0, 0, 1 / math.sqrt(2) - 1j / math.sqrt(2)], [math.pi / 2]), - (qml.IsingZZ, [1, 0, 0, 0], [1 / math.sqrt(2) - 1j / math.sqrt(2), 0, 0, 0], [math.pi / 2]), - ] - - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_two_wires_with_parameters - ) - def test_apply_operation_two_wires_with_parameters( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that applying an operation yields the expected output state for two wire - operations that have parameters.""" - - qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( - (2, 2) - ) - qubit_device_2_wires.apply([operation(*par, wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.flatten(), np.array(expected_output), atol=tol, rtol=0 - ) - assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE - - def test_apply_errors_qubit_state_vector(self, qubit_device_2_wires): - """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" - with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): - qubit_device_2_wires.apply([qml.QubitStateVector(np.array([1, -1]), wires=[0])]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): - p = np.array([1, 0, 1, 1, 0]) / np.sqrt(3) - qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) - - with pytest.raises( - DeviceError, - match="Operation QubitStateVector cannot be used after other Operations have already been applied " - "on a default.qubit device.", - ): - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.RZ(0.5, wires=[0]), qml.QubitStateVector(np.array([0, 1, 0, 0]), wires=[0, 1])] - ) - - def test_apply_errors_basis_state(self, qubit_device_2_wires): - with pytest.raises( - ValueError, match="BasisState parameter must consist of 0 or 1 integers." - ): - qubit_device_2_wires.apply([qml.BasisState(np.array([-0.2, 4.2]), wires=[0, 1])]) - - with pytest.raises( - ValueError, match="BasisState parameter and wires must be of equal length." - ): - qubit_device_2_wires.apply([qml.BasisState(np.array([0, 1]), wires=[0])]) - - with pytest.raises( - DeviceError, - match="Operation BasisState cannot be used after other Operations have already been applied " - "on a default.qubit device.", - ): - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.RZ(0.5, wires=[0]), qml.BasisState(np.array([1, 1]), wires=[0, 1])] - ) - - -class TestExpval: - """Tests that expectation values are properly calculated or that the proper errors are raised.""" - - @pytest.mark.parametrize( - "operation,input,expected_output", - [ - (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), - (qml.PauliX, [1 / math.sqrt(2), -1 / math.sqrt(2)], -1), - (qml.PauliX, [1, 0], 0), - (qml.PauliY, [1 / math.sqrt(2), 1j / math.sqrt(2)], 1), - (qml.PauliY, [1 / math.sqrt(2), -1j / math.sqrt(2)], -1), - (qml.PauliY, [1, 0], 0), - (qml.PauliZ, [1, 0], 1), - (qml.PauliZ, [0, 1], -1), - (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), - (qml.Hadamard, [1, 0], 1 / math.sqrt(2)), - (qml.Hadamard, [0, 1], -1 / math.sqrt(2)), - (qml.Hadamard, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / math.sqrt(2)), - (qml.Identity, [1, 0], 1), - (qml.Identity, [0, 1], 1), - (qml.Identity, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1), - ], - ) - def test_expval_single_wire_no_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that expectation values are properly calculated for single-wire observables without parameters.""" - - obs = operation(wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.expval(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - (qml.Hermitian, [1, 0], 1, [[1, 1j], [-1j, 1]]), - (qml.Hermitian, [0, 1], 1, [[1, 1j], [-1j, 1]]), - (qml.Hermitian, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, [[1, 1j], [-1j, 1]]), - ], - ) - def test_expval_single_wire_with_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that expectation values are properly calculated for single-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.expval(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - ( - qml.Hermitian, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - 5 / 3, - [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [0, 0, 0, 1], - 0, - [[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], - ), - ( - qml.Hermitian, - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - 1, - [[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [1 / math.sqrt(3), -1 / math.sqrt(3), 1 / math.sqrt(6), 1 / math.sqrt(6)], - 1, - [[1, 1j, 0, 0.5j], [-1j, 1, 0, 0], [0, 0, 1, -1j], [-0.5j, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - 1, - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ( - qml.Hermitian, - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - -1, - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ], - ) - def test_expval_two_wires_with_parameters( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that expectation values are properly calculated for two-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0, 1]) - - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() - ) - res = qubit_device_2_wires.expval(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - def test_expval_estimate(self): - """Test that the expectation value is not analytically calculated""" - - dev = qml.device("default.qubit", wires=1, shots=3) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - return qml.expval(qml.PauliX(0)) - - expval = circuit() - - # With 3 samples we are guaranteed to see a difference between - # an estimated variance an an analytically calculated one - assert expval != 0.0 - - -class TestVar: - """Tests that variances are properly calculated.""" - - @pytest.mark.parametrize( - "operation,input,expected_output", - [ - (qml.PauliX, [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), - (qml.PauliX, [1 / math.sqrt(2), -1 / math.sqrt(2)], 0), - (qml.PauliX, [1, 0], 1), - (qml.PauliY, [1 / math.sqrt(2), 1j / math.sqrt(2)], 0), - (qml.PauliY, [1 / math.sqrt(2), -1j / math.sqrt(2)], 0), - (qml.PauliY, [1, 0], 1), - (qml.PauliZ, [1, 0], 0), - (qml.PauliZ, [0, 1], 0), - (qml.PauliZ, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), - (qml.Hadamard, [1, 0], 1 / 2), - (qml.Hadamard, [0, 1], 1 / 2), - (qml.Hadamard, [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / 2), - (qml.Identity, [1, 0], 0), - (qml.Identity, [0, 1], 0), - (qml.Identity, [1 / math.sqrt(2), -1 / math.sqrt(2)], 0), - ], - ) - def test_var_single_wire_no_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that variances are properly calculated for single-wire observables without parameters.""" - - obs = operation(wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.var(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - (qml.Hermitian, [1, 0], 1, [[1, 1j], [-1j, 1]]), - (qml.Hermitian, [0, 1], 1, [[1, 1j], [-1j, 1]]), - (qml.Hermitian, [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, [[1, 1j], [-1j, 1]]), - ], - ) - def test_var_single_wire_with_parameters( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that variances are properly calculated for single-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.var(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - ( - qml.Hermitian, - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - 11 / 9, - [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [0, 0, 0, 1], - 1, - [[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], - ), - ( - qml.Hermitian, - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - 1, - [[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - 0, - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ( - qml.Hermitian, - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - 0, - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ], - ) - def test_var_two_wires_with_parameters( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that variances are properly calculated for two-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0, 1]) - - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() - ) - res = qubit_device_2_wires.var(obs) - - assert np.isclose(res, expected_output, atol=tol, rtol=0) - - def test_var_estimate(self): - """Test that the variance is not analytically calculated""" - - dev = qml.device("default.qubit", wires=1, shots=3) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - return qml.var(qml.PauliX(0)) - - var = circuit() - - # With 3 samples we are guaranteed to see a difference between - # an estimated variance and an analytically calculated one - assert var != 1.0 - - -class TestSample: - """Tests that samples are properly calculated.""" - - def test_sample_dimensions(self): - """Tests if the samples returned by the sample function have - the correct dimensions - """ - - # Explicitly resetting is necessary as the internal - # state is set to None in __init__ and only properly - # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) - - dev.apply([qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])]) - - dev.shots = 10 - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(qml.PauliZ(wires=[0])) - assert np.array_equal(s1.shape, (10,)) - - dev.reset() - dev.shots = 12 - dev._wires_measured = {1} - dev._samples = dev.generate_samples() - s2 = dev.sample(qml.PauliZ(wires=[1])) - assert np.array_equal(s2.shape, (12,)) - - dev.reset() - dev.shots = 17 - dev._wires_measured = {0, 1} - dev._samples = dev.generate_samples() - s3 = dev.sample(qml.PauliX(0) @ qml.PauliZ(1)) - assert np.array_equal(s3.shape, (17,)) - - def test_sample_values(self, tol): - """Tests if the samples returned by sample have - the correct values - """ - - # Explicitly resetting is necessary as the internal - # state is set to None in __init__ and only properly - # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) - - dev.apply([qml.RX(1.5708, wires=[0])]) - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - - s1 = dev.sample(qml.PauliZ(0)) - - # s1 should only contain 1 and -1, which is guaranteed if - # they square to 1 - assert np.allclose(s1**2, 1, atol=tol, rtol=0) - - -class TestDefaultQubitIntegration: - """Integration tests for default.qubit. This test ensures it integrates - properly with the PennyLane interface, in particular QNode.""" - - def test_defines_correct_capabilities(self): - """Test that the device defines the right capabilities""" - - dev = qml.device("default.qubit", wires=1) - cap = dev.capabilities() - capabilities = { - "model": "qubit", - "supports_finite_shots": True, - "supports_tensor_observables": True, - "returns_probs": True, - "returns_state": True, - "supports_inverse_operations": True, - "supports_analytic_computation": True, - "supports_broadcasting": True, - "passthru_devices": { - "torch": "default.qubit.torch", - "tf": "default.qubit.tf", - "autograd": "default.qubit.autograd", - "jax": "default.qubit.jax", - }, - } - assert cap == capabilities - - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - def test_qubit_circuit(self, qubit_device_1_wire, r_dtype, tol): - """Test that the default qubit plugin provides correct result for a simple circuit""" - - p = 0.543 - - dev = qubit_device_1_wire - dev.R_DTYPE = r_dtype - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -np.sin(p) - - res = circuit(p) - assert np.isclose(res, expected, atol=tol, rtol=0) - assert res.dtype == r_dtype - - def test_qubit_identity(self, qubit_device_1_wire, tol): - """Test that the default qubit plugin provides correct result for the Identity expectation""" - - p = 0.543 - - @qml.qnode(qubit_device_1_wire) - def circuit(x): - """Test quantum function""" - qml.RX(x, wires=0) - return qml.expval(qml.Identity(0)) - - assert np.isclose(circuit(p), 1, atol=tol, rtol=0) - - def test_nonzero_shots(self, tol): - """Test that the default qubit plugin provides correct result for high shot number""" - - shots = 10**5 - dev = qml.device("default.qubit", wires=1, shots=shots) - - p = 0.543 - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - """Test quantum function""" - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - runs = [] - for _ in range(100): - runs.append(circuit(p)) - - assert np.isclose(np.mean(runs), -np.sin(p), atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output", - [ - ("PauliX", [1 / math.sqrt(2), 1 / math.sqrt(2)], 1), - ("PauliX", [1 / math.sqrt(2), -1 / math.sqrt(2)], -1), - ("PauliX", [1, 0], 0), - ("PauliY", [1 / math.sqrt(2), 1j / math.sqrt(2)], 1), - ("PauliY", [1 / math.sqrt(2), -1j / math.sqrt(2)], -1), - ("PauliY", [1, 0], 0), - ("PauliZ", [1, 0], 1), - ("PauliZ", [0, 1], -1), - ("PauliZ", [1 / math.sqrt(2), 1 / math.sqrt(2)], 0), - ("Hadamard", [1, 0], 1 / math.sqrt(2)), - ("Hadamard", [0, 1], -1 / math.sqrt(2)), - ("Hadamard", [1 / math.sqrt(2), 1 / math.sqrt(2)], 1 / math.sqrt(2)), - ], - ) - def test_supported_observable_single_wire_no_parameters( - self, qubit_device_1_wire, tol, name, state, expected_output - ): - """Tests supported observables on single wires without parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_1_wire.supports_observable(name) - - @qml.qnode(qubit_device_1_wire) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0]) - return qml.expval(obs(wires=[0])) - - assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output,par", - [ - ("Identity", [1, 0], 1, []), - ("Identity", [0, 1], 1, []), - ("Identity", [1 / math.sqrt(2), -1 / math.sqrt(2)], 1, []), - ("Hermitian", [1, 0], 1, [np.array([[1, 1j], [-1j, 1]])]), - ("Hermitian", [0, 1], 1, [np.array([[1, 1j], [-1j, 1]])]), - ( - "Hermitian", - [1 / math.sqrt(2), -1 / math.sqrt(2)], - 1, - [np.array([[1, 1j], [-1j, 1]])], - ), - ], - ) - def test_supported_observable_single_wire_with_parameters( - self, qubit_device_1_wire, tol, name, state, expected_output, par - ): - """Tests supported observables on single wires with parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_1_wire.supports_observable(name) - - @qml.qnode(qubit_device_1_wire) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0]) - return qml.expval(obs(*par, wires=[0])) - - assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output,par", - [ - ( - "Hermitian", - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - 5 / 3, - [np.array([[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]])], - ), - ( - "Hermitian", - [0, 0, 0, 1], - 0, - [np.array([[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]])], - ), - ( - "Hermitian", - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - 1, - [np.array([[1, 1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, 1]])], - ), - ( - "Hermitian", - [1 / math.sqrt(3), -1 / math.sqrt(3), 1 / math.sqrt(6), 1 / math.sqrt(6)], - 1, - [np.array([[1, 1j, 0, 0.5j], [-1j, 1, 0, 0], [0, 0, 1, -1j], [-0.5j, 0, 1j, 1]])], - ), - ( - "Hermitian", - [1 / math.sqrt(2), 0, 0, 1 / math.sqrt(2)], - 1, - [np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])], - ), - ( - "Hermitian", - [0, 1 / math.sqrt(2), -1 / math.sqrt(2), 0], - -1, - [np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])], - ), - ], - ) - def test_supported_observable_two_wires_with_parameters( - self, qubit_device_2_wires, tol, name, state, expected_output, par - ): - """Tests supported observables on two wires with parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_2_wires.supports_observable(name) - - @qml.qnode(qubit_device_2_wires) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0, 1]) - return qml.expval(obs(*par, wires=[0, 1])) - - assert np.isclose(circuit(), expected_output, atol=tol, rtol=0) - - def test_multi_samples_return_correlated_results(self): - """Tests if the samples returned by the sample function have - the correct dimensions - """ - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.Hadamard(0) - qml.CNOT(wires=[0, 1]) - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) - - outcomes = circuit() - - assert np.array_equal(outcomes[0], outcomes[1]) - - @pytest.mark.parametrize("num_wires", [3, 4, 5, 6, 7, 8]) - def test_multi_samples_return_correlated_results_more_wires_than_size_of_observable( - self, num_wires - ): - """Tests if the samples returned by the sample function have - the correct dimensions - """ - - dev = qml.device("default.qubit", wires=num_wires, shots=1000) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.Hadamard(0) - qml.CNOT(wires=[0, 1]) - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) - - outcomes = circuit() - - assert np.array_equal(outcomes[0], outcomes[1]) - - -# pylint: disable=unused-argument -@pytest.mark.parametrize("theta,phi,varphi", list(zip(THETA, PHI, VARPHI))) -class TestTensorExpval: - """Test tensor expectation values""" - - def test_paulix_pauliy(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_identity(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.5 * ( - -6 * np.cos(theta) * (np.cos(varphi) + 1) - - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) - + 3 * np.cos(varphi) * np.sin(phi) - + np.sin(phi) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit", wires=3) - - A1 = np.array([[1, 2], [2, 4]]) - - A2 = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.25 * ( - -30 - + 4 * np.cos(phi) * np.sin(theta) - + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) - - 3 * np.sin(phi) - - 2 - * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) - * np.sin(varphi) - + np.cos(theta) - * ( - 18 - + 5 * np.sin(phi) - + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) - + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) - ) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit", wires=2) - - A = np.array( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] - ) - - obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit", wires=3) - - A = np.array( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] - ) - Identity = np.array([[1, 0], [0, 1]]) - H = np.kron(np.kron(Identity, Identity), A) - obs = qml.Hermitian(H, wires=[2, 1, 0]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -class TestTensorVar: - """Tests for variance of tensor observables""" - - def test_paulix_pauliy(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) - - A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 1057 - - np.cos(2 * phi) - + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) - - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) - + 16 * np.sin(2 * phi) - - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) - - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 - - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) - - 8 - * np.cos(theta) - * ( - 4 - * np.cos(phi) - * ( - 4 - + 8 * np.cos(varphi) - + np.cos(2 * varphi) - - (1 + 6 * np.cos(varphi)) * np.sin(varphi) - ) - + np.sin(phi) - * ( - 15 - + 8 * np.cos(varphi) - - 11 * np.cos(2 * varphi) - + 42 * np.sin(varphi) - + 3 * np.sin(2 * varphi) - ) - ) - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.parametrize("theta, phi, varphi", list(zip(THETA, PHI, VARPHI))) -class TestTensorSample: - """Test tensor expectation values""" - - def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.probability(wires=dev.map_wires(obs.wires)) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - - mean = s1 @ p - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - - mean = s1 @ p - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - def test_hermitian(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - - A = 0.1 * np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain the eigenvalues of - # the hermitian matrix tensor product Z - Z = np.diag([1, -1]) - eigvals = np.linalg.eigvalsh(np.kron(Z, A)) - assert set(np.round(s1, 8).tolist()).issubset(set(np.round(eigvals, 8).tolist())) - - mean = s1 @ p - expected = ( - 0.1 - * 0.5 - * ( - -6 * np.cos(theta) * (np.cos(varphi) + 1) - - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) - + 3 * np.cos(varphi) * np.sin(phi) - + np.sin(phi) - ) - ) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = (s1**2) @ p - (s1 @ p).real ** 2 - expected = ( - 0.01 - * ( - 1057 - - np.cos(2 * phi) - + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) - - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) - + 16 * np.sin(2 * phi) - - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) - - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 - - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) - - 8 - * np.cos(theta) - * ( - 4 - * np.cos(phi) - * ( - 4 - + 8 * np.cos(varphi) - + np.cos(2 * varphi) - - (1 + 6 * np.cos(varphi)) * np.sin(varphi) - ) - + np.sin(phi) - * ( - 15 - + 8 * np.cos(varphi) - - 11 * np.cos(2 * varphi) - + 42 * np.sin(varphi) - + 3 * np.sin(2 * varphi) - ) - ) - ) - / 16 - ) - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - -@pytest.mark.parametrize( - "r_dtype,c_dtype", [(np.float32, np.complex64), (np.float64, np.complex128)] -) -class TestDtypePreserved: - """Test that the user-defined dtype of the device is preserved for QNode - evaluation""" - - @pytest.mark.parametrize( - "op", - [ - qml.SingleExcitation, - qml.SingleExcitationPlus, - qml.SingleExcitationMinus, - qml.DoubleExcitation, - qml.DoubleExcitationPlus, - qml.DoubleExcitationMinus, - qml.OrbitalRotation, - qml.FermionicSWAP, - qml.QubitSum, - qml.QubitCarry, - ], - ) - def test_state_dtype_after_op(self, r_dtype, c_dtype, op): - """Test that the default qubit plugin preserves data types of states when an operation is - applied. As TestApply class check most of operators, we here only check some subtle - examples. - """ - - dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) - - n_wires = op.num_wires - n_params = op.num_params - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - if n_params == 0: - op(wires=range(n_wires)) - elif n_params == 1: - op(0.543, wires=range(n_wires)) - else: - op([0.543] * n_params, wires=range(n_wires)) - return qml.state() - - res = circuit() - assert res.dtype == c_dtype - - @pytest.mark.parametrize( - "measurement", - [ - qml.expval(qml.PauliY(0)), - qml.var(qml.PauliY(0)), - qml.probs(wires=[1]), - qml.probs(wires=[2, 0]), - ], - ) - def test_measurement_real_dtype(self, r_dtype, c_dtype, measurement): - """Test that the default qubit plugin provides correct result for a simple circuit""" - p = 0.543 - - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == r_dtype - - @pytest.mark.parametrize( - "measurement", - [qml.state(), qml.density_matrix(wires=[1]), qml.density_matrix(wires=[2, 0])], - ) - def test_measurement_complex_dtype(self, r_dtype, c_dtype, measurement): - """Test that the default qubit plugin provides correct result for a simple circuit""" - p = 0.543 - - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == c_dtype - - -class TestProbabilityIntegration: - """Test probability method for when analytic is True/False""" - - # pylint: disable=unused-argument - def mock_analytic_counter(self, wires=None): - self.analytic_counter += 1 - return np.array([1, 0, 0, 0], dtype=float) - - @pytest.mark.parametrize("x", [[0.2, 0.5], [0.4, 0.9], [0.8, 0.3]]) - def test_probability(self, x, tol): - """Test that the probability function works for finite and infinite shots""" - dev = qml.device("default.qubit", wires=2, shots=1000) - dev_analytic = qml.device("default.qubit", wires=2, shots=None) - - def circuit(x): - qml.RX(x[0], wires=0) - qml.RY(x[1], wires=0) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[0, 1]) - - prob = qml.QNode(circuit, dev) - prob_analytic = qml.QNode(circuit, dev_analytic) - - assert np.isclose(prob(x).sum(), 1, atol=tol, rtol=0) - assert np.allclose(prob_analytic(x), prob(x), atol=0.1, rtol=0) - assert not np.array_equal(prob_analytic(x), prob(x)) - - # pylint: disable=attribute-defined-outside-init - def test_call_generate_samples(self, monkeypatch): - """Test analytic_probability call when generating samples""" - self.analytic_counter = False - - dev = qml.device("default.qubit", wires=2, shots=1000) - monkeypatch.setattr(dev, "analytic_probability", self.mock_analytic_counter) - - # generate samples through `generate_samples` (using 'analytic_probability') - dev.generate_samples() - - # should call `analytic_probability` once through `generate_samples` - assert self.analytic_counter == 1 - - def test_stateless_analytic_return(self): - """Test that analytic_probability returns None if device is stateless""" - dev = qml.device("default.qubit", wires=2) - dev._state = None - - assert dev.analytic_probability() is None - - -class TestWiresIntegration: - """Test that the device integrates with PennyLane's wire management.""" - - def make_circuit_probs(self, wires): - """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = qml.device("default.qubit", wires=wires) - n_wires = len(wires) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(0.5, wires=wires[0 % n_wires]) - qml.RY(2.0, wires=wires[1 % n_wires]) - if n_wires > 1: - qml.CNOT(wires=[wires[0], wires[1]]) - return qml.probs(wires=wires) - - return circuit - - @pytest.mark.parametrize( - "wires1, wires2", - [ - (["a", "c", "d"], [2, 3, 0]), - ([-1, -2, -3], ["q1", "ancilla", 2]), - (["a", "c"], [3, 0]), - ([-1, -2], ["ancilla", 2]), - (["a"], ["nothing"]), - ], - ) - def test_wires_probs(self, wires1, wires2, tol): - """Test that the probability vector of a circuit is independent from the wire labels used.""" - - circuit1 = self.make_circuit_probs(wires1) - circuit2 = self.make_circuit_probs(wires2) - - assert np.allclose(circuit1(), circuit2(), tol) - - def test_wires_not_found_exception(self): - """Tests that an exception is raised when wires not present on the device are adressed.""" - dev = qml.device("default.qubit", wires=["a", "b"]) - - with qml.queuing.AnnotatedQueue() as q: - qml.RX(0.5, wires="c") - - tape = qml.tape.QuantumScript.from_queue(q) - with pytest.raises(WireError, match="Did not find some of the wires"): - dev.execute(tape) - - wires_to_try = [ - (1, Wires([0])), - (4, Wires([1, 3])), - (["a", 2], Wires([2])), - (["a", 2], Wires([2, "a"])), - ] - - @pytest.mark.parametrize("dev_wires, wires_to_map", wires_to_try) - def test_map_wires_caches(self, dev_wires, wires_to_map): - """Test that multiple calls to map_wires will use caching.""" - dev = qml.device("default.qubit", wires=dev_wires) - - original_hits = dev.map_wires.cache_info().hits - original_misses = dev.map_wires.cache_info().misses - - # The first call is computed: it's a miss as it didn't come from the cache - dev.map_wires(wires_to_map) - - # The number of misses increased - assert dev.map_wires.cache_info().misses > original_misses - - # The second call comes from the cache: it's a hit - dev.map_wires(wires_to_map) - - # The number of hits increased - assert dev.map_wires.cache_info().hits > original_hits - - -class TestGetSlice: - """Tests for the _get_slice function.""" - - def test_get_slice(self): - """Test that the _get_slice function returns the expected slice and allows us to slice - correctly into an array.""" - - sl = _get_slice(1, 1, 3) - array = np.arange(27).reshape((3, 3, 3)) - target = array[:, 1, :] - - assert sl == (slice(None, None, None), 1, slice(None, None, None)) - assert np.allclose(array[sl], target) - - def test_get_slice_first(self): - """Test that the _get_slice function returns the expected slice when accessing the first - axis of an array.""" - - sl = _get_slice(2, 0, 3) - array = np.arange(27).reshape((3, 3, 3)) - target = array[2] - - assert sl == (2, slice(None, None, None), slice(None, None, None)) - assert np.allclose(array[sl], target) - - def test_get_slice_last(self): - """Test that the _get_slice function returns the expected slice when accessing the last - axis of an array.""" - - sl = _get_slice(0, 2, 3) - array = np.arange(27).reshape((3, 3, 3)) - target = array[:, :, 0] - - assert sl == (slice(None, None, None), slice(None, None, None), 0) - assert np.allclose(array[sl], target) - - def test_get_slice_1d(self): - """Test that the _get_slice function returns the expected slice when accessing a - 1-dimensional array.""" - - sl = _get_slice(2, 0, 1) - array = np.arange(27) - target = array[2] - - assert sl == (2,) - assert np.allclose(array[sl], target) - - -class TestApplyOps: - """Tests for special methods listed in _apply_ops that use array manipulation tricks to apply - gates in DefaultQubit.""" - - state = np.arange(2**4, dtype=np.complex128).reshape((2, 2, 2, 2)) - dev = qml.device("default.qubit", wires=4) - - single_qubit_ops = [ - (qml.PauliX, dev._apply_x), - (qml.PauliY, dev._apply_y), - (qml.PauliZ, dev._apply_z), - (qml.Hadamard, dev._apply_hadamard), - (qml.S, dev._apply_s), - (qml.T, dev._apply_t), - (qml.SX, dev._apply_sx), - ] - two_qubit_ops = [ - (qml.CNOT, dev._apply_cnot), - (qml.SWAP, dev._apply_swap), - (qml.CZ, dev._apply_cz), - ] - three_qubit_ops = [ - (qml.Toffoli, dev._apply_toffoli), - ] - - @pytest.mark.parametrize("op, method", single_qubit_ops) - def test_apply_single_qubit_op(self, op, method): - """Test if the application of single qubit operations is correct.""" - state_out = method(self.state, axes=[1]) - op = op(wires=[1]) - matrix = op.matrix() - state_out_einsum = np.einsum("ab,ibjk->iajk", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", two_qubit_ops) - def test_apply_two_qubit_op(self, op, method): - """Test if the application of two qubit operations is correct.""" - state_out = method(self.state, axes=[0, 1]) - op = op(wires=[0, 1]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2, 2, 2)) - state_out_einsum = np.einsum("abcd,cdjk->abjk", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", two_qubit_ops) - def test_apply_two_qubit_op_reverse(self, op, method): - """Test if the application of two qubit operations is correct when the applied wires are - reversed.""" - state_out = method(self.state, axes=[2, 1]) - op = op(wires=[2, 1]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2, 2, 2)) - state_out_einsum = np.einsum("abcd,idck->ibak", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_smaller(self, op, method): - """Test if the application of three qubit operations is correct when both control wires are - smaller than the target wire.""" - state_out = method(self.state, axes=[0, 2, 3]) - op = op(wires=[0, 2, 3]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,dkef->akbc", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_greater(self, op, method): - """Test if the application of three qubit operations is correct when both control wires are - greater than the target wire.""" - state_out = method(self.state, axes=[2, 1, 0]) - op = op(wires=[2, 1, 0]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,fedk->cbak", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_split(self, op, method): - """Test if the application of three qubit operations is correct when one control wire is smaller - and one control wire is greater than the target wire.""" - state_out = method(self.state, axes=[3, 1, 2]) - op = op(wires=[3, 1, 2]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,kdfe->kacb", matrix, self.state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.jax - def test_apply_parametrized_evolution_raises_error(self): - """Test that applying a ParametrizedEvolution raises an error.""" - param_ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX(0)])) - with pytest.raises( - NotImplementedError, - match="The device default.qubit cannot execute a ParametrizedEvolution operation", - ): - self.dev._apply_parametrized_evolution(state=self.state, operation=param_ev) - - @qml.qnode(self.dev) - def circuit(): - qml.apply(param_ev) - return qml.expval(qml.PauliZ(0)) - - with pytest.raises( - DeviceError, - match="Gate ParametrizedEvolution not supported on device default.qubit.autograd", - ): - circuit() - - self.dev.operations.add("ParametrizedEvolution") - with pytest.raises( - NotImplementedError, - match="The device default.qubit.autograd cannot execute a ParametrizedEvolution operation", - ): - circuit() - - -class TestStateVector: - """Unit tests for the _apply_state_vector method""" - - def test_full_subsystem(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubit(wires=["a", "b", "c"]) - state = np.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(dev._state.flatten() == state) - spy.assert_not_called() - - def test_partial_subsystem(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubit(wires=["a", "b", "c"]) - state = np.array([1, 0, 1, 0]) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = np.sum(dev._state, axis=(1,)).flatten() - - assert np.all(res == state) - spy.assert_called() - - -class TestApplyOperationUnit: - """Unit tests for the internal _apply_operation method.""" - - def test_internal_apply_ops_case(self, monkeypatch): - """Tests that if we provide an operation that has an internal - implementation, then we use that specific implementation. - - This test provides a new internal function that `default.qubit` uses to - apply `PauliX` (rather than redefining the gate itself). - """ - dev = qml.device("default.qubit", wires=1) - - # Create a dummy operation - expected_test_output = np.ones(1) - supported_gate_application = lambda *args, **kwargs: expected_test_output - - with monkeypatch.context() as m: - # Set the internal ops implementations dict - m.setattr(dev, "_apply_ops", {"PauliX": supported_gate_application}) - - test_state = np.array([1, 0]) - op = qml.PauliX(0) - - res = dev._apply_operation(test_state, op) - assert np.allclose(res, expected_test_output) - - def test_diagonal_operation_case(self, monkeypatch): - """Tests the case when the operation to be applied is - diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = qml.device("default.qubit", wires=1) - par = 0.3 - - test_state = np.array([1, 0]) - wires = 0 - op = qml.PhaseShift(par, wires=wires) - assert op.name not in dev._apply_ops - - # Set the internal _apply_diagonal_unitary - history = [] - mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) - with monkeypatch.context() as m: - m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) - assert dev._apply_diagonal_unitary == mock_apply_diag - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, np.diag(op.matrix())) - assert np.allclose(res_wires, wires) - - def test_apply_einsum_case(self, monkeypatch): - """Tests the case when np.einsum is used to apply an operation in - default.qubit.""" - dev = qml.device("default.qubit", wires=1) - - test_state = np.array([1, 0]) - wires = 0 - - # Redefine the S gate so that it is an example for a one-qubit gate - # that is not registered in the diagonal_in_z_basis attribute - class TestSGate(qml.operation.Operation): - num_wires = 1 - - # pylint: disable=unused-argument - @staticmethod - def compute_matrix(*params, **hyperparams): - return np.array([[1, 0], [0, 1j]]) - - dev.operations.add("TestSGate") - op = TestSGate(wires=wires) - - assert op.name in dev.operations - assert op.name not in dev._apply_ops - - # Set the internal _apply_unitary_einsum - history = [] - mock_apply_einsum = lambda state, matrix, wires: history.append((state, matrix, wires)) - with monkeypatch.context() as m: - m.setattr(dev, "_apply_unitary_einsum", mock_apply_einsum) - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, op.matrix()) - assert np.allclose(res_wires, wires) - - def test_apply_tensordot_case(self, monkeypatch): - """Tests the case when np.tensordot is used to apply an operation in - default.qubit.""" - dev = qml.device("default.qubit", wires=3) - - test_state = np.array([1, 0]) - wires = [0, 1, 2] - - # Redefine the Toffoli gate so that it is an example for a gate with - # more than two wires - class TestToffoli(qml.operation.Operation): - num_wires = 3 - - # pylint: disable=unused-argument - @staticmethod - def compute_matrix(*params, **hyperparams): - return U_toffoli - - dev.operations.add("TestToffoli") - op = TestToffoli(wires=wires) - - assert op.name in dev.operations - assert op.name not in dev._apply_ops - - # Set the internal _apply_unitary_tensordot - history = [] - mock_apply_tensordot = lambda state, matrix, wires: history.append((state, matrix, wires)) - - with monkeypatch.context() as m: - m.setattr(dev, "_apply_unitary", mock_apply_tensordot) - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, op.matrix()) - assert np.allclose(res_wires, wires) - - def test_apply_unitary_tensordot_double_broadcasting_error(self): - """Tests that an error is raised if attempting to use _apply_unitary - with a broadcasted matrix and a broadcasted state simultaneously.""" - dev = qml.device("default.qubit", wires=3) - - class BroadcastedToffoli(qml.operation.Operation): - num_wires = 3 - batch_size = 3 - num_params = 0 - - # pylint: disable=unused-argument - @staticmethod - def compute_matrix(*params, **hyperparams): - return np.array([U_toffoli] * 3) - - state = np.eye(8)[:3] - wires = qml.wires.Wires([0, 1, 2]) - - mat = BroadcastedToffoli(wires=wires).matrix() - with pytest.raises(NotImplementedError, match="broadcasted unitary to an already"): - dev._apply_unitary(state, mat, wires=wires) - - def test_identity_skipped(self, mocker): - """Test that applying the identity operation does not perform any additional computations.""" - dev = qml.device("default.qubit", wires=1) - - starting_state = np.array([1, 0]) - op = qml.Identity(0) - - spy_diagonal = mocker.spy(dev, "_apply_diagonal_unitary") - spy_einsum = mocker.spy(dev, "_apply_unitary_einsum") - spy_unitary = mocker.spy(dev, "_apply_unitary") - - res = dev._apply_operation(starting_state, op) - assert res is starting_state - - spy_diagonal.assert_not_called() - spy_einsum.assert_not_called() - spy_unitary.assert_not_called() - - -class TestHamiltonianSupport: - """Tests the devices' native support for Hamiltonian observables.""" - - def test_do_not_split_analytic(self, mocker): - """Tests that the Hamiltonian is not split for shots=None.""" - dev = qml.device("default.qubit", wires=2) - H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="parameter-shift", interface=None) - def circuit(): - return qml.expval(H) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_split_finite_shots(self, mocker): - """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) - spy = mocker.spy(dev, "expval") - - H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev) - def circuit(): - return qml.expval(H) - - circuit() - - # evaluated one expval per Pauli observable - assert spy.call_count == 2 - - def test_error_hamiltonian_expval_finite_shots(self): - """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) - H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) - - with pytest.raises(AssertionError, match="Hamiltonian must be used with shots=None"): - dev.expval(H) - - def test_error_hamiltonian_expval_wrong_wires(self): - """Tests that expval fails if Hamiltonian uses non-device wires.""" - dev = qml.device("default.qubit", wires=2, shots=None) - H = qml.Hamiltonian([0.1, 0.2, 0.3], [qml.PauliX(0), qml.PauliZ(1), qml.PauliY(2)]) - - with pytest.raises( - WireError, - match=r"Did not find some of the wires \(0, 1, 2\) on device with wires \(0, 1\).", - ): - dev.expval(H) - - def test_Hamiltonian_filtered_from_rotations(self, mocker): - """Tests that the device does not attempt to get rotations for Hamiltonians.""" - dev = qml.device("default.qubit", wires=2, shots=10) - H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) - - spy = mocker.spy(qml.QubitDevice, "_get_diagonalizing_gates") - qs = qml.tape.QuantumScript([qml.RX(1, 0)], [qml.expval(qml.PauliX(0)), qml.expval(H)]) - rotations = dev._get_diagonalizing_gates(qs) - - assert len(rotations) == 1 - assert qml.equal(rotations[0], qml.Hadamard(0)) - - call_args = spy.call_args.args[1] # 0 is self (the device) - assert isinstance(call_args, qml.tape.QuantumScript) - assert len(call_args.operations) == 0 - assert len(call_args.measurements) == 1 - assert qml.equal(call_args.measurements[0], qml.expval(qml.PauliX(0))) - - -@pytest.mark.parametrize("is_state_batched", [False, True]) -class TestSumSupport: - """Tests for custom Sum support in DefaultQubit.""" - - @staticmethod - def expected_grad(is_state_batched): - if is_state_batched: - return [[-np.sin(1.3), -np.sin(0.4)], [np.cos(1.3), np.cos(0.4)]] - return [-np.sin(1.3), np.cos(1.3)] - - @staticmethod - def circuit(y, z, is_state_batched): - rx_param = [1.3, 0.4] if is_state_batched else 1.3 - qml.RX(rx_param, 0) - return qml.expval( - qml.sum( - qml.s_prod(y, qml.PauliY(0)), - qml.s_prod(z, qml.PauliZ(0)), - ) - ) - - def test_super_expval_not_called(self, is_state_batched, mocker): - """Tests basic expval result, and ensures QubitDevice.expval is not called.""" - dev = qml.device("default.qubit", wires=1) - spy = mocker.spy(qml.QubitDevice, "expval") - obs = qml.sum(qml.s_prod(0.1, qml.PauliX(0)), qml.s_prod(0.2, qml.PauliZ(0))) - assert np.isclose(dev.expval(obs), 0.2) - spy.assert_not_called() - - @pytest.mark.autograd - def test_trainable_autograd(self, is_state_batched): - """Tests that coeffs passed to a sum are trainable with autograd.""" - if is_state_batched: - pytest.skip(msg="Broadcasting, qml.jacobian and new return types do not work together") - dev = qml.device("default.qubit", wires=1) - qnode = qml.QNode(self.circuit, dev, interface="autograd") - y, z = np.array([1.1, 2.2]) - actual = qml.grad(qnode, argnum=[0, 1])(y, z, is_state_batched) - assert np.allclose(actual, self.expected_grad(is_state_batched)) - - @pytest.mark.torch - def test_trainable_torch(self, is_state_batched): - """Tests that coeffs passed to a sum are trainable with torch.""" - import torch - - dev = qml.device("default.qubit", wires=1) - qnode = qml.QNode(self.circuit, dev, interface="torch") - y, z = torch.tensor(1.1, requires_grad=True), torch.tensor(2.2, requires_grad=True) - _qnode = partial(qnode, is_state_batched=is_state_batched) - actual = torch.stack(torch.autograd.functional.jacobian(_qnode, (y, z))) - assert np.allclose(actual, self.expected_grad(is_state_batched)) - - @pytest.mark.tf - def test_trainable_tf(self, is_state_batched): - """Tests that coeffs passed to a sum are trainable with tf.""" - import tensorflow as tf - - dev = qml.device("default.qubit", wires=1) - qnode = qml.QNode(self.circuit, dev, interface="tensorflow") - y, z = tf.Variable(1.1, dtype=tf.float64), tf.Variable(2.2, dtype=tf.float64) - with tf.GradientTape() as tape: - res = qnode(y, z, is_state_batched) - actual = tape.jacobian(res, [y, z]) - assert np.allclose(actual, self.expected_grad(is_state_batched)) - - @pytest.mark.jax - def test_trainable_jax(self, is_state_batched): - """Tests that coeffs passed to a sum are trainable with jax.""" - import jax - - dev = qml.device("default.qubit", wires=1) - qnode = qml.QNode(self.circuit, dev, interface="jax") - y, z = jax.numpy.array([1.1, 2.2]) - actual = jax.jacobian(qnode, argnums=[0, 1])(y, z, is_state_batched) - assert np.allclose(actual, self.expected_grad(is_state_batched)) - - -class TestGetBatchSize: - """Tests for the helper method ``_get_batch_size`` of ``QubitDevice``.""" - - @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) - def test_batch_size_None(self, shape): - """Test that a ``batch_size=None`` is reported correctly.""" - dev = qml.device("default.qubit", wires=1) - tensor0 = np.ones(shape, dtype=complex) - assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None - tensor1 = np.arange(np.prod(shape)).reshape(shape) - assert dev._get_batch_size(tensor1, shape, qml.math.prod(shape)) is None - - @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) - @pytest.mark.parametrize("batch_size", [1, 3]) - def test_batch_size_int(self, shape, batch_size): - """Test that an integral ``batch_size`` is reported correctly.""" - dev = qml.device("default.qubit", wires=1) - full_shape = (batch_size,) + shape - tensor0 = np.ones(full_shape, dtype=complex) - assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size - tensor1 = np.arange(np.prod(full_shape)).reshape(full_shape) - assert dev._get_batch_size(tensor1, shape, qml.math.prod(shape)) == batch_size - - @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested") - def test_invalid_tensor(self): - """Test that an error is raised if a tensor is provided that does not - have a proper shape/ndim.""" - dev = qml.device("default.qubit", wires=1) - with pytest.raises(ValueError, match="could not broadcast"): - dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) - - -class TestDenseMatrixDecompositionThreshold: - """Tests for QFT and Grover operators the automatic transition from dense matrix to decomposition - on calculations.""" - - input = [ - (qml.QFT, 4, True), - (qml.QFT, 6, False), - (qml.GroverOperator, 4, True), - (qml.GroverOperator, 13, False), - ] - - @pytest.mark.parametrize("op, n_wires, condition", input) - def test_threshold(self, op, n_wires, condition): - wires = np.linspace(0, n_wires - 1, n_wires, dtype=int) - op = op(wires=wires) - assert DefaultQubit.stopping_condition.__get__(op)(op) == condition diff --git a/tests/devices/test_default_qubit_autograd.py b/tests/devices/test_default_qubit_autograd.py deleted file mode 100644 index 76f3299b00e..00000000000 --- a/tests/devices/test_default_qubit_autograd.py +++ /dev/null @@ -1,802 +0,0 @@ -# Copyright 2018-2020 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. -""" -Integration tests for the ``default.qubit.autograd`` device. -""" -import pytest - -import pennylane as qml -from pennylane import numpy as np -from pennylane.devices.default_qubit_autograd import DefaultQubitAutograd -from pennylane import DeviceError - - -@pytest.mark.autograd -def test_analytic_deprecation(): - """Tests if the kwarg `analytic` is used and displays error message.""" - msg = "The analytic argument has been replaced by shots=None. " - msg += "Please use shots=None instead of analytic=True." - - with pytest.raises( - DeviceError, - match=msg, - ): - qml.device("default.qubit.autograd", wires=1, shots=1, analytic=True) - - -@pytest.mark.autograd -class TestQNodeIntegration: - """Integration tests for default.qubit.autograd. This test ensures it integrates - properly with the PennyLane UI, in particular the new QNode.""" - - def test_defines_correct_capabilities(self): - """Test that the device defines the right capabilities""" - - dev = qml.device("default.qubit.autograd", wires=1) - cap = dev.capabilities() - capabilities = { - "model": "qubit", - "supports_finite_shots": True, - "supports_tensor_observables": True, - "returns_probs": True, - "returns_state": True, - "supports_inverse_operations": True, - "supports_analytic_computation": True, - "passthru_interface": "autograd", - "supports_broadcasting": True, - "passthru_devices": { - "torch": "default.qubit.torch", - "tf": "default.qubit.tf", - "autograd": "default.qubit.autograd", - "jax": "default.qubit.jax", - }, - } - assert cap == capabilities - - def test_load_device(self): - """Test that the plugin device loads correctly""" - dev = qml.device("default.qubit.autograd", wires=2) - assert dev.num_wires == 2 - assert dev.shots is None - assert dev.short_name == "default.qubit.autograd" - assert dev.capabilities()["passthru_interface"] == "autograd" - - def test_qubit_circuit(self, tol): - """Test that the device provides the correct - result for a simple circuit.""" - p = np.array(0.543) - - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -np.sin(p) - - assert circuit.gradient_fn == "backprop" - assert np.isclose(circuit(p), expected, atol=tol, rtol=0) - - def test_qubit_circuit_broadcasted(self, tol): - """Test that the device provides the correct - result for a simple broadcasted circuit.""" - p = np.array([0.543, 0.21, 1.5]) - - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -np.sin(p) - - assert circuit.gradient_fn == "backprop" - assert np.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_correct_state(self, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - - dev = qml.device("default.qubit.autograd", wires=2) - - state = dev.state - expected = np.array([1, 0, 0, 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(np.pi / 4, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - amplitude = np.exp(-1j * np.pi / 8) / np.sqrt(2) - - expected = np.array([amplitude, 0, np.conj(amplitude), 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_broadcasted(self, tol): - """Test that the device state is correct after applying a - broadcasted quantum function on the device""" - - dev = qml.device("default.qubit.autograd", wires=2) - - state = dev.state - expected = np.array([1, 0, 0, 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(np.array([np.pi / 4, np.pi / 2]), wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - phase = np.exp(-1j * np.pi / 8) - - expected = np.array( - [ - [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], - [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], - ] - ) - assert np.allclose(state, expected, atol=tol, rtol=0) - - -@pytest.mark.autograd -class TestDtypePreserved: - """Test that the user-defined dtype of the device is preserved for QNode - evaluation""" - - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - @pytest.mark.parametrize( - "measurement", - [ - qml.expval(qml.PauliY(0)), - qml.var(qml.PauliY(0)), - qml.probs(wires=[1]), - qml.probs(wires=[2, 0]), - ], - ) - def test_real_dtype(self, r_dtype, measurement): - """Test that the default qubit plugin returns the correct - real data type for a simple circuit""" - p = 0.543 - - dev = qml.device("default.qubit.autograd", wires=3) - dev.R_DTYPE = r_dtype - - @qml.qnode(dev, diff_method="backprop") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == r_dtype - - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - @pytest.mark.parametrize( - "measurement", - [ - qml.expval(qml.PauliY(0)), - qml.var(qml.PauliY(0)), - qml.probs(wires=[1]), - qml.probs(wires=[2, 0]), - ], - ) - def test_real_dtype_broadcasted(self, r_dtype, measurement): - """Test that the default qubit plugin returns the correct - real data type for a simple broadcasted circuit""" - p = np.array([0.543, 0.21, 1.6]) - - dev = qml.device("default.qubit.autograd", wires=3) - dev.R_DTYPE = r_dtype - - @qml.qnode(dev, diff_method="backprop") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == r_dtype - - @pytest.mark.parametrize("c_dtype", [np.complex64, np.complex128]) - @pytest.mark.parametrize( - "measurement", - [qml.state(), qml.density_matrix(wires=[1]), qml.density_matrix(wires=[2, 0])], - ) - def test_complex_dtype(self, c_dtype, measurement): - """Test that the default qubit plugin returns the correct - complex data type for a simple circuit""" - p = 0.543 - - dev = qml.device("default.qubit.autograd", wires=3) - dev.C_DTYPE = c_dtype - - @qml.qnode(dev, diff_method="backprop") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == c_dtype - - @pytest.mark.parametrize("c_dtype", [np.complex64, np.complex128]) - def test_complex_dtype_broadcasted(self, c_dtype): - """Test that the default qubit plugin returns the correct - complex data type for a simple broadcasted circuit""" - p = np.array([0.543, 0.21, 1.6]) - - dev = qml.device("default.qubit.autograd", wires=3) - dev.C_DTYPE = c_dtype - - measurement = qml.state() - - @qml.qnode(dev, diff_method="backprop") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == c_dtype - - -@pytest.mark.autograd -class TestPassthruIntegration: - """Tests for integration with the PassthruQNode""" - - def test_jacobian_variable_multiply(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.autograd device - gives the correct result in the case of parameters multiplied by scalars""" - x = 0.43316321 - y = 0.2162158 - z = 0.75110998 - weights = np.array([x, y, z], requires_grad=True) - - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - assert circuit.gradient_fn == "backprop" - res = circuit(weights) - - expected = np.cos(3 * x) * np.cos(y) * np.cos(z / 2) - np.sin(3 * x) * np.sin(z / 2) - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = qml.jacobian(circuit, 0) - res = grad_fn(np.array(weights)) - - expected = np.array( - [ - -3 * (np.sin(3 * x) * np.cos(y) * np.cos(z / 2) + np.cos(3 * x) * np.sin(z / 2)), - -np.cos(3 * x) * np.sin(y) * np.cos(z / 2), - -0.5 * (np.sin(3 * x) * np.cos(z / 2) + np.cos(3 * x) * np.cos(y) * np.sin(z / 2)), - ] - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_variable_multiply_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.autograd device - gives the correct result in the case of broadcasted parameters multiplied by scalars""" - x = np.array([0.43316321, 92.1, -0.5129]) - y = np.array([0.2162158, 0.241, -0.51]) - z = np.array([0.75110998, 0.12512, 9.12]) - weights = np.array([x, y, z], requires_grad=True) - - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - assert circuit.gradient_fn == "backprop" - res = circuit(weights) - - expected = np.cos(3 * x) * np.cos(y) * np.cos(z / 2) - np.sin(3 * x) * np.sin(z / 2) - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = qml.jacobian(circuit, 0) - res = grad_fn(np.array(weights)) - - expected = np.array( - [ - -3 * (np.sin(3 * x) * np.cos(y) * np.cos(z / 2) + np.cos(3 * x) * np.sin(z / 2)), - -np.cos(3 * x) * np.sin(y) * np.cos(z / 2), - -0.5 * (np.sin(3 * x) * np.cos(z / 2) + np.cos(3 * x) * np.cos(y) * np.sin(z / 2)), - ] - ) - - assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - def test_jacobian_repeated(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.autograd device - gives the correct result in the case of repeated parameters""" - x = 0.43316321 - y = 0.2162158 - z = 0.75110998 - p = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - - expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = qml.jacobian(circuit, 0) - res = grad_fn(p) - - expected = np.array( - [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0] - ) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_repeated_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.autograd device - gives the correct result in the case of repeated broadcasted parameters""" - x = np.array([0.43316321, 92.1, -0.5129]) - y = np.array([0.2162158, 0.241, -0.51]) - z = np.array([0.75110998, 0.12512, 9.12]) - p = np.array([x, y, z], requires_grad=True) - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - - expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = qml.jacobian(circuit, 0) - res = grad_fn(p) - - expected = np.array( - [ - -np.cos(x) * np.sin(y) ** 2, - -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), - np.zeros_like(x), - ] - ) - assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - def test_jacobian_agrees_backprop_parameter_shift(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.autograd device - gives the correct result with respect to the parameter-shift method""" - p = np.array([0.43316321, 0.2162158, 0.75110998, 0.94714242], requires_grad=True) - - def circuit(x): - for i in range(0, len(p), 2): - qml.RX(x[i], wires=0) - qml.RY(x[i + 1], wires=1) - for i in range(2): - qml.CNOT(wires=[i, i + 1]) - return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - - dev1 = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=3) - - def cost(x): - return qml.math.stack(circuit(x)) - - circuit1 = qml.QNode(cost, dev1, diff_method="backprop", interface="autograd") - circuit2 = qml.QNode(cost, dev2, diff_method="parameter-shift") - - res = circuit1(p) - - assert np.allclose(res, circuit2(p), atol=tol, rtol=0) - - assert circuit1.gradient_fn == "backprop" - assert circuit2.gradient_fn is qml.gradients.param_shift - - grad_fn = qml.jacobian(circuit1, 0) - res = grad_fn(p) - assert np.allclose(res, qml.jacobian(circuit2)(p), atol=tol, rtol=0) - - @pytest.mark.parametrize("wires", [[0], ["abc"]]) - def test_state_differentiability(self, wires, tol): - """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=wires) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a): - qml.RY(a, wires=wires[0]) - return qml.state() - - a = np.array(0.54, requires_grad=True) - - def cost(a): - """A function of the device quantum state, as a function - of input QNode parameters.""" - res = np.abs(circuit(a)) ** 2 - return res[1] - res[0] - - grad = qml.grad(cost)(a) - expected = np.sin(a) - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_state_differentiability_broadcasted(self, tol): - """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a): - qml.RY(a, wires=0) - return qml.expval(qml.PauliZ(0)) - - a = np.array([0.54, 0.32, 1.2], requires_grad=True) - - def cost(a): - """A function of the device quantum state, as a function - of input QNode parameters.""" - circuit(a) - res = np.abs(dev.state) ** 2 - return res[:, 1] - res[:, 0] - - grad = qml.jacobian(cost)(a) - expected = np.diag(np.sin(a)) - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_prob_differentiability(self, tol): - """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = np.array(0.54, requires_grad=True) - b = np.array(0.12, requires_grad=True) - - def cost(a, b): - prob_wire_1 = circuit(a, b) - return prob_wire_1[1] - prob_wire_1[0] - - res = cost(a, b) - expected = -np.cos(a) * np.cos(b) - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad = qml.grad(cost)(a, b) - expected = [np.sin(a) * np.cos(b), np.cos(a) * np.sin(b)] - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_prob_differentiability_broadcasted(self, tol): - """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.autograd", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = np.array([0.54, 0.32, 1.2], requires_grad=True) - b = np.array(0.12, requires_grad=True) - - def cost(a, b): - prob_wire_1 = circuit(a, b) - return prob_wire_1[:, 1] - prob_wire_1[:, 0] - - res = cost(a, b) - expected = -np.cos(a) * np.cos(b) - assert np.allclose(res, expected, atol=tol, rtol=0) - - jac = qml.jacobian(cost)(a, b) - expected = np.array([np.sin(a) * np.cos(b), np.cos(a) * np.sin(b)]) - expected = (np.diag(expected[0]), expected[1]) # Only first parameter is broadcasted - assert all(np.allclose(j, e, atol=tol, rtol=0) for j, e in zip(jac, expected)) - - def test_backprop_gradient(self, tol): - """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.autograd", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = np.array(-0.234, requires_grad=True) - b = np.array(0.654, requires_grad=True) - - res = circuit(a, b) - expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) - assert np.allclose(res, expected_cost, atol=tol, rtol=0) - - res = qml.grad(circuit)(a, b) - expected_grad = np.array( - [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] - ) - assert np.allclose(res, expected_grad, atol=tol, rtol=0) - - def test_backprop_gradient_broadcasted(self, tol): - """Tests that the gradient of the broadcasted qnode is correct""" - dev = qml.device("default.qubit.autograd", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = np.array(0.12, requires_grad=True) - b = np.array([0.54, 0.32, 1.2], requires_grad=True) - - res = circuit(a, b) - expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) - assert np.allclose(res, expected_cost, atol=tol, rtol=0) - - res = qml.jacobian(circuit)(a, b) - expected = np.array([-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))]) - expected = (expected[0], np.diag(expected[1])) - assert all(np.allclose(r, e, atol=tol, rtol=0) for r, e in zip(res, expected)) - - @pytest.mark.parametrize( - "x, shift", - [np.array((0.0, 0.0), requires_grad=True), np.array((0.5, -0.5), requires_grad=True)], - ) - def test_hessian_at_zero(self, x, shift): - """Tests that the Hessian at vanishing state vector amplitudes - is correct.""" - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def circuit(x): - qml.RY(shift, wires=0) - qml.RY(x, wires=0) - return qml.expval(qml.PauliZ(0)) - - assert qml.math.isclose(qml.jacobian(circuit)(x), 0.0) - assert qml.math.isclose(qml.jacobian(qml.jacobian(circuit))(x), -1.0) - assert qml.math.isclose(qml.grad(qml.grad(circuit))(x), -1.0) - - @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) - @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) - def test_autograd_interface_gradient(self, operation, diff_method, tol): - """Tests that the gradient of an arbitrary U3 gate is correct - using the Autograd interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.autograd", wires=1) - state = np.array(1j * np.array([1, -1]) / np.sqrt(2), requires_grad=False) - - @qml.qnode(dev, diff_method=diff_method, interface="autograd") - def circuit(x, weights, w): - """In this example, a mixture of scalar - arguments, array arguments, and keyword arguments are used.""" - qml.QubitStateVector(state, wires=w) - operation(x, weights[0], weights[1], wires=w) - return qml.expval(qml.PauliX(w)) - - def cost(params): - """Perform some classical processing""" - return circuit(params[0], params[1:], w=0) ** 2 - - theta = 0.543 - phi = -0.234 - lam = 0.654 - - params = np.array([theta, phi, lam], requires_grad=True) - - res = cost(params) - expected_cost = (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) ** 2 - assert np.allclose(res, expected_cost, atol=tol, rtol=0) - - # Check that the correct differentiation method is being used. - if diff_method == "backprop": - assert circuit.gradient_fn == "backprop" - elif diff_method == "parameter-shift": - assert circuit.gradient_fn is qml.gradients.param_shift - else: - assert circuit.gradient_fn is qml.gradients.finite_diff - - res = qml.grad(cost)(params) - expected_grad = ( - np.array( - [ - np.sin(theta) * np.cos(lam) * np.cos(phi), - np.cos(theta) * np.cos(lam) * np.sin(phi) + np.sin(lam) * np.cos(phi), - np.cos(theta) * np.sin(lam) * np.cos(phi) + np.cos(lam) * np.sin(phi), - ] - ) - * 2 - * (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) - ) - assert np.allclose(res, expected_grad, atol=tol, rtol=0) - - @pytest.mark.parametrize("interface", ["tf", "torch"]) - def test_error_backprop_wrong_interface(self, interface): - """Tests that an error is raised if diff_method='backprop' but not using - the Autograd interface""" - dev = qml.device("default.qubit.autograd", wires=1) - - def circuit(x, w=None): - qml.RZ(x, wires=w) - return qml.expval(qml.PauliX(w)) - - with pytest.raises( - qml.QuantumFunctionError, - match="default.qubit.autograd only supports diff_method='backprop' when using the autograd interface", - ): - qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) - - -@pytest.mark.autograd -class TestHighLevelIntegration: - """Tests for integration with higher level components of PennyLane.""" - - def test_do_not_split_analytic_autograd(self, mocker): - """Tests that the Hamiltonian is not split for shots=None using the autograd device.""" - dev = qml.device("default.qubit.autograd", wires=2) - H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(): - return qml.expval(H) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_do_not_split_analytic_autograd_broadcasted(self, mocker): - """Tests that the Hamiltonian is not split for shots=None - and broadcasting using the autograd device.""" - dev = qml.device("default.qubit.autograd", wires=2) - H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="autograd") - def circuit(): - qml.RX(np.zeros(5), 0) - return qml.expval(H) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_template_integration(self): - """Test that a PassthruQNode default.qubit.autograd works with templates.""" - dev = qml.device("default.qubit.autograd", wires=2) - - @qml.qnode(dev, diff_method="backprop") - def circuit(weights): - qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=2) - weights = np.random.random(shape, requires_grad=True) - - grad = qml.grad(circuit)(weights) - assert grad.shape == weights.shape - - -# pylint: disable=protected-access -@pytest.mark.autograd -class TestOps: - """Unit tests for operations supported by the default.qubit.autograd device""" - - def test_multirz_jacobian(self): - """Test that the patched numpy functions are used for the MultiRZ - operation and the jacobian can be computed.""" - wires = 4 - dev = qml.device("default.qubit.autograd", wires=wires) - - @qml.qnode(dev, diff_method="backprop") - def circuit(param): - qml.MultiRZ(param, wires=[0, 1]) - return qml.probs(wires=list(range(wires))) - - param = np.array(0.3, requires_grad=True) - res = qml.jacobian(circuit)(param) - assert np.allclose(res, np.zeros(wires**2)) - - def test_full_subsystem(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubitAutograd(wires=["a", "b", "c"]) - state = np.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(dev._state.flatten() == state) - spy.assert_not_called() - - def test_partial_subsystem(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubitAutograd(wires=["a", "b", "c"]) - state = np.array([1, 0, 1, 0]) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = np.sum(dev._state, axis=(1,)).flatten() - - assert np.all(res == state) - spy.assert_called() - - -@pytest.mark.autograd -class TestOpsBroadcasted: - """Unit tests for broadcasted operations supported by the default.qubit.autograd device""" - - def test_multirz_jacobian_broadcasted(self): - """Test that the patched numpy functions are used for the MultiRZ - operation and the jacobian can be computed.""" - wires = 4 - dev = qml.device("default.qubit.autograd", wires=wires) - - @qml.qnode(dev, diff_method="backprop") - def circuit(param): - qml.MultiRZ(param, wires=[0, 1]) - return qml.probs(wires=list(range(wires))) - - param = np.array([0.3, 0.9, -4.3], requires_grad=True) - res = qml.jacobian(circuit)(param) - assert np.allclose(res, np.zeros((3, wires**2, 3))) - - def test_full_subsystem_broadcasted(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubitAutograd(wires=["a", "b", "c"]) - state = np.array([[1, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 1, 1, 1, 0]]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(dev._state.reshape((2, 8)) == state) - spy.assert_not_called() - - def test_partial_subsystem_broadcasted(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubitAutograd(wires=["a", "b", "c"]) - state = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [1, 1, 0, 0]]) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = np.sum(dev._state, axis=(2,)).reshape((3, 4)) - - assert np.allclose(res, state) - spy.assert_called() diff --git a/tests/devices/test_default_qubit_broadcasting.py b/tests/devices/test_default_qubit_broadcasting.py deleted file mode 100644 index d783754d1bc..00000000000 --- a/tests/devices/test_default_qubit_broadcasting.py +++ /dev/null @@ -1,2023 +0,0 @@ -# Copyright 2018-2020 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 :mod:`pennylane.plugin.DefaultQubit` device when using broadcasting. -""" -from itertools import product - -# pylint: disable=protected-access,cell-var-from-loop,too-many-arguments -import math - -import pytest -from gate_data import ( - X, - Y, - Z, - S, - T, - H, - CNOT, - SWAP, - CZ, - ISWAP, - SISWAP, - CSWAP, - Rphi, - Rotx, - Roty, - Rotz, - MultiRZ1, - Rot3, - CRotx, - CRoty, - CRotz, - MultiRZ2, - IsingXX, - IsingYY, - IsingZZ, - CRot3, - I, - Toffoli, -) - -import pennylane as qml -from pennylane import numpy as np, DeviceError -from pennylane.devices.default_qubit import DefaultQubit - -THETA = np.linspace(0.11, 1, 3) -PHI = np.linspace(0.32, 1, 3) -VARPHI = np.linspace(0.02, 1, 3) - -INVSQ2 = 1 / math.sqrt(2) -T_PHASE = np.exp(1j * np.pi / 4) -T_PHASE_C = np.exp(-1j * np.pi / 4) - -# Variant of diag that does not take the diagonal of a 2d array, but broadcasts diag. -diag = lambda x: np.array([np.diag(_x) for _x in x]) if np.ndim(x) == 2 else np.diag(x) - - -def mat_vec(mat, vec, par=None, inv=False): - if par is not None: - scalar = [np.isscalar(p) for p in par] - if not all(scalar): - batch_size = len(par[scalar.index(False)]) - par = [tuple(p if s else p[i] for p, s in zip(par, scalar)) for i in range(batch_size)] - mat = np.array([mat(*_par) for _par in par]) - else: - mat = mat(*par) - - if inv: - mat = np.moveaxis(mat.conj(), -2, -1) - - return np.einsum("...ij,...j->...i", mat, vec) - - -class TestApplyBroadcasted: - """Tests that operations and inverses of certain operations are applied to a broadcasted - state/with broadcasted parameters (or both) correctly, or that the proper errors are raised. - """ - - triple_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - test_data_no_parameters = [ - (qml.PauliX, triple_state, mat_vec(X, triple_state)), - (qml.PauliY, triple_state, mat_vec(Y, triple_state)), - (qml.PauliZ, triple_state, mat_vec(Z, triple_state)), - (qml.S, triple_state, mat_vec(S, triple_state)), - (qml.T, triple_state, mat_vec(T, triple_state)), - (qml.Hadamard, triple_state, mat_vec(H, triple_state)), - (qml.Identity, triple_state, triple_state), - ] - - @pytest.mark.parametrize("operation,input,expected_output", test_data_no_parameters) - def test_apply_operation_single_wire_no_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have no parameters.""" - - qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) - qubit_device_1_wire.apply([operation(wires=[0])]) - - assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) - assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE - - single_state = np.array([[0, 0.6, 0, 0.8]]) - triple_state = np.array([[1, 0, 0, 0], [0, 0, INVSQ2, -INVSQ2], [0, 0.6, 0, 0.8]]) - - test_data_two_wires_no_param = [ - (qml_op, state, mat_vec(mat_op, state)) - for (qml_op, mat_op), state in product( - zip( - [qml.CNOT, qml.SWAP, qml.CZ, qml.ISWAP, qml.SISWAP, qml.SQISW], - [CNOT, SWAP, CZ, ISWAP, SISWAP, SISWAP], - ), - [single_state, triple_state], - ) - ] - - @pytest.mark.parametrize("operation,input,expected_output", test_data_two_wires_no_param) - def test_apply_operation_two_wires_no_parameters_broadcasted( - self, qubit_device_2_wires, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for two wire - operations that have no parameters.""" - - qubit_device_2_wires._state = np.array(input, dtype=qubit_device_2_wires.C_DTYPE).reshape( - (-1, 2, 2) - ) - qubit_device_2_wires.apply([operation(wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.reshape((-1, 4)), - np.array(expected_output), - atol=tol, - rtol=0, - ) - assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE - - quad_state = np.array( - [ - [0.6, 0, 0, 0, 0, 0, 0.8, 0], - [-INVSQ2, INVSQ2, 0, 0, 0, 0, 0, 0], - [0, 0, 0.5, 0.5, 0.5, -0.5, 0, 0], - [0, 0, 0.5, 0, 0.5, -0.5, 0, 0.5], - ] - ) - test_data_three_wires_no_parameters = [(qml.CSWAP, quad_state, mat_vec(CSWAP, quad_state))] - - @pytest.mark.parametrize("operation,input,expected_output", test_data_three_wires_no_parameters) - def test_apply_operation_three_wires_no_parameters_broadcasted( - self, qubit_device_3_wires, tol, operation, input, expected_output - ): - """Tests that applying an operation yields the expected output state for three wire - operations that have no parameters.""" - - qubit_device_3_wires._state = np.array(input, dtype=qubit_device_3_wires.C_DTYPE).reshape( - (-1, 2, 2, 2) - ) - qubit_device_3_wires.apply([operation(wires=[0, 1, 2])]) - - assert np.allclose( - qubit_device_3_wires._state.reshape((-1, 8)), - np.array(expected_output), - atol=tol, - rtol=0, - ) - assert qubit_device_3_wires._state.dtype == qubit_device_3_wires.C_DTYPE - - single_state = np.array([[0, 0, 1, 0]]) - triple_state = np.array( - [ - [0, 0, 1, 0], - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [0.5, -0.5, 0.5j, -0.5j], - ] - ) - - # TODO[dwierichs]: add tests with qml.BaisState once `_apply_basis_state` supports broadcasting - @pytest.mark.parametrize( - "operation,expected_output,par", - [(qml.QubitStateVector, s, s) for s in [single_state, triple_state]], - ) - def test_apply_operation_state_preparation_broadcasted( - self, qubit_device_2_wires, tol, operation, expected_output, par - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have no parameters.""" - - par = np.array(par) - qubit_device_2_wires.reset() - qubit_device_2_wires.apply([operation(par, wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.reshape((-1, 4)), - np.array(expected_output), - atol=tol, - rtol=0, - ) - - # Collect test cases for single-scalar-parameter single-wire operations and their inverses - # For each operation, we choose broadcasted state, broadcasted params, or both - state_1 = np.array([0.6, 0.8j]) - state_5 = np.array([[INVSQ2, INVSQ2], [0.6, 0.8], [0, 1j], [-1, 0], [-INVSQ2, INVSQ2]]) - scalar_par_1 = [np.pi / 2] - scalar_par_5 = [[np.pi / 3, np.pi, 0.5, -1.2, -3 * np.pi / 2]] - test_data_single_wire_with_parameters = [ - (qml_op, state, mat_vec(mat_op, state, par=par), par) - for (qml_op, mat_op), (state, par) in product( - zip( - [qml.PhaseShift, qml.RX, qml.RY, qml.RZ, qml.MultiRZ], - [Rphi, Rotx, Roty, Rotz, MultiRZ1], - ), - [(state_1, scalar_par_5), (state_5, scalar_par_1), (state_5, scalar_par_5)], - ) - ] - - # Add qml.QubitUnitary test cases - matrix_1_par_1 = [np.array([[1, 1j], [1j, 1]]) * INVSQ2] - matrix_1_par_5 = [ - np.array( - [ - np.array([[1, -1j], [-1j, 1]]) * INVSQ2, - np.array([[1, -1], [1, 1]]) * INVSQ2, - np.array([[T_PHASE_C, 0], [0, T_PHASE]]), - np.array([[1, 0], [0, -1]]), - T, - ] - ) - ] - test_data_single_wire_with_parameters += [ - (qml.QubitUnitary, s, mat_vec(par[0], s), par) - for s, par in [ - (state_1, matrix_1_par_5), - (state_5, matrix_1_par_1), - (state_5, matrix_1_par_5), - ] - ] - - # Add qml.DiagonalQubitUnitary test cases - diag_par_1 = [[np.exp(1j * 0.1), np.exp(1j * np.pi)]] - diag_par_5 = [ - np.array( - [ - [1, -1j], - [np.exp(1j * 0.4), np.exp(1j * -0.4)], - [np.exp(1j * 0.1), np.exp(1j * np.pi)], - [1.0, np.exp(1j * np.pi / 2)], - [1, 1], - ] - ) - ] - test_data_single_wire_with_parameters += [ - (qml.DiagonalQubitUnitary, s, mat_vec(diag(par[0]), s), par) - for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)] - ] - - # Add qml.SpecialUnitary test cases - theta_1_par_1 = [np.array([np.pi / 2, 0, 0])] - theta_1_par_5 = [ - np.array( - [[np.pi / 2, 0, 0], [0, np.pi / 2, 0], [0, 0, np.pi / 2], [0.3, 0, 0], [0.4, 0.2, 1.2]] - ) - ] - test_data_single_wire_with_parameters += [ - (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 1), s), par) - for s, par in [(state_1, theta_1_par_5), (state_5, theta_1_par_1), (state_5, theta_1_par_5)] - ] - - # Add qml.Rot test cases - multi_par_1 = { - "rz_0": [0.632, 0, 0], - "ry": [0, 0.632, 0], - "rz_1": [0, 0, 0.632], - "mixed": [0.12, -2.468, 0.812], - } - multi_par_5 = { - "rz_0": [[np.pi / 2 * i for i in range(5)], 0, 0], - "ry": [0, [np.pi / 2 * i for i in range(5)], 0], - "rz_1": [0, 0, [np.pi / 2 * i for i in range(5)]], - "mixed": [[np.pi / 2 * i for i in range(5)], [np.pi / 2 * i for i in range(5)], np.pi], - } - for like in ["rz_0", "ry", "rz_1", "mixed"]: - states_and_pars = [ - (state_1, multi_par_5[like]), - (state_5, multi_par_1[like]), - (state_5, multi_par_5[like]), - ] - test_data_single_wire_with_parameters += [ - (qml.Rot, s, mat_vec(Rot3, s, par=par), par) for s, par in states_and_pars - ] - - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_single_wire_with_parameters - ) - def test_apply_operation_single_wire_with_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that applying an operation yields the expected output state for single wire - operations that have parameters.""" - - qubit_device_1_wire._state = np.array(input, dtype=qubit_device_1_wire.C_DTYPE) - - par = tuple(np.array(p) for p in par) - qubit_device_1_wire.apply([operation(*par, wires=[0])]) - - assert np.allclose(qubit_device_1_wire._state, np.array(expected_output), atol=tol, rtol=0) - assert qubit_device_1_wire._state.dtype == qubit_device_1_wire.C_DTYPE - - # Collect test cases for single-scalar-parameter two-wires operations and their inverses - # For each operation, we choose broadcasted state, broadcasted params, or both - state_1 = np.array([0.6, 0.8j, -0.6, -0.8j]) * INVSQ2 - state_5 = np.array( - [ - [0, 1, 0, 0], - [0, 0, 0, 1], - [0, INVSQ2, INVSQ2, 0], - [0.5, 0.5j, -0.5, 0.5], - [0.6, 0, -0.8j, 0], - ] - ) - scalar_par_1 = [np.pi / 2] - scalar_par_5 = [[np.pi / 3, np.pi, 0.5, -1.2, -3 * np.pi / 2]] - two_wires_scalar_par_ops = [ - qml.CRX, - qml.CRY, - qml.CRZ, - qml.MultiRZ, - qml.IsingXX, - qml.IsingYY, - qml.IsingZZ, - ] - two_wires_scalar_par_mats = [CRotx, CRoty, CRotz, MultiRZ2, IsingXX, IsingYY, IsingZZ] - test_data_two_wires_with_parameters = [ - (qml_op, state, mat_vec(mat_op, state, par=par), par) - for (qml_op, mat_op), (state, par) in product( - zip(two_wires_scalar_par_ops, two_wires_scalar_par_mats), - [(state_1, scalar_par_5), (state_5, scalar_par_1), (state_5, scalar_par_5)], - ) - ] - - # Add qml.CRot test cases - multi_par_1 = { - "rz_0": [0.632, 0, 0], - "ry": [0, 0.632, 0], - "rz_1": [0, 0, 0.632], - "mixed": [0.12, -2.468, 0.812], - } - multi_par_5 = { - "rz_0": [[np.pi / 2 * i for i in range(5)], 0, 0], - "ry": [0, [np.pi / 2 * i for i in range(5)], 0], - "rz_1": [0, 0, [np.pi / 2 * i for i in range(5)]], - "mixed": [[np.pi / 2 * i for i in range(5)], [np.pi / 2 * i for i in range(5)], np.pi], - } - for like in ["rz_0", "ry", "rz_1", "mixed"]: - states_and_pars = [ - (state_1, multi_par_5[like]), - (state_5, multi_par_1[like]), - (state_5, multi_par_5[like]), - ] - test_data_two_wires_with_parameters += [ - (qml.CRot, s, mat_vec(CRot3, s, par=par), par) for s, par in states_and_pars - ] - - # Add qml.QubitUnitary test cases - matrix_2_par_1 = [SISWAP] - matrix_2_par_5 = [ - np.array( - [ - np.eye(4), - np.array([[1, -1j, 0, 0], [-1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, -1j, 1]]) * INVSQ2, - np.array([[1, -1, 0, 0], [1, 1, 0, 0], [0, 0, 1, -1j], [0, 0, 1j, -1]]) * INVSQ2, - np.array([[T_PHASE_C, 0, 0, 0], [0, T_PHASE, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1j]]), - SISWAP, - ] - ) - ] - test_data_two_wires_with_parameters += [ - (qml.QubitUnitary, s, mat_vec(par[0], s), par) - for s, par in [ - (state_1, matrix_2_par_5), - (state_5, matrix_2_par_1), - (state_5, matrix_2_par_5), - ] - ] - - # Add qml.DiagonalQubitUnitary test cases - diag_par_1 = [np.exp(1j * np.array([0.1, np.pi, 0.2, -2.4]))] - diag_par_5 = [ - np.array( - [ - np.ones(4), - [1, -1j, 1, 1j], - [np.exp(1j * 0.4), np.exp(1j * -0.4), 1j, 1], - [np.exp(1j * 0.1), np.exp(1j * np.pi), INVSQ2 * (1 + 1j), INVSQ2 * (1 - 1j)], - [1.0, np.exp(1j * np.pi / 2), 1, 1], - ] - ) - ] - test_data_two_wires_with_parameters += [ - (qml.DiagonalQubitUnitary, s, mat_vec(diag(par[0]), s), par) - for s, par in [(state_1, diag_par_5), (state_5, diag_par_1), (state_5, diag_par_5)] - ] - - # Add qml.SpecialUnitary test cases - theta_2_par_1 = [np.linspace(0.1, 3, 15)] - theta_2_par_5 = [np.array([0.4, -0.2, 1.2, -0.5, 2.2])[:, np.newaxis] * np.eye(15)[2::3]] - test_data_two_wires_with_parameters += [ - (qml.SpecialUnitary, s, mat_vec(qml.SpecialUnitary.compute_matrix(par[0], 2), s), par) - for s, par in [(state_1, theta_2_par_5), (state_5, theta_2_par_1), (state_5, theta_2_par_5)] - ] - - @pytest.mark.parametrize( - "operation,input,expected_output,par", test_data_two_wires_with_parameters - ) - def test_apply_operation_two_wires_with_parameters_broadcasted( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that applying an operation yields the expected output state for two wire - operations that have parameters.""" - - shape = (5, 2, 2) if np.array(input).size == 20 else (2, 2) - dtype = qubit_device_2_wires.C_DTYPE - qubit_device_2_wires._state = np.array(input, dtype=dtype).reshape(shape) - par = tuple(np.array(p) for p in par) - qubit_device_2_wires.apply([operation(*par, wires=[0, 1])]) - - assert np.allclose( - qubit_device_2_wires._state.reshape((5, 4)), expected_output, atol=tol, rtol=0 - ) - assert qubit_device_2_wires._state.dtype == qubit_device_2_wires.C_DTYPE - - def test_apply_errors_qubit_state_vector_broadcasted(self, qubit_device_2_wires): - """Test that apply fails for incorrect state preparation, and > 2 qubit gates""" - with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array([[1, -1], [0, 2]]), wires=[0])] - ) - - # Also test that the sum-check is *not* performed along the broadcasting dimension - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array([[0.6, 0.8], [0.6, 0.8]]), wires=[0])] - ) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): - # Second dimension does not match 2**num_wires - p = np.array([[1, 0, 1, 1, 0], [0, 1, 1, 0, 1]]) / np.sqrt(3) - qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)."): - # Broadcasting dimension is not first dimension - p = np.array([[1, 1, 0], [0, 1, 1], [1, 0, 1], [0, 1, 1]]) / np.sqrt(2) - qubit_device_2_wires.apply([qml.QubitStateVector(p, wires=[0, 1])]) - - qubit_device_2_wires.reset() - vec = qml.QubitStateVector(np.array([[0, 1, 0, 0], [0, 0, 1, 0]]), wires=[0, 1]) - with pytest.raises( - DeviceError, - match="Operation QubitStateVector cannot be used after other Operations have already been applied " - "on a default.qubit device.", - ): - qubit_device_2_wires.apply([qml.RZ(0.5, wires=[0]), vec]) - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_apply_errors_basis_state_broadcasted(self, qubit_device_2_wires): - """Test that applying the BasisState operation raises the correct errors.""" - with pytest.raises( - ValueError, match="BasisState parameter must consist of 0 or 1 integers." - ): - op = qml.BasisState(np.array([[-0.2, 4.2], [0.5, 1.2]]), wires=[0, 1]) - qubit_device_2_wires.apply([op]) - - with pytest.raises( - ValueError, match="BasisState parameter and wires must be of equal length." - ): - # Test that the error is raised - qubit_device_2_wires.apply( - [qml.BasisState(np.array([[0, 1], [1, 1], [1, 0]]), wires=[0])] - ) - # Test that the broadcasting dimension is allowed to mismatch the length of the wires - qubit_device_2_wires.apply([qml.BasisState(np.array([[0], [1], [0]]), wires=[0])]) - - qubit_device_2_wires.reset() - qubit_device_2_wires.apply([qml.RZ(0.5, wires=[0])]) - vec = qml.BasisState(np.array([[0, 0], [1, 0], [1, 1]]), wires=[0, 1]) - with pytest.raises( - DeviceError, - match="Operation BasisState cannot be used after other Operations have already been applied " - "on a default.qubit device.", - ): - qubit_device_2_wires.apply([vec]) - - -zero = [1, 0] -one = [0, 1] -plus = [INVSQ2, INVSQ2] -minus = [INVSQ2, -INVSQ2] -y_plus = [INVSQ2, 1j * INVSQ2] -y_minus = [INVSQ2, -1j * INVSQ2] - - -class TestExpvalBroadcasted: - """Tests that expectation values are properly calculated for broadcasted states - or that the proper errors are raised.""" - - @pytest.mark.parametrize( - "operation,input,expected_output", - [ - (qml.PauliX, np.array([plus, zero, minus]), [1, 0, -1]), - (qml.PauliY, np.array([y_plus, zero, y_minus]), [1, 0, -1]), - (qml.PauliZ, np.array([plus, zero, one]), [0, 1, -1]), - (qml.Hadamard, np.array([plus, zero, one]), [INVSQ2, INVSQ2, -INVSQ2]), - (qml.Identity, np.array([minus, zero, one]), [1, 1, 1]), - ], - ) - def test_expval_single_wire_no_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that expectation values are properly calculated for single-wire observables without parameters.""" - - obs = operation(wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.expval(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [(qml.Hermitian, [zero, one, minus, y_plus], [1, 1, 1, 0], I - Y)], - ) - def test_expval_single_wire_with_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that expectation values are properly calculated for single-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.expval(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - ( - qml.Hermitian, - [ - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [0, 0, 0, 1], - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - ], - [4 / 3, 0, 1], - [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 0]], - ), - ( - qml.Hermitian, - [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], - [1, -1], - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ], - ) - def test_expval_two_wires_with_parameters_broadcasted( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that expectation values are properly calculated for two-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0, 1]) - - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() - ) - res = qubit_device_2_wires.expval(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - def test_expval_estimate_broadcasted(self): - """Test that the expectation value is not analytically calculated""" - - dev = qml.device("default.qubit", wires=1, shots=3) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(np.zeros(5), wires=0) # Broadcast the tape without applying an op - return qml.expval(qml.PauliX(0)) - - expval = circuit() - - # With 3 samples we are guaranteed to see a difference between - # an estimated variance an an analytically calculated one - assert np.all(expval != 0.0) - - -class TestVarBroadcasted: - """Tests that variances are properly calculated for broadcasted states.""" - - @pytest.mark.parametrize( - "operation,input,expected_output", - [ - (qml.PauliX, [plus, zero, minus], [0, 1, 0]), - (qml.PauliY, [y_plus, zero, y_minus], [0, 1, 0]), - (qml.PauliZ, [plus, zero, one], [1, 0, 0]), - (qml.Hadamard, [plus, zero, one], [0.5, 0.5, 0.5]), - (qml.Identity, [minus, zero, one], [0, 0, 0]), - ], - ) - def test_var_single_wire_no_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output - ): - """Tests that variances are properly calculated for single-wire observables without parameters.""" - - obs = operation(wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.var(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [(qml.Hermitian, [zero, one, minus, y_plus], [1, 1, 1, 0], I - Y)], - ) - def test_var_single_wire_with_parameters_broadcasted( - self, qubit_device_1_wire, tol, operation, input, expected_output, par - ): - """Tests that variances are properly calculated for single-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0]) - - qubit_device_1_wire.reset() - qubit_device_1_wire.apply( - [qml.QubitStateVector(np.array(input), wires=[0])], obs.diagonalizing_gates() - ) - res = qubit_device_1_wire.var(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "operation,input,expected_output,par", - [ - ( - qml.Hermitian, - [ - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [0, 0, 0, 1], - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - ], - [11 / 9, 2, 3 / 2], - [[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 1]], - ), - ( - qml.Hermitian, - [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], - [0, 0], - [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], - ), - ], - ) - def test_var_two_wires_with_parameters_broadcasted( - self, qubit_device_2_wires, tol, operation, input, expected_output, par - ): - """Tests that variances are properly calculated for two-wire observables with parameters.""" - - obs = operation(np.array(par), wires=[0, 1]) - - qubit_device_2_wires.reset() - qubit_device_2_wires.apply( - [qml.QubitStateVector(np.array(input), wires=[0, 1])], obs.diagonalizing_gates() - ) - res = qubit_device_2_wires.var(obs) - - assert np.allclose(res, expected_output, atol=tol, rtol=0) - - def test_var_estimate_broadcasted(self): - """Test that the variance is not analytically calculated""" - - dev = qml.device("default.qubit", wires=1, shots=3) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(np.zeros(5), wires=0) # Broadcast the tape without applying an op - return qml.var(qml.PauliX(0)) - - var = circuit() - - # With 3 samples we are guaranteed to see a difference between - # an estimated variance and an analytically calculated one - assert np.all(var != 1.0) - - -class TestSampleBroadcasted: - """Tests that samples are properly calculated for broadcasted states.""" - - def test_sample_dimensions_broadcasted(self): - """Tests if the samples returned by the sample function have - the correct dimensions - """ - - # Explicitly resetting is necessary as the internal - # state is set to None in __init__ and only properly - # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) - - dev.apply([qml.RX(np.array([np.pi / 2, 0.0]), 0), qml.RX(np.array([np.pi / 2, 0.0]), 1)]) - - dev.shots = 10 - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - s1 = dev.sample(qml.PauliZ(0)) - assert s1.shape == ( - 2, - 10, - ) - - dev.reset() - dev.shots = 12 - dev._wires_measured = {1} - dev._samples = dev.generate_samples() - s2 = dev.sample(qml.PauliZ(wires=[1])) - assert s2.shape == (12,) - - dev.reset() - dev.apply([qml.RX(np.ones(5), 0), qml.RX(np.ones(5), 1)]) - dev.shots = 17 - dev._wires_measured = {0, 1} - dev._samples = dev.generate_samples() - s3 = dev.sample(qml.PauliX(0) @ qml.PauliZ(1)) - assert s3.shape == (5, 17) - - def test_sample_values_broadcasted(self, tol): - """Tests if the samples returned by sample have - the correct values - """ - - # Explicitly resetting is necessary as the internal - # state is set to None in __init__ and only properly - # initialized during reset - dev = qml.device("default.qubit", wires=2, shots=1000) - - dev.apply([qml.RX(np.ones(3), wires=[0])]) - dev._wires_measured = {0} - dev._samples = dev.generate_samples() - - s1 = dev.sample(qml.PauliZ(0)) - - # s1 should only contain 1 and -1, which is guaranteed if - # they square to 1 - assert np.allclose(s1**2, 1, atol=tol, rtol=0) - - -class TestDefaultQubitIntegrationBroadcasted: - """Integration tests for default.qubit. This test ensures it integrates - properly with the PennyLane interface, in particular QNode.""" - - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - def test_qubit_circuit_broadcasted(self, qubit_device_1_wire, r_dtype, tol): - """Test that the default qubit plugin provides correct result for a simple circuit""" - - p = np.array([0.543, np.pi / 2, 0.0, 1.0]) - - dev = qubit_device_1_wire - dev.R_DTYPE = r_dtype - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -np.sin(p) - - res = circuit(p) - assert np.allclose(res, expected, atol=tol, rtol=0) - assert res.dtype == r_dtype - - def test_qubit_identity_broadcasted(self, qubit_device_1_wire, tol): - """Test that the default qubit plugin provides correct result for the Identity expectation""" - - p = np.array([0.543, np.pi / 2, 0.0, 1.0]) - - @qml.qnode(qubit_device_1_wire) - def circuit(x): - """Test quantum function""" - qml.RX(x, wires=0) - return qml.expval(qml.Identity(0)) - - assert np.allclose(circuit(p), 1, atol=tol, rtol=0) - - def test_nonzero_shots_broadcasted(self, tol): - """Test that the default qubit plugin provides correct result for high shot number""" - - shots = 10**5 - dev = qml.device("default.qubit", wires=1, shots=shots) - - p = np.array([0.543, np.pi / 2, 0.0, 1.0]) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - """Test quantum function""" - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - runs = [] - for _ in range(100): - runs.append(circuit(p)) - - assert np.allclose(np.mean(runs, axis=0), -np.sin(p), atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output", - [ - ("PauliX", [plus, minus, zero], [1, -1, 0]), - ("PauliY", [y_plus, y_minus, zero], [1, -1, 0]), - ("PauliZ", [plus, one, zero], [0, -1, 1]), - ("Hadamard", [plus, one, zero], [INVSQ2, -INVSQ2, INVSQ2]), - ], - ) - def test_supported_observable_single_wire_no_parameters_broadcasted( - self, qubit_device_1_wire, tol, name, state, expected_output - ): - """Tests supported observables on single wires without parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_1_wire.supports_observable(name) - - @qml.qnode(qubit_device_1_wire) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0]) - return qml.expval(obs(wires=[0])) - - assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output,par", - [ - ("Identity", [zero, one, plus], [1, 1, 1], []), - ("Hermitian", [zero, one, minus], [1, 1, 1], [I - Y]), - ], - ) - def test_supported_observable_single_wire_with_parameters_broadcasted( - self, qubit_device_1_wire, tol, name, state, expected_output, par - ): - """Tests supported observables on single wires with parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_1_wire.supports_observable(name) - - @qml.qnode(qubit_device_1_wire) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0]) - return qml.expval(obs(*par, wires=[0])) - - assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "name,state,expected_output,par", - [ - ( - "Hermitian", - [ - [1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)], - [0, 0, 0, 1], - [1 / math.sqrt(2), 0, -1 / math.sqrt(2), 0], - ], - [4 / 3, 0, 1], - ([[1, 1j, 0, 1], [-1j, 1, 0, 0], [0, 0, 1, -1j], [1, 0, 1j, 0]],), - ), - ( - "Hermitian", - [[INVSQ2, 0, 0, INVSQ2], [0, INVSQ2, -INVSQ2, 0]], - [1, -1], - ([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]],), - ), - ], - ) - def test_supported_observable_two_wires_with_parameters_broadcasted( - self, qubit_device_2_wires, tol, name, state, expected_output, par - ): - """Tests supported observables on two wires with parameters.""" - - obs = getattr(qml.ops, name) - - assert qubit_device_2_wires.supports_observable(name) - - @qml.qnode(qubit_device_2_wires) - def circuit(): - qml.QubitStateVector(np.array(state), wires=[0, 1]) - return qml.expval(obs(*par, wires=[0, 1])) - - assert np.allclose(circuit(), expected_output, atol=tol, rtol=0) - - def test_multi_samples_return_correlated_results_broadcasted(self): - """Tests if the samples returned by the sample function are correlated - correctly for correlated observables. - """ - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.Hadamard(0) - qml.RX(np.zeros(5), 0) - qml.CNOT(wires=[0, 1]) - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) - - outcomes = circuit() - - assert np.array_equal(outcomes[0], outcomes[1]) - - @pytest.mark.parametrize("num_wires", [3, 4, 5, 6, 7, 8]) - def test_multi_samples_correlated_results_more_wires_than_observable_broadcasted( - self, num_wires - ): - """Tests if the samples returned by the sample function are correlated - correctly for correlated observables on larger devices than the observables - """ - - dev = qml.device("default.qubit", wires=num_wires, shots=1000) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.Hadamard(0) - qml.RX(np.zeros(5), 0) - qml.CNOT(wires=[0, 1]) - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)) - - outcomes = circuit() - - assert np.array_equal(outcomes[0], outcomes[1]) - - -# pylint: disable=unused-argument -@pytest.mark.parametrize( - "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] -) -class TestTensorExpvalBroadcasted: - """Test tensor expectation values for broadcasted states""" - - def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) - dev.reset() - - A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.5 * ( - -6 * np.cos(theta) * (np.cos(varphi) + 1) - - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) - + 3 * np.cos(varphi) * np.sin(phi) - + np.sin(phi) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit", wires=3) - - A1 = np.array([[1, 2], [2, 4]]) - - A2 = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.25 * ( - -30 - + 4 * np.cos(phi) * np.sin(theta) - + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) - - 3 * np.sin(phi) - - 2 - * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) - * np.sin(varphi) - + np.cos(theta) - * ( - 18 - + 5 * np.sin(phi) - + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) - + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) - ) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit", wires=2) - - A = np.array( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] - ) - - obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_two_wires_identity_expectation_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit", wires=3) - - A = np.array( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] - ) - Identity = np.array([[1, 0], [0, 1]]) - Ham = np.kron(np.kron(Identity, Identity), A) - obs = qml.Hermitian(Ham, wires=[2, 1, 0]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.parametrize( - "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] -) -class TestTensorVarBroadcasted: - """Tests for variance of tensor observables for broadcasted states""" - - def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_broadcasted(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3) - - A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 1057 - - np.cos(2 * phi) - + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) - - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) - + 16 * np.sin(2 * phi) - - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) - - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 - - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) - - 8 - * np.cos(theta) - * ( - 4 - * np.cos(phi) - * ( - 4 - + 8 * np.cos(varphi) - + np.cos(2 * varphi) - - (1 + 6 * np.cos(varphi)) * np.sin(varphi) - ) - + np.sin(phi) - * ( - 15 - + 8 * np.cos(varphi) - - 11 * np.cos(2 * varphi) - + 42 * np.sin(varphi) - + 3 * np.sin(2 * varphi) - ) - ) - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.parametrize( - "theta,phi,varphi", [(THETA, PHI, VARPHI), (THETA, PHI[0], VARPHI), (THETA[0], PHI, VARPHI[1])] -) -class TestTensorSampleBroadcasted: - """Test tensor sampling for broadcated states""" - - def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.probability(wires=dev.map_wires(obs.wires)) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - - mean = p @ s1 - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = p @ (s1**2) - (p @ s1).real ** 2 - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain 1 and -1 - assert np.allclose(s1**2, 1, atol=tol_stochastic, rtol=0) - - mean = p @ s1 - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = p @ (s1**2) - (p @ s1).real ** 2 - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - def test_hermitian_broadcasted(self, theta, phi, varphi, tol_stochastic): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit", wires=3, shots=int(1e6)) - - A = 0.1 * np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - dev._wires_measured = {0, 1, 2} - dev._samples = dev.generate_samples() - dev.sample(obs) - - s1 = obs.eigvals() - p = dev.marginal_prob(dev.probability(), wires=obs.wires) - - # s1 should only contain the eigenvalues of - # the hermitian matrix tensor product Z - z = np.diag([1, -1]) - eigvals = np.linalg.eigvalsh(np.kron(z, A)) - assert set(np.round(s1, 8).tolist()).issubset(set(np.round(eigvals, 8).tolist())) - - mean = p @ s1 - expected = ( - 0.1 - * 0.5 - * ( - -6 * np.cos(theta) * (np.cos(varphi) + 1) - - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) - + 3 * np.cos(varphi) * np.sin(phi) - + np.sin(phi) - ) - ) - assert np.allclose(mean, expected, atol=tol_stochastic, rtol=0) - - var = p @ (s1**2) - (p @ s1).real ** 2 - expected = ( - 0.01 - * ( - 1057 - - np.cos(2 * phi) - + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) - - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) - + 16 * np.sin(2 * phi) - - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) - - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 - - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) - - 8 - * np.cos(theta) - * ( - 4 - * np.cos(phi) - * ( - 4 - + 8 * np.cos(varphi) - + np.cos(2 * varphi) - - (1 + 6 * np.cos(varphi)) * np.sin(varphi) - ) - + np.sin(phi) - * ( - 15 - + 8 * np.cos(varphi) - - 11 * np.cos(2 * varphi) - + 42 * np.sin(varphi) - + 3 * np.sin(2 * varphi) - ) - ) - ) - / 16 - ) - assert np.allclose(var, expected, atol=tol_stochastic, rtol=0) - - -@pytest.mark.parametrize( - "r_dtype,c_dtype", [(np.float32, np.complex64), (np.float64, np.complex128)] -) -class TestDtypePreservedBroadcasted: - """Test that the user-defined dtype of the device is preserved for QNode - evaluation""" - - @pytest.mark.parametrize( - "op", - [ - qml.SingleExcitation, - qml.SingleExcitationPlus, - qml.SingleExcitationMinus, - qml.DoubleExcitation, - qml.DoubleExcitationPlus, - qml.DoubleExcitationMinus, - qml.OrbitalRotation, - qml.FermionicSWAP, - qml.QubitSum, - qml.QubitCarry, - ], - ) - def test_state_dtype_after_op_broadcasted(self, r_dtype, c_dtype, op): - """Test that the default qubit plugin preserves data types of states when an operation is - applied. As TestApply class check most of operators, we here only check some subtle - examples. - """ - - dev = qml.device("default.qubit", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) - - n_wires = op.num_wires - n_params = op.num_params - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - x = np.array([0.543, 0.622, 1.3]) - if n_params == 0: - op(wires=range(n_wires)) - elif n_params == 1: - op(x, wires=range(n_wires)) - else: - op([x] * n_params, wires=range(n_wires)) - return qml.state() - - res = circuit() - assert res.dtype == c_dtype - - @pytest.mark.parametrize( - "measurement", - [ - qml.expval(qml.PauliY(0)), - qml.var(qml.PauliY(0)), - qml.probs(wires=[1]), - qml.probs(wires=[2, 0]), - ], - ) - def test_measurement_real_dtype_broadcasted(self, r_dtype, c_dtype, measurement): - """Test that the default qubit plugin provides correct result for a simple circuit""" - p = np.array([0.543, 0.622, 1.3]) - - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(measurement) - - res = circuit(p) - assert res.dtype == r_dtype - - def test_measurement_complex_dtype_broadcasted(self, r_dtype, c_dtype): - """Test that the default qubit plugin provides correct result for a simple circuit""" - p = np.array([0.543, 0.622, 1.3]) - m = qml.state() - - dev = qml.device("default.qubit", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.apply(m) - - res = circuit(p) - assert res.dtype == c_dtype - - -class TestProbabilityIntegrationBroadcasted: - """Test probability method for when analytic is True/False""" - - # pylint: disable=no-member, unused-argument - def mock_analytic_counter(self, wires=None): - self.analytic_counter += 1 - return np.array([1, 0, 0, 0], dtype=float) - - def test_probability_broadcasted(self, tol): - """Test that the probability function works for finite and infinite shots""" - dev = qml.device("default.qubit", wires=2, shots=1000) - dev_analytic = qml.device("default.qubit", wires=2, shots=None) - - x = np.array([[0.2, 0.5, 0.4], [0.9, 0.8, 0.3]]) - - def circuit(x): - qml.RX(x[0], wires=0) - qml.RY(x[1], wires=0) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[0, 1]) - - prob = qml.QNode(circuit, dev) - prob_analytic = qml.QNode(circuit, dev_analytic) - - assert np.allclose(prob(x).sum(axis=-1), 1, atol=tol, rtol=0) - assert np.allclose(prob_analytic(x), prob(x), atol=0.1, rtol=0) - assert not np.array_equal(prob_analytic(x), prob(x)) - - -class TestWiresIntegrationBroadcasted: - """Test that the device integrates with PennyLane's wire management.""" - - def make_circuit_probs(self, wires): - """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = qml.device("default.qubit", wires=wires) - n_wires = len(wires) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(np.array([0.5, 1.2, -0.6]), wires=wires[0 % n_wires]) - qml.RY(np.array([2.0, 0.4, 1.2]), wires=wires[1 % n_wires]) - if n_wires > 1: - qml.CNOT(wires=[wires[0], wires[1]]) - return qml.probs(wires=wires) - - return circuit - - @pytest.mark.parametrize( - "wires1, wires2", - [ - (["a", "c", "d"], [2, 3, 0]), - ([-1, -2, -3], ["q1", "ancilla", 2]), - (["a", "c"], [3, 0]), - ([-1, -2], ["ancilla", 2]), - (["a"], ["nothing"]), - ], - ) - def test_wires_probs_broadcasted(self, wires1, wires2, tol): - """Test that the probability vector of a circuit is independent from the wire labels used.""" - - circuit1 = self.make_circuit_probs(wires1) - circuit2 = self.make_circuit_probs(wires2) - - assert np.allclose(circuit1(), circuit2(), tol) - - -class TestApplyOpsBroadcasted: - """Tests for special methods listed in _apply_ops that use array manipulation tricks to apply - gates in DefaultQubit.""" - - broadcasted_state = np.arange(2**4 * 3, dtype=np.complex128).reshape((3, 2, 2, 2, 2)) - dev = qml.device("default.qubit", wires=4) - - single_qubit_ops = [ - (qml.PauliX, dev._apply_x), - (qml.PauliY, dev._apply_y), - (qml.PauliZ, dev._apply_z), - (qml.Hadamard, dev._apply_hadamard), - (qml.S, dev._apply_s), - (qml.T, dev._apply_t), - (qml.SX, dev._apply_sx), - ] - two_qubit_ops = [ - (qml.CNOT, dev._apply_cnot), - (qml.SWAP, dev._apply_swap), - (qml.CZ, dev._apply_cz), - ] - three_qubit_ops = [ - (qml.Toffoli, dev._apply_toffoli), - ] - - @pytest.mark.parametrize("op, method", single_qubit_ops) - def test_apply_single_qubit_op_broadcasted_state(self, op, method): - """Test if the application of single qubit operations to a - broadcasted state is correct.""" - state_out = method(self.broadcasted_state, axes=[2]) - op = op(wires=[1]) - matrix = op.matrix() - state_out_einsum = np.einsum("ab,mibjk->miajk", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", two_qubit_ops) - def test_apply_two_qubit_op_broadcasted_state(self, op, method): - """Test if the application of two qubit operations to a - broadcasted state is correct.""" - state_out = method(self.broadcasted_state, axes=[1, 2]) - op = op(wires=[0, 1]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2, 2, 2)) - state_out_einsum = np.einsum("abcd,mcdjk->mabjk", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", two_qubit_ops) - def test_apply_two_qubit_op_reverse_broadcasted_state(self, op, method): - """Test if the application of two qubit operations to a - broadcasted state is correct when the applied wires are reversed.""" - state_out = method(self.broadcasted_state, axes=[3, 2]) - op = op(wires=[2, 1]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2, 2, 2)) - state_out_einsum = np.einsum("abcd,midck->mibak", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_smaller_broadcasted_state(self, op, method): - """Test if the application of three qubit operations to a broadcasted - state is correct when both control wires are smaller than the target wire.""" - state_out = method(self.broadcasted_state, axes=[1, 3, 4]) - op = op(wires=[0, 2, 3]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,mdkef->makbc", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_greater_broadcasted_state(self, op, method): - """Test if the application of three qubit operations to a broadcasted - state is correct when both control wires are greater than the target wire.""" - state_out = method(self.broadcasted_state, axes=[3, 2, 1]) - op = op(wires=[2, 1, 0]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,mfedk->mcbak", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - @pytest.mark.parametrize("op, method", three_qubit_ops) - def test_apply_three_qubit_op_controls_split_broadcasted_state(self, op, method): - """Test if the application of three qubit operations to a broadcasted state is correct - when one control wire is smaller and one control wire is greater than the target wire.""" - state_out = method(self.broadcasted_state, axes=[4, 2, 3]) - op = op(wires=[3, 1, 2]) - matrix = op.matrix() - matrix = matrix.reshape((2, 2) * 3) - state_out_einsum = np.einsum("abcdef,mkdfe->mkacb", matrix, self.broadcasted_state) - assert np.allclose(state_out, state_out_einsum) - - -class TestStateVectorBroadcasted: - """Unit tests for the _apply_state_vector method with broadcasting""" - - def test_full_subsystem_broadcasted(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubit(wires=["a", "b", "c"]) - state = np.array([[0, 1, 1, 0, 1, 1, 0, 0], [1, 0, 0, 0, 1, 0, 1, 1]]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(dev._state.reshape((2, 8)) == state) - spy.assert_not_called() - - def test_partial_subsystem_broadcasted(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubit(wires=["a", "b", "c"]) - state = np.array([[0, 1, 1, 0], [1, 0, 1, 0], [1, 1, 0, 0]]) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - # Axes are (broadcasting, wire "a", wire "b", wire "c"), so we sum over axis=2 - res = np.sum(dev._state, axis=(2,)).reshape((3, 4)) - - assert np.all(res == state) - spy.assert_called() - - -class TestApplyOperationBroadcasted: - """Unit tests for the internal _apply_operation method.""" - - def test_internal_apply_ops_case_broadcasted(self, monkeypatch): - """Tests that if we provide an operation that has an internal - implementation, then we use that specific implementation. - - This test provides a new internal function that `default.qubit` uses to - apply `PauliX` (rather than redefining the gate itself). - """ - dev = qml.device("default.qubit", wires=1) - - test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - # Create a dummy operation - expected_test_output = np.ones(1) - supported_gate_application = lambda *args, **kwargs: expected_test_output - - with monkeypatch.context() as m: - # Set the internal ops implementations dict - m.setattr(dev, "_apply_ops", {"PauliX": supported_gate_application}) - - op = qml.PauliX(0) - - res = dev._apply_operation(test_state, op) - assert np.allclose(res, expected_test_output) - - def test_diagonal_operation_case_broadcasted(self, monkeypatch): - """Tests the case when the operation to be applied is - diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = qml.device("default.qubit", wires=1) - par = 0.3 - - test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - wires = 0 - op = qml.PhaseShift(par, wires=wires) - assert op.name not in dev._apply_ops - - # Set the internal _apply_diagonal_unitary - history = [] - mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) - with monkeypatch.context() as m: - m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) - assert dev._apply_diagonal_unitary == mock_apply_diag - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, np.diag(op.matrix())) - assert np.allclose(res_wires, wires) - - def test_apply_einsum_case_broadcasted(self, monkeypatch): - """Tests the case when np.einsum is used to apply an operation in - default.qubit.""" - dev = qml.device("default.qubit", wires=1) - - test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - wires = 0 - - # Redefine the S gate so that it is an example for a one-qubit gate - # that is not registered in the diagonal_in_z_basis attribute - # pylint: disable=too-few-public-methods - class TestSGate(qml.operation.Operation): - num_wires = 1 - - # pylint: disable=unused-argument - @staticmethod - def compute_matrix(*params, **hyperparams): - return np.array([[1, 0], [0, 1j]]) - - dev.operations.add("TestSGate") - op = TestSGate(wires=wires) - - assert op.name in dev.operations - assert op.name not in dev._apply_ops - - # Set the internal _apply_unitary_einsum - history = [] - mock_apply_einsum = lambda state, matrix, wires: history.append((state, matrix, wires)) - with monkeypatch.context() as m: - m.setattr(dev, "_apply_unitary_einsum", mock_apply_einsum) - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, op.matrix()) - assert np.allclose(res_wires, wires) - - def test_apply_tensordot_case_broadcasted(self, monkeypatch): - """Tests the case when np.tensordot is used to apply an operation in - default.qubit.""" - dev = qml.device("default.qubit", wires=3) - - test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - wires = [0, 1, 2] - - # Redefine the Toffoli gate so that it is an example for a gate with - # more than two wires - # pylint: disable=too-few-public-methods - class TestToffoli(qml.operation.Operation): - num_wires = 3 - - # pylint: disable=unused-argument - @staticmethod - def compute_matrix(*params, **hyperparams): - return Toffoli - - dev.operations.add("TestToffoli") - op = TestToffoli(wires=wires) - - assert op.name in dev.operations - assert op.name not in dev._apply_ops - - # Set the internal _apply_unitary_tensordot - history = [] - mock_apply_tensordot = lambda state, matrix, wires: history.append((state, matrix, wires)) - - with monkeypatch.context() as m: - m.setattr(dev, "_apply_unitary", mock_apply_tensordot) - - dev._apply_operation(test_state, op) - - res_state, res_mat, res_wires = history[0] - - assert np.allclose(res_state, test_state) - assert np.allclose(res_mat, op.matrix()) - assert np.allclose(res_wires, wires) - - def test_identity_skipped_broadcasted(self, mocker): - """Test that applying the identity operation does not perform any additional computations.""" - dev = qml.device("default.qubit", wires=1) - - starting_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) - op = qml.Identity(0) - - spy_diagonal = mocker.spy(dev, "_apply_diagonal_unitary") - spy_einsum = mocker.spy(dev, "_apply_unitary_einsum") - spy_unitary = mocker.spy(dev, "_apply_unitary") - - res = dev._apply_operation(starting_state, op) - assert res is starting_state - - spy_diagonal.assert_not_called() - spy_einsum.assert_not_called() - spy_unitary.assert_not_called() - - -class TestHamiltonianSupportBroadcasted: - """Tests the devices' native support for Hamiltonian observables.""" - - def test_do_not_split_analytic_broadcasted(self, mocker): - """Tests that the Hamiltonian is not split for shots=None.""" - dev = qml.device("default.qubit", wires=2) - Ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="parameter-shift", interface=None) - def circuit(): - qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity - return qml.expval(Ham) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_split_finite_shots_broadcasted(self, mocker): - """Tests that the Hamiltonian is split for finite shots.""" - dev = qml.device("default.qubit", wires=2, shots=10) - spy = mocker.spy(dev, "expval") - - ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev) - def circuit(): - qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity - return qml.expval(ham) - - circuit() - - # evaluated one expval per Pauli observable - assert spy.call_count == 2 - - -original_capabilities = qml.devices.DefaultQubit.capabilities() - - -@pytest.fixture(scope="function", name="mock_default_qubit") -def mock_default_qubit_fixture(monkeypatch): - """A function to create a mock device that mocks the broadcasting support flag - to be False, so that default support via broadcast_expand transform can be tested""" - - # pylint: disable=unused-argument - def overwrite_support(*cls): - capabilities = original_capabilities.copy() - capabilities.update(supports_broadcasting=False) - return capabilities - - with monkeypatch.context() as m: - m.setattr(qml.devices.DefaultQubit, "capabilities", overwrite_support) - - def get_default_qubit(wires=1, shots=None): - dev = qml.devices.DefaultQubit(wires=wires, shots=shots) - return dev - - yield get_default_qubit - - -@pytest.mark.parametrize("shots", [None, 100000]) -class TestBroadcastingSupportViaExpansion: - """Tests that the device correctly makes use of ``broadcast_expand`` to - execute broadcasted tapes if its capability to execute broadcasted tapes - is artificially deactivated.""" - - @pytest.mark.parametrize("x", [0.2, np.array([0.1, 0.6, 0.3]), np.array([0.1])]) - def test_with_single_broadcasted_par(self, x, shots, mock_default_qubit): - """Test that broadcasting on a circuit with a - single parametrized operation works.""" - dev = mock_default_qubit(wires=2, shots=shots) - - @qml.qnode(dev) - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit.construct((np.array(x),), {}) - out = circuit(np.array(x)) - - assert circuit.device.num_executions == (1 if isinstance(x, float) else len(x)) - tol = 1e-10 if shots is None else 1e-2 - assert qml.math.allclose(out, qml.math.cos(x), atol=tol, rtol=0) - - @pytest.mark.parametrize( - "x, y", [(0.2, np.array([0.4])), (np.array([0.1, 5.1]), np.array([0.1, -0.3]))] - ) - def test_with_multiple_pars(self, x, y, shots, mock_default_qubit): - """Test that broadcasting on a circuit with a - single parametrized operation works.""" - dev = mock_default_qubit(wires=2, shots=shots) - - @qml.qnode(dev) - def circuit(x, y): - qml.RX(x, wires=0) - qml.RX(y, wires=1) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1)) - - out = circuit(x, y) - expected = qml.math.stack([qml.math.cos(x) * qml.math.ones_like(y), -qml.math.sin(y)]) - - assert circuit.device.num_executions == len(y) - tol = 1e-10 if shots is None else 1e-2 - - assert qml.math.allclose(out[0], expected[0], atol=tol, rtol=0) - assert qml.math.allclose(out[1], expected[1], atol=tol, rtol=0) - - @pytest.mark.parametrize( - "x, y", [(0.2, np.array([0.4])), (np.array([0.1, 5.1]), np.array([0.1, -0.3]))] - ) - def test_with_Hamiltonian(self, x, y, shots, mock_default_qubit): - """Test that broadcasting on a circuit with a - single parametrized operation works.""" - dev = mock_default_qubit(wires=2, shots=shots) - - Ham = qml.Hamiltonian([0.3, 0.9], [qml.PauliZ(0), qml.PauliY(1)]) - Ham.compute_grouping() - - @qml.qnode(dev) - def circuit(x, y): - qml.RX(x, wires=0) - qml.RX(y, wires=1) - return qml.expval(Ham) - - out = circuit(x, y) - expected = 0.3 * qml.math.cos(x) * qml.math.ones_like(y) - 0.9 * qml.math.sin(y) - - assert circuit.device.num_executions == len(y) - tol = 1e-10 if shots is None else 1e-2 - assert qml.math.allclose(out, expected, atol=tol, rtol=0) diff --git a/tests/devices/test_default_qubit_jax.py b/tests/devices/test_default_qubit_jax.py deleted file mode 100644 index ea08c1a1ece..00000000000 --- a/tests/devices/test_default_qubit_jax.py +++ /dev/null @@ -1,1311 +0,0 @@ -# Copyright 2018-2021 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. -""" -Integration tests for the ``default.qubit.jax`` device. -""" -import pytest -import numpy as np - -import pennylane as qml -from pennylane import DeviceError -from pennylane.pulse import ParametrizedHamiltonian - -jax = pytest.importorskip("jax", minversion="0.2") -from pennylane.devices.default_qubit_jax import ( # pylint: disable=wrong-import-position - DefaultQubitJax, -) - -jnp = jax.numpy - - -@pytest.mark.jax -def test_analytic_deprecation(): - """Tests if the kwarg `analytic` is used and displays error message.""" - msg = "The analytic argument has been replaced by shots=None. " - msg += "Please use shots=None instead of analytic=True." - - with pytest.raises( - DeviceError, - match=msg, - ): - qml.device("default.qubit.jax", wires=1, shots=1, analytic=True) - - -# pylint: disable=too-many-public-methods -@pytest.mark.jax -class TestQNodeIntegration: - """Integration tests for default.qubit.jax. This test ensures it integrates - properly with the PennyLane UI, in particular the new QNode.""" - - def test_defines_correct_capabilities(self): - """Test that the device defines the right capabilities""" - - dev = qml.device("default.qubit.jax", wires=1) - cap = dev.capabilities() - capabilities = { - "model": "qubit", - "supports_finite_shots": True, - "supports_tensor_observables": True, - "returns_probs": True, - "returns_state": True, - "supports_inverse_operations": True, - "supports_analytic_computation": True, - "supports_broadcasting": True, - "passthru_interface": "jax", - "passthru_devices": { - "torch": "default.qubit.torch", - "tf": "default.qubit.tf", - "autograd": "default.qubit.autograd", - "jax": "default.qubit.jax", - }, - } - assert cap == capabilities - - def test_defines_correct_capabilities_directly_from_class(self): - """Test that the device defines the right capabilities""" - - dev = DefaultQubitJax(wires=1) - cap = dev.capabilities() - assert cap["passthru_interface"] == "jax" - - def test_load_device(self): - """Test that the plugin device loads correctly""" - dev = qml.device("default.qubit.jax", wires=2) - assert dev.num_wires == 2 - assert dev.shots is None - assert dev.short_name == "default.qubit.jax" - assert dev.capabilities()["passthru_interface"] == "jax" - - @pytest.mark.parametrize( - "jax_enable_x64, c_dtype, r_dtype", - ([True, np.complex128, np.float64], [False, np.complex64, np.float32]), - ) - def test_float_precision(self, jax_enable_x64, c_dtype, r_dtype): - """Test that the plugin device uses the same float precision as the jax config.""" - jax.config.update("jax_enable_x64", jax_enable_x64) - dev = qml.device("default.qubit.jax", wires=2) - assert dev.state.dtype == c_dtype - assert dev.state.real.dtype == r_dtype - - def test_qubit_circuit(self, tol): - """Test that the device provides the correct - result for a simple circuit.""" - p = jnp.array(0.543) - - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -jnp.sin(p) - assert jnp.isclose(circuit(p), expected, atol=tol, rtol=0) - - def test_qubit_circuit_with_jit(self, tol): - """Test that the device provides the correct - result for a simple circuit under a jax.jit.""" - p = jnp.array(0.543) - - dev = qml.device("default.qubit.jax", wires=1) - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -jnp.sin(p) - # Do not test isinstance here since the @jax.jit changes the function - # type. Just test that it works and spits our the right value. - assert jnp.isclose(circuit(p), expected, atol=tol, rtol=0) - - # Test with broadcasted parameters - p = jnp.array([0.543, 0.21, 1.5]) - expected = -jnp.sin(p) - assert jnp.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_qubit_circuit_broadcasted(self, tol): - """Test that the device provides the correct - result for a simple broadcasted circuit.""" - p = jnp.array([0.543, 0.21, 1.5]) - - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -jnp.sin(p) - - assert jnp.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_correct_state(self, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - - dev = qml.device("default.qubit.jax", wires=2) - - state = dev.state - expected = jnp.array([1, 0, 0, 0]) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(jnp.pi / 4, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - amplitude = jnp.exp(-1j * jnp.pi / 8) / jnp.sqrt(2) - - expected = jnp.array([amplitude, 0, jnp.conj(amplitude), 0]) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_broadcasted(self, tol): - """Test that the device state is correct after applying a - broadcasted quantum function on the device""" - - dev = qml.device("default.qubit.jax", wires=2) - - state = dev.state - expected = jnp.array([1, 0, 0, 0]) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(jnp.array([np.pi / 4, np.pi / 2]), wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - phase = jnp.exp(-1j * jnp.pi / 8) - - expected = np.array( - [ - [phase / jnp.sqrt(2), 0, jnp.conj(phase) / jnp.sqrt(2), 0], - [phase**2 / jnp.sqrt(2), 0, jnp.conj(phase) ** 2 / jnp.sqrt(2), 0], - ] - ) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_returned(self, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(jnp.pi / 4, wires=0) - return qml.state() - - state = circuit() - - amplitude = jnp.exp(-1j * jnp.pi / 8) / jnp.sqrt(2) - - expected = jnp.array([amplitude, 0, jnp.conj(amplitude), 0]) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_returned_broadcasted(self, tol): - """Test that the device state is correct after applying a - broadcasted quantum function on the device""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(jnp.array([np.pi / 4, np.pi / 2]), wires=0) - return qml.state() - - state = circuit() - - phase = jnp.exp(-1j * jnp.pi / 8) - - expected = np.array( - [ - [phase / jnp.sqrt(2), 0, jnp.conj(phase) / jnp.sqrt(2), 0], - [phase**2 / jnp.sqrt(2), 0, jnp.conj(phase) ** 2 / jnp.sqrt(2), 0], - ] - ) - assert jnp.allclose(state, expected, atol=tol, rtol=0) - - def test_probs_jax(self, tol): - """Test that returning probs works with jax""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) - expected = jnp.array([0.0, 1.0]) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.PauliX(wires=0) - return qml.probs(wires=0) - - result = circuit() - assert jnp.allclose(result, expected, atol=tol) - - def test_probs_jax_broadcasted(self, tol): - """Test that returning probs works with jax""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) - expected = jnp.array([[0.0, 1.0]] * 3) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.RX(jnp.zeros(3), 0) - qml.PauliX(wires=0) - return qml.probs(wires=0) - - result = circuit() - assert jnp.allclose(result, expected, atol=tol) - - def test_probs_jax_jit(self, tol): - """Test that returning probs works with jax and jit""" - dev = qml.device("default.qubit.jax", wires=1, shots=100) - expected = jnp.array([0.0, 1.0]) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(z): - qml.RX(z, wires=0) - qml.PauliX(wires=0) - return qml.probs(wires=0) - - result = circuit(0.0) - assert jnp.allclose(result, expected, atol=tol) - - # Test with broadcasting - result = circuit(jnp.zeros(3)) - expected = jnp.array([[0.0, 1.0]] * 3) - assert jnp.allclose(result, expected, atol=tol) - - def test_custom_shots_probs_jax_jit(self, tol): - """Test that returning probs works with jax and jit when using custom shot vector""" - dev = qml.device("default.qubit.jax", wires=1, shots=(3, 2)) - expected = jnp.array([[0.0, 1.0], [0.0, 1.0]]) - - @jax.jit - @qml.qnode(dev, diff_method=None, interface="jax") - def circuit(): - qml.PauliX(wires=0) - return qml.probs(wires=0) - - result = circuit() - assert jnp.allclose(qml.math.hstack(result[0]), expected[0], atol=tol) - assert jnp.allclose(qml.math.hstack(result[1]), expected[1], atol=tol) - - @pytest.mark.skip("Shot lists are not supported with broadcasting yet") - def test_custom_shots_probs_jax_jit_broadcasted(self, tol): - """Test that returning probs works with jax and jit when - using a custom shot vector and broadcasting""" - dev = qml.device("default.qubit.jax", wires=1, shots=(2, 2)) - expected = jnp.array([[[0.0, 1.0], [0.0, 1.0]]] * 5) - - @jax.jit - @qml.qnode(dev, diff_method=None, interface="jax") - def circuit(): - qml.RX(jnp.zeros(5), 0) - qml.PauliX(wires=0) - return qml.probs(wires=0) - - result = circuit() - assert jnp.allclose(result, expected, atol=tol) - - def test_sampling_with_jit(self): - """Test that sampling works with a jax.jit""" - - @jax.jit - def circuit(x, key): - dev = qml.device("default.qubit.jax", wires=1, shots=1000, prng_key=key) - - @qml.qnode(dev, interface="jax", diff_method=None) - def inner_circuit(): - qml.RX(x, wires=0) - qml.Hadamard(0) - return qml.sample(qml.PauliZ(wires=0)) - - return inner_circuit() - - a = circuit(0.0, jax.random.PRNGKey(0)) - b = circuit(0.0, jax.random.PRNGKey(0)) - c = circuit(0.0, jax.random.PRNGKey(1)) - np.testing.assert_array_equal(a, b) - assert not np.all(a == c) - - # Test with broadcasting - d = circuit(jnp.zeros(5), jax.random.PRNGKey(9)) - assert qml.math.shape(d) == (5, 1000) - - @pytest.mark.parametrize( - "state_vector", - [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], - ) - def test_qubit_state_vector_arg_jax_jit(self, state_vector, tol): - """Test that Qubit state vector as argument works with a jax.jit""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(x): - wires = list(range(2)) - qml.QubitStateVector(x, wires=wires) - return [qml.expval(qml.PauliX(wires=i)) for i in wires] - - res = circuit(state_vector) - assert jnp.allclose(jnp.array(res), jnp.array([0, 1]), atol=tol, rtol=0) - - @pytest.mark.parametrize( - "state_vector", - [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], - ) - def test_qubit_state_vector_arg_jax(self, state_vector, tol): - """Test that Qubit state vector as argument works with jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) - - @qml.qnode(dev, interface="jax") - def circuit(x): - wires = list(range(2)) - qml.QubitStateVector(x, wires=wires) - return [qml.expval(qml.PauliX(wires=i)) for i in wires] - - res = circuit(state_vector) - assert jnp.allclose(jnp.array(res), jnp.array([0, 1]), atol=tol, rtol=0) - - @pytest.mark.parametrize( - "state_vector", - [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], - ) - def test_qubit_state_vector_jax_jit(self, state_vector, tol): - """Test that Qubit state vector works with a jax.jit""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.QubitStateVector(state_vector, wires=dev.wires) - for w in dev.wires: - qml.RZ(x, wires=w, id="x") - return qml.expval(qml.PauliZ(wires=0)) - - res = circuit(0.1) - assert jnp.allclose(jnp.array(res), 1, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "state_vector", - [np.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0]), jnp.array([0.5 + 0.5j, 0.5 + 0.5j, 0, 0])], - ) - def test_qubit_state_vector_jax(self, state_vector, tol): - """Test that Qubit state vector works with a jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.QubitStateVector(state_vector, wires=dev.wires) - for w in dev.wires: - qml.RZ(x, wires=w, id="x") - return qml.expval(qml.PauliZ(wires=0)) - - res = circuit(0.1) - assert jnp.allclose(jnp.array(res), 1, atol=tol, rtol=0) - - @pytest.mark.parametrize( - "state_vector", - [np.array([0.1 + 0.1j, 0.2 + 0.2j, 0, 0]), jnp.array([0.1 + 0.1j, 0.2 + 0.2j, 0, 0])], - ) - def test_qubit_state_vector_jax_not_normed(self, state_vector): - """Test that an error is raised when Qubit state vector is not normed works with a jax""" - dev = qml.device("default.qubit.jax", wires=list(range(2))) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.QubitStateVector(state_vector, wires=dev.wires) - for w in dev.wires: - qml.RZ(x, wires=w, id="x") - return qml.expval(qml.PauliZ(wires=0)) - - with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."): - circuit(0.1) - - def test_sampling_op_by_op(self): - """Test that op-by-op sampling works as a new user would expect""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.Hadamard(0) - return qml.sample(qml.PauliZ(wires=0)) - - a = circuit() - b = circuit() - assert not np.all(a == b) - - def test_sampling_analytic_mode(self): - """Test that when sampling with shots=None an error is raised.""" - dev = qml.device("default.qubit.jax", wires=1, shots=None) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - return qml.sample(qml.PauliZ(wires=0)) - - with pytest.raises( - qml.QuantumFunctionError, - match="The number of shots has to be explicitly set on the device " - "when using sample-based measurements.", - ): - circuit() - - def test_sampling_analytic_mode_with_counts(self): - """Test that when sampling with counts and shots=None an error is raised.""" - dev = qml.device("default.qubit.jax", wires=1, shots=None) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - return qml.counts(qml.PauliZ(wires=0)) - - with pytest.raises( - qml.QuantumFunctionError, - match="The number of shots has to be explicitly set on the device " - "when using sample-based measurements.", - ): - circuit() - - def test_gates_dont_crash(self): - """Test for gates that weren't covered by other tests.""" - dev = qml.device("default.qubit.jax", wires=2, shots=1000) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.CRZ(0.0, wires=[0, 1]) - qml.CRX(0.0, wires=[0, 1]) - qml.PhaseShift(0.0, wires=0) - qml.ControlledPhaseShift(0.0, wires=[1, 0]) - qml.CRot(1.0, 0.0, 0.0, wires=[0, 1]) - qml.CRY(0.0, wires=[0, 1]) - return qml.sample(qml.PauliZ(wires=0)) - - circuit() # Just don't crash. - - def test_diagonal_doesnt_crash(self): - """Test that diagonal gates can be used.""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.DiagonalQubitUnitary(np.array([1.0, 1.0]), wires=0) - return qml.sample(qml.PauliZ(wires=0)) - - circuit() # Just don't crash. - - def test_broadcasted_diagonal_doesnt_crash(self): - """Test that diagonal gates can be used.""" - dev = qml.device("default.qubit.jax", wires=1, shots=1000) - - @qml.qnode(dev, interface="jax", diff_method=None) - def circuit(): - qml.DiagonalQubitUnitary(np.array([[-1, -1], [1j, -1], [1.0, 1.0]]), wires=0) - return qml.sample(qml.PauliZ(wires=0)) - - circuit() # Just don't crash. - - @pytest.mark.parametrize("phi", np.pi * np.array([1e-8, 1 / 8, 1 / 4, 1 / 2, 1])) - def test_parametrized_evolution_state_vector(self, phi, mocker): - """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` - the `_evolve_state_vector_under_parametrized_evolution` method is used.""" - dev = qml.device("default.qubit.jax", wires=1) - H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) - spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(): - qml.evolve(H)(params=[], t=phi / 2) - return qml.expval(qml.PauliZ(0)) - - @qml.qnode(dev) - def true_circuit(): - qml.RX(phi, 0) - return qml.expval(qml.PauliZ(0)) - - res = circuit() - spy.assert_called_once() - assert qml.math.allclose(res, true_circuit(), atol=1e-6) - - @pytest.mark.parametrize("phi", np.pi * np.array([1e-8, 1 / 8, 1 / 4, 1 / 2, 1])) - def test_parametrized_evolution_matrix(self, phi, mocker): - """Test that when executing a ParametrizedEvolution with ``num_wires < device.num_wires/2`` - the `_apply_operation` method is used.""" - dev = qml.device("default.qubit.jax", wires=3) - H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) - spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") - spy2 = mocker.spy(dev, "_apply_operation") - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(): - qml.evolve(H)(params=[], t=phi / 2) # corresponds to a PauliX gate - return qml.expval(qml.PauliZ(0)) - - @qml.qnode(dev) - def true_circuit(): - qml.RX(phi, 0) - return qml.expval(qml.PauliZ(0)) - - res = circuit() - spy.assert_not_called() - spy2.assert_called_once() - assert qml.math.allclose(res, true_circuit(), atol=1e-6) - - def test_parametrized_evolution_state_vector_return_intermediate(self, mocker): - """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` - and ``return_intermediate=True``, the ``_evolve_state_vector_under_parametrized_evolution`` - method is used.""" - dev = qml.device("default.qubit.jax", wires=1) - H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) - spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") - spy2 = mocker.spy(dev, "_apply_operation") - - phi = jnp.linspace(0.3, 0.7, 7) - phi_for_RX = phi - phi[0] - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(): - qml.evolve(H, return_intermediate=True)(params=[], t=phi / 2) - return qml.expval(qml.PauliZ(0)) - - @qml.qnode(dev) - def true_circuit(): - qml.RX(phi_for_RX, 0) - return qml.expval(qml.PauliZ(0)) - - res = circuit() - spy.assert_called_once() - spy2.assert_not_called() - assert qml.math.allclose(res, true_circuit(), atol=1e-6) - - def test_parametrized_evolution_matrix_complementary(self, mocker): - """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` - but with ``complementary=True``, the `_apply_operation` method is used.""" - dev = qml.device("default.qubit.jax", wires=1) - H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) - spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") - spy2 = mocker.spy(dev, "_apply_operation") - - phi = jnp.linspace(0.3, 0.7, 7) - phi_for_RX = phi[-1] - phi - - @jax.jit - @qml.qnode(dev, interface="jax") - def circuit(): - qml.evolve(H, return_intermediate=True, complementary=True)(params=[], t=phi / 2) - return qml.expval(qml.PauliZ(0)) - - @qml.qnode(dev) - def true_circuit(): - qml.RX(phi_for_RX, 0) - return qml.expval(qml.PauliZ(0)) - - res = circuit() - spy.assert_not_called() - spy2.assert_called_once() - assert qml.math.allclose(res, true_circuit(), atol=1e-6) - - -@pytest.mark.jax -class TestPassthruIntegration: - """Tests for integration with the PassthruQNode""" - - @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) - def test_jacobian_variable_multiply(self, tol, jacobian_transform): - """Test that jacobian of a QNode with an attached default.qubit.jax device - gives the correct result in the case of parameters multiplied by scalars""" - x = 0.43316321 - y = 0.2162158 - z = 0.75110998 - weights = jnp.array([x, y, z]) - - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(weights) - - expected = jnp.cos(3 * x) * jnp.cos(y) * jnp.cos(z / 2) - jnp.sin(3 * x) * jnp.sin(z / 2) - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = jacobian_transform(circuit, 0) - res = grad_fn(jnp.array(weights)) - - expected = jnp.array( - [ - -3 - * (jnp.sin(3 * x) * jnp.cos(y) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.sin(z / 2)), - -jnp.cos(3 * x) * jnp.sin(y) * jnp.cos(z / 2), - -0.5 - * (jnp.sin(3 * x) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.cos(y) * jnp.sin(z / 2)), - ] - ) - - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_variable_multiply_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.jax device - gives the correct result in the case of broadcasted parameters multiplied by scalars""" - x = jnp.array([0.43316321, 92.1, -0.5129]) - y = jnp.array([0.2162158, 0.241, -0.51]) - z = jnp.array([0.75110998, 0.12512, 9.12]) - weights = jnp.array([x, y, z]) - - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - assert circuit.gradient_fn == "backprop" - res = circuit(weights) - - expected = jnp.cos(3 * x) * jnp.cos(y) * jnp.cos(z / 2) - jnp.sin(3 * x) * jnp.sin(z / 2) - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = jax.jacobian(circuit, 0) - res = grad_fn(jnp.array(weights)) - - expected = jnp.array( - [ - -3 - * (jnp.sin(3 * x) * jnp.cos(y) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.sin(z / 2)), - -jnp.cos(3 * x) * jnp.sin(y) * jnp.cos(z / 2), - -0.5 - * (jnp.sin(3 * x) * jnp.cos(z / 2) + jnp.cos(3 * x) * jnp.cos(y) * jnp.sin(z / 2)), - ] - ) - - assert all(jnp.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) - def test_jacobian_repeated(self, tol, jacobian_transform): - """Test that jacobian of a QNode with an attached default.qubit.jax device - gives the correct result in the case of repeated parameters""" - x = 0.43316321 - y = 0.2162158 - z = 0.75110998 - p = jnp.array([x, y, z]) - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - - expected = jnp.cos(y) ** 2 - jnp.sin(x) * jnp.sin(y) ** 2 - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = jacobian_transform(circuit, 0) - res = grad_fn(p) - - expected = jnp.array( - [-jnp.cos(x) * jnp.sin(y) ** 2, -2 * (jnp.sin(x) + 1) * jnp.sin(y) * jnp.cos(y), 0] - ) - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_repeated_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.jax device - gives the correct result in the case of repeated broadcasted parameters""" - p = jnp.array([[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]]) - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - - x, y, _ = p - expected = jnp.cos(y) ** 2 - jnp.sin(x) * jnp.sin(y) ** 2 - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - grad_fn = jax.jacobian(circuit) - res = grad_fn(p) - - expected = jnp.array( - [ - -jnp.cos(x) * jnp.sin(y) ** 2, - -2 * (jnp.sin(x) + 1) * jnp.sin(y) * jnp.cos(y), - jnp.zeros_like(x), - ] - ) - assert all(jnp.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - @pytest.mark.parametrize("wires", [[0], ["abc"]]) - def test_state_differentiability(self, wires, tol): - """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.jax", wires=wires) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a): - qml.RY(a, wires=wires[0]) - return qml.state() - - a = jnp.array(0.54) - - def cost(a): - """A function of the device quantum state, as a function - of input QNode parameters.""" - res = jnp.abs(circuit(a)) ** 2 - return res[1] - res[0] - - grad = jax.grad(cost)(a) - expected = jnp.sin(a) - assert jnp.allclose(grad, expected, atol=tol, rtol=0) - - def test_state_differentiability_broadcasted(self, tol): - """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a): - qml.RY(a, wires=0) - return qml.expval(qml.PauliZ(0)) - - a = jnp.array([0.54, 0.32, 1.2]) - - def cost(a): - """A function of the device quantum state, as a function - of input QNode parameters.""" - circuit(a) - res = jnp.abs(dev.state) ** 2 - return res[:, 1] - res[:, 0] - - jac = jax.jacobian(cost)(a) - expected = jnp.diag(jnp.sin(a)) - assert jnp.allclose(jac, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", np.linspace(-2 * np.pi, np.pi, 7)) - def test_CRot_gradient(self, theta, tol): - """Tests that the automatic gradient of a arbitrary controlled Euler-angle-parameterized - gate is correct.""" - dev = qml.device("default.qubit.jax", wires=2) - a, b, c = np.array([theta, theta**3, np.sqrt(2) * theta]) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a, b, c): - qml.QubitStateVector(np.array([1.0, -1.0]) / np.sqrt(2), wires=0) - qml.CRot(a, b, c, wires=[0, 1]) - return qml.expval(qml.PauliX(0)) - - res = circuit(a, b, c) - expected = -np.cos(b / 2) * np.cos(0.5 * (a + c)) - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad = jax.grad(circuit, argnums=(0, 1, 2))(a, b, c) - expected = np.array( - [ - [ - 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), - 0.5 * np.sin(b / 2) * np.cos(0.5 * (a + c)), - 0.5 * np.cos(b / 2) * np.sin(0.5 * (a + c)), - ] - ] - ) - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_prob_differentiability(self, tol): - """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = jnp.array(0.54) - b = jnp.array(0.12) - - def cost(a, b): - prob_wire_1 = circuit(a, b).squeeze() - return prob_wire_1[1] - prob_wire_1[0] - - res = cost(a, b) - expected = -jnp.cos(a) * jnp.cos(b) - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - grad = jax.jit(jax.grad(cost, argnums=(0, 1)))(a, b) - expected = [jnp.sin(a) * jnp.cos(b), jnp.cos(a) * jnp.sin(b)] - assert jnp.allclose(jnp.array(grad), jnp.array(expected), atol=tol, rtol=0) - - def test_prob_differentiability_broadcasted(self, tol): - """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = jnp.array([0.54, 0.32, 1.2]) - b = jnp.array(0.12) - - def cost(a, b): - prob_wire_1 = circuit(a, b) - return prob_wire_1[:, 1] - prob_wire_1[:, 0] - - res = cost(a, b) - expected = -jnp.cos(a) * jnp.cos(b) - assert jnp.allclose(res, expected, atol=tol, rtol=0) - - jac = jax.jacobian(cost, argnums=[0, 1])(a, b) - expected = jnp.array([jnp.sin(a) * jnp.cos(b), jnp.cos(a) * jnp.sin(b)]) - expected = (jnp.diag(expected[0]), expected[1]) # Only first parameter is broadcasted - assert all(jnp.allclose(j, e, atol=tol, rtol=0) for j, e in zip(jac, expected)) - - def test_backprop_gradient(self, tol): - """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = jnp.array(-0.234) - b = jnp.array(0.654) - - res = circuit(a, b) - expected_cost = 0.5 * (jnp.cos(a) * jnp.cos(b) + jnp.cos(a) - jnp.cos(b) + 1) - assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) - res = jax.grad(circuit, argnums=(0, 1))(a, b) - expected_grad = jnp.array( - [-0.5 * jnp.sin(a) * (jnp.cos(b) + 1), 0.5 * jnp.sin(b) * (1 - jnp.cos(a))] - ) - - assert jnp.allclose(jnp.array(res), jnp.array(expected_grad), atol=tol, rtol=0) - - def test_backprop_gradient_broadcasted(self, tol): - """Tests that the gradient of the broadcasted qnode is correct""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = jnp.array(0.12) - b = jnp.array([0.54, 0.32, 1.2]) - - res = circuit(a, b) - expected_cost = 0.5 * (jnp.cos(a) * jnp.cos(b) + jnp.cos(a) - jnp.cos(b) + 1) - assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) - - res = jax.jacobian(circuit, argnums=[0, 1])(a, b) - expected = jnp.array( - [-0.5 * jnp.sin(a) * (jnp.cos(b) + 1), 0.5 * jnp.sin(b) * (1 - jnp.cos(a))] - ) - expected = (expected[0], jnp.diag(expected[1])) - assert all(jnp.allclose(r, e, atol=tol, rtol=0) for r, e in zip(res, expected)) - - @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) - def test_hessian_at_zero(self, x, shift): - """Tests that the Hessian at vanishing state vector amplitudes - is correct.""" - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, interface="jax", diff_method="backprop") - def circuit(x): - qml.RY(shift, wires=0) - qml.RY(x, wires=0) - return qml.expval(qml.PauliZ(0)) - - assert qml.math.isclose(jax.grad(circuit)(x), 0.0) - assert qml.math.isclose(jax.jacobian(jax.jacobian(circuit))(x), -1.0) - assert qml.math.isclose(jax.grad(jax.grad(circuit))(x), -1.0) - - @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) - @pytest.mark.parametrize("diff_method", ["backprop"]) - def test_jax_interface_gradient(self, operation, diff_method, tol): - """Tests that the gradient of an arbitrary U3 gate is correct - using the Jax interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.jax", wires=1) - - @qml.qnode(dev, diff_method=diff_method, interface="jax") - def circuit(x, weights, w=None): - """In this example, a mixture of scalar - arguments, array arguments, and keyword arguments are used.""" - qml.QubitStateVector(1j * jnp.array([1, -1]) / jnp.sqrt(2), wires=w) - operation(x, weights[0], weights[1], wires=w) - return qml.expval(qml.PauliX(w)) - - def cost(params): - """Perform some classical processing""" - return (circuit(params[0], params[1:], w=0) ** 2).reshape(()) - - theta = 0.543 - phi = -0.234 - lam = 0.654 - - params = jnp.array([theta, phi, lam]) - - res = cost(params) - expected_cost = ( - jnp.sin(lam) * jnp.sin(phi) - jnp.cos(theta) * jnp.cos(lam) * jnp.cos(phi) - ) ** 2 - assert jnp.allclose(res, expected_cost, atol=tol, rtol=0) - - res = jax.grad(cost)(params) - expected_grad = ( - jnp.array( - [ - jnp.sin(theta) * jnp.cos(lam) * jnp.cos(phi), - jnp.cos(theta) * jnp.cos(lam) * jnp.sin(phi) + jnp.sin(lam) * jnp.cos(phi), - jnp.cos(theta) * jnp.sin(lam) * jnp.cos(phi) + jnp.cos(lam) * jnp.sin(phi), - ] - ) - * 2 - * (jnp.sin(lam) * jnp.sin(phi) - jnp.cos(theta) * jnp.cos(lam) * jnp.cos(phi)) - ) - assert jnp.allclose(res, expected_grad, atol=tol, rtol=0) - - @pytest.mark.parametrize("interface", ["autograd", "tf", "torch"]) - def test_error_backprop_wrong_interface(self, interface): - """Tests that an error is raised if diff_method='backprop' but not using - the Jax interface""" - dev = qml.device("default.qubit.jax", wires=1) - - def circuit(x, w=None): - qml.RZ(x, wires=w) - return qml.expval(qml.PauliX(w)) - - error_type = qml.QuantumFunctionError - with pytest.raises( - error_type, - match="default.qubit.jax only supports diff_method='backprop' when using the jax interface", - ): - qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) - - def test_no_jax_interface_applied(self): - """Tests that the JAX interface is not applied and no error is raised if qml.probs is used with the Jax - interface when diff_method='backprop' - - When the JAX interface is applied, we can only get the expectation value and the variance of a QNode. - """ - dev = qml.device("default.qubit.jax", wires=1, shots=None) - - def circuit(): - return qml.probs(wires=0) - - qnode = qml.qnode(dev, diff_method="backprop", interface="jax")(circuit) - assert jnp.allclose(qnode(), jnp.array([1, 0])) - - -@pytest.mark.jax -class TestHighLevelIntegration: - """Tests for integration with higher level components of PennyLane.""" - - def test_do_not_split_analytic_jax(self, mocker): - """Tests that the Hamiltonian is not split for shots=None using the jax device.""" - dev = qml.device("default.qubit.jax", wires=2) - H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(): - return qml.expval(H) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_direct_eval_hamiltonian_broadcasted_error_jax(self): - """Tests that an error is raised when attempting to evaluate a Hamiltonian with - broadcasting and shots=None directly via its sparse representation with Jax.""" - dev = qml.device("default.qubit.jax", wires=2) - H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(): - qml.RX(jnp.zeros(5), 0) - return qml.expval(H) - - with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): - circuit() - - def test_template_integration(self): - """Test that a PassthruQNode using default.qubit.jax works with templates.""" - dev = qml.device("default.qubit.jax", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(weights): - qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - weights = jnp.array( - np.random.random(qml.templates.StronglyEntanglingLayers.shape(n_layers=2, n_wires=2)) - ) - - grad = jax.grad(circuit)(weights) - assert grad.shape == weights.shape - - -# pylint: disable=protected-access -@pytest.mark.jax -class TestOps: - """Unit tests for operations supported by the default.qubit.jax device""" - - @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) - def test_multirz_jacobian(self, jacobian_transform): - """Test that the patched numpy functions are used for the MultiRZ - operation and the jacobian can be computed.""" - wires = 4 - dev = qml.device("default.qubit.jax", wires=wires) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(param): - qml.MultiRZ(param, wires=[0, 1]) - return qml.probs(wires=list(range(wires))) - - param = 0.3 - res = jacobian_transform(circuit)(param) - assert jnp.allclose(res, jnp.zeros(wires**2)) - - def test_full_subsystem(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubitJax(wires=["a", "b", "c"]) - state = jnp.array([1, 0, 0, 0, 1, 0, 1, 1]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert jnp.all(dev._state.flatten() == state) - spy.assert_not_called() - - def test_partial_subsystem(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubitJax(wires=["a", "b", "c"]) - state = jnp.array([1, 0, 1, 0]) / jnp.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = jnp.sum(dev._state, axis=(1,)).flatten() - - assert jnp.all(res == state) - spy.assert_called() - - def test_parametrized_evolution(self): - """Test applying a ParametrizedEvolution to a subset of wires of the full subsystem""" - dev = DefaultQubitJax(wires=["a", "b", "c"]) - state = jnp.array([[[1.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], dtype=complex) - expected_res = jnp.array( - [[[0.0, 0.0], [0.0, 0.0]], [[1.0, 0.0], [0.0, 0.0]]], dtype=complex - ) - # ev corresponds to a PauliX gate - ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX("a")]))(params=[], t=np.pi / 2) - res = qml.math.abs(dev._apply_parametrized_evolution(state=state, operation=ev)) - - assert qml.math.allclose(res, expected_res, atol=1e-5) - - def test_parametrized_evolution_raises_error(self): - """Test applying a ParametrizedEvolution without params or t specified raises an error.""" - dev = DefaultQubitJax(wires=["a"]) - state = jnp.array([[[1.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], dtype=complex) - ev = qml.evolve(ParametrizedHamiltonian([1], [qml.PauliX("a")])) - with pytest.raises( - ValueError, - match="The parameters and the time window are required to execute a ParametrizedEvolution", - ): - dev._apply_parametrized_evolution(state=state, operation=ev) - - -@pytest.mark.jax -class TestOpsBroadcasted: - """Unit tests for broadcasted operations supported by the default.qubit.jax device""" - - @pytest.mark.parametrize("jacobian_transform", [jax.jacfwd, jax.jacrev]) - def test_multirz_jacobian_broadcasted(self, jacobian_transform): - """Test that the patched numpy functions are used for the MultiRZ - operation and the jacobian can be computed.""" - wires = 4 - dev = qml.device("default.qubit.jax", wires=wires) - - @qml.qnode(dev, diff_method="backprop", interface="jax") - def circuit(param): - qml.MultiRZ(param, wires=[0, 1]) - return qml.probs(wires=list(range(wires))) - - param = jnp.array([0.3, 0.9, -4.3]) - res = jacobian_transform(circuit)(param) - assert jnp.allclose(res, jnp.zeros((3, wires**2, 3))) - - def test_full_subsystem_broadcasted(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubitJax(wires=["a", "b", "c"]) - state = jnp.array([[1, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 1, 1, 1, 0]]) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert jnp.all(dev._state.reshape((2, 8)) == state) - spy.assert_not_called() - - def test_partial_subsystem_broadcasted(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - - dev = DefaultQubitJax(wires=["a", "b", "c"]) - state = jnp.array([[1, 0, 1, 0], [0, 1, 0, 1], [1, 1, 0, 0]]) / jnp.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = jnp.sum(dev._state, axis=(2,)).reshape((3, 4)) - - assert jnp.allclose(res, state) - spy.assert_called() - - -@pytest.mark.jax -class TestEstimateProb: - """Test the estimate_probability method""" - - @pytest.mark.parametrize( - "wires, expected", [([0], [0.5, 0.5]), (None, [0.5, 0, 0, 0.5]), ([0, 1], [0.5, 0, 0, 0.5])] - ) - def test_estimate_probability(self, wires, expected, monkeypatch): - """Tests the estimate_probability method""" - dev = qml.device("default.qubit.jax", wires=2) - samples = jnp.array([[0, 0], [1, 1], [1, 1], [0, 0]]) - - with monkeypatch.context() as m: - m.setattr(dev, "_samples", samples) - res = dev.estimate_probability(wires=wires) - - assert np.allclose(res, expected) - - @pytest.mark.parametrize( - "wires, expected", - [ - ([0], [[0.0, 0.5], [1.0, 0.5]]), - (None, [[0.0, 0.5], [0, 0], [0, 0.5], [1.0, 0]]), - ([0, 1], [[0.0, 0.5], [0, 0], [0, 0.5], [1.0, 0]]), - ], - ) - def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): - """Tests the estimate_probability method with a bin size""" - dev = qml.device("default.qubit.jax", wires=2) - samples = jnp.array([[1, 1], [1, 1], [1, 0], [0, 0]]) - bin_size = 2 - - with monkeypatch.context() as m: - m.setattr(dev, "_samples", samples) - res = dev.estimate_probability(wires=wires, bin_size=bin_size) - - assert np.allclose(res, expected) - - @pytest.mark.parametrize( - "wires, expected", - [ - ([0], [[0.0, 1.0], [0.5, 0.5], [0.25, 0.75]]), - (None, [[0, 0, 0.25, 0.75], [0.5, 0, 0, 0.5], [0.25, 0, 0.25, 0.5]]), - ([0, 1], [[0, 0, 0.25, 0.75], [0.5, 0, 0, 0.5], [0.25, 0, 0.25, 0.5]]), - ], - ) - def test_estimate_probability_with_broadcasting(self, wires, expected, monkeypatch): - """Tests the estimate_probability method with parameter broadcasting""" - dev = qml.device("default.qubit.jax", wires=2) - samples = jnp.array( - [ - [[1, 0], [1, 1], [1, 1], [1, 1]], - [[0, 0], [1, 1], [1, 1], [0, 0]], - [[1, 0], [1, 1], [1, 1], [0, 0]], - ] - ) - - with monkeypatch.context() as m: - m.setattr(dev, "_samples", samples) - res = dev.estimate_probability(wires=wires) - - assert np.allclose(res, expected) - - @pytest.mark.parametrize( - "wires, expected", - [ - ( - [0], - [ - [[0, 0, 0.5], [1, 1, 0.5]], - [[0.5, 0.5, 0], [0.5, 0.5, 1]], - [[0, 0.5, 1], [1, 0.5, 0]], - ], - ), - ( - None, - [ - [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], - [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], - [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], - ], - ), - ( - [0, 1], - [ - [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], - [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], - [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], - ], - ), - ], - ) - def test_estimate_probability_with_binsize_with_broadcasting( - self, wires, expected, monkeypatch - ): - """Tests the estimate_probability method with a bin size and parameter broadcasting""" - dev = qml.device("default.qubit.jax", wires=2) - bin_size = 2 - samples = jnp.array( - [ - [[1, 0], [1, 1], [1, 1], [1, 1], [1, 1], [0, 1]], - [[0, 0], [1, 1], [1, 1], [0, 0], [1, 1], [1, 1]], - [[1, 0], [1, 1], [1, 1], [0, 0], [0, 1], [0, 0]], - ] - ) - - with monkeypatch.context() as m: - m.setattr(dev, "_samples", samples) - res = dev.estimate_probability(wires=wires, bin_size=bin_size) - - assert np.allclose(res, expected) diff --git a/tests/devices/test_default_qubit_tf.py b/tests/devices/test_default_qubit_tf.py deleted file mode 100644 index 5593af37b29..00000000000 --- a/tests/devices/test_default_qubit_tf.py +++ /dev/null @@ -1,2313 +0,0 @@ -# Copyright 2018-2020 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 and integration tests for the ``default.qubit.tf`` device. -""" -# pylint: disable=too-many-arguments,protected-access,too-many-public-methods -import numpy as np -import pytest - -from gate_data import ( - I, - X, - Y, - Z, - H, - S, - T, - CNOT, - CZ, - CCZ, - SWAP, - Toffoli, - CSWAP, - Rphi, - Rotx, - Roty, - Rotz, - Rot3, - CRotx, - CRoty, - CRotz, - CRot3, - MultiRZ1, - MultiRZ2, - ControlledPhaseShift, - OrbitalRotation, - FermionicSWAP, -) - -import pennylane as qml -from pennylane import numpy as pnp -from pennylane import DeviceError - -tf = pytest.importorskip("tensorflow", minversion="2.0") -from pennylane.devices.default_qubit_tf import ( # pylint: disable=wrong-import-position - DefaultQubitTF, -) - -np.random.seed(42) - - -##################################################### -# Test matrices -##################################################### - -U = np.array( - [ - [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], - [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], - ] -) - -U2 = np.array([[0, 1, 1, 1], [1, 0, 1, -1], [1, -1, 0, 1], [1, 1, -1, 0]]) / np.sqrt(3) -A = np.array([[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]]) - - -##################################################### -# Define standard qubit operations -##################################################### - -single_qubit = [ - (qml.S, S), - (qml.T, T), - (qml.PauliX, X), - (qml.PauliY, Y), - (qml.PauliZ, Z), - (qml.Hadamard, H), -] -single_qubit_param = [ - (qml.PhaseShift, Rphi), - (qml.RX, Rotx), - (qml.RY, Roty), - (qml.RZ, Rotz), - (qml.MultiRZ, MultiRZ1), -] -two_qubit = [(qml.CZ, CZ), (qml.CNOT, CNOT), (qml.SWAP, SWAP)] -two_qubit_param = [ - (qml.CRX, CRotx), - (qml.CRY, CRoty), - (qml.CRZ, CRotz), - (qml.MultiRZ, MultiRZ2), - (qml.ControlledPhaseShift, ControlledPhaseShift), - (qml.FermionicSWAP, FermionicSWAP), -] -three_qubit = [(qml.Toffoli, Toffoli), (qml.CSWAP, CSWAP), (qml.CCZ, CCZ)] -four_qubit_param = [(qml.OrbitalRotation, OrbitalRotation)] - -##################################################### -# Fixtures -##################################################### - - -# pylint: disable=unused-argument -@pytest.fixture(name="init_state") -def init_state_fixture(scope="session"): - """Generates a random initial state""" - - def _init_state(n): - """random initial state""" - np.random.seed(4214152) - state = np.random.random([2**n]) + np.random.random([2**n]) * 1j - state /= np.linalg.norm(state) - return state - - return _init_state - - -# pylint: disable=unused-argument -@pytest.fixture(name="broadcasted_init_state") -def broadcasted_init_state_fixture(scope="session"): - """Generates a random initial state""" - - def _broadcasted_init_state(n, batch_size): - """random initial state""" - np.random.seed(4214152) - state = np.random.random([batch_size, 2**n]) + np.random.random([batch_size, 2**n]) * 1j - return state / np.linalg.norm(state, axis=1)[:, np.newaxis] - - return _broadcasted_init_state - - -##################################################### -# Initialization test -##################################################### - - -@pytest.mark.tf -def test_analytic_deprecation(): - """Tests if the kwarg `analytic` is used and displays error message.""" - msg = "The analytic argument has been replaced by shots=None. " - msg += "Please use shots=None instead of analytic=True." - - with pytest.raises( - DeviceError, - match=msg, - ): - qml.device("default.qubit.tf", wires=1, shots=1, analytic=True) - - -##################################################### -# Device-level matrix creation tests -##################################################### - - -@pytest.mark.tf -class TestTFMatrix: - """Test special case of matrix construction in TensorFlow for - cases where variables must be casted to complex.""" - - @pytest.mark.parametrize( - "op,params,wires", - [ - (qml.PhaseShift, [0.1], 0), - (qml.ControlledPhaseShift, [0.1], [0, 1]), - (qml.CRX, [0.1], [0, 1]), - (qml.CRY, [0.1], [0, 1]), - (qml.CRZ, [0.1], [0, 1]), - (qml.CRot, [0.1, 0.2, 0.3], [0, 1]), - (qml.U1, [0.1], 0), - (qml.U2, [0.1, 0.2], 0), - (qml.U3, [0.1, 0.2, 0.3], 0), - (qml.Rot, [0.1, 0.2, 0.3], 0), - ], - ) - def test_tf_matrix(self, op, params, wires): - tf_params = [tf.Variable(x) for x in params] - expected_mat = op(*params, wires=wires).matrix() - obtained_mat = op(*tf_params, wires=wires).matrix() - assert qml.math.get_interface(obtained_mat) == "tensorflow" - assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) - - @pytest.mark.parametrize( - "op,params,wires", - [ - (qml.PhaseShift, ([0.1, 0.2, 0.5],), 0), - (qml.ControlledPhaseShift, ([0.1],), [0, 1]), - (qml.CRX, ([0.1, -0.6, 0.2],), [0, 1]), - (qml.CRY, ([0.1, -0.4, 6.3],), [0, 1]), - (qml.CRZ, ([0.1, -0.6, 0.2],), [0, 1]), - (qml.CRot, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), [0, 1]), - (qml.U1, ([0.1, 0.2, 0.5],), 0), - (qml.U2, ([0.1, 0.2, 0.5], [0.6, 9.3, 2.1]), 0), - (qml.U3, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), 0), - (qml.Rot, ([0.1, 0.2, 0.3], 0.6, [0.2, 1.2, 4.3]), 0), - ], - ) - def test_broadcasted_tf_matrix(self, op, params, wires): - params = [np.array(p) for p in params] - tf_params = [tf.Variable(x) for x in params] - expected_mat = op(*params, wires=wires).matrix() - obtained_mat = op(*tf_params, wires=wires).matrix() - assert qml.math.get_interface(obtained_mat) == "tensorflow" - assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) - - @pytest.mark.parametrize( - "param,pauli,wires", - [ - (0.1, "I", "a"), - (0.2, "IX", ["a", "b"]), - (-0.3, "III", [0, 1, 2]), - (0.5, "ZXI", [0, 1, 2]), - # Broadcasted rotations - ([0.1, 0.6], "I", "a"), - ([0.2], "IX", ["a", "b"]), - ([-0.3, 0.0, 0.2], "III", [0, 1, 2]), - ([0.5, 0.2], "ZXI", [0, 1, 2]), - ], - ) - def test_pauli_rot_tf_(self, param, pauli, wires): - param = np.array(param) - op = qml.PauliRot(param, pauli, wires=wires) - expected_mat = op.matrix() - expected_eigvals = op.eigvals() - - tf_op = qml.PauliRot(tf.Variable(param), pauli, wires=wires) - obtained_mat = tf_op.matrix() - obtained_eigvals = tf_op.eigvals() - - assert qml.math.get_interface(obtained_mat) == "tensorflow" - assert qml.math.get_interface(obtained_eigvals) == "tensorflow" - - assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) - assert qml.math.allclose(qml.math.unwrap(obtained_eigvals), expected_eigvals) - - @pytest.mark.parametrize( - "op,param,wires", - [ - (qml.PhaseShift, 0.1, [1]), - (qml.ControlledPhaseShift, 0.1, [1, 2]), - (qml.CRZ, 0.1, [1, 2]), - (qml.U1, 0.1, [1]), - # broadcasted operation matrices - (qml.PhaseShift, np.array([0.1, 0.6]), [1]), - (qml.ControlledPhaseShift, np.array([0.1]), [1, 2]), - (qml.CRZ, np.array([0.1, 0.7, 8.3]), [1, 2]), - (qml.U1, np.array([0.1, 0.7, 8.3]), [1]), - ], - ) - def test_expand_tf_matrix(self, op, param, wires): - reg_mat = op(param, wires=wires).matrix() - - if len(wires) == 1: - expected_mat = qml.math.kron(I, qml.math.kron(reg_mat, qml.math.kron(I, I))) - else: - expected_mat = qml.math.kron(I, qml.math.kron(reg_mat, I)) - - tf_mat = op(tf.Variable(param), wires=wires).matrix() - obtained_mat = qml.math.expand_matrix(tf_mat, wires, list(range(4))) - - assert qml.math.get_interface(obtained_mat) == "tensorflow" - assert qml.math.allclose(qml.math.unwrap(obtained_mat), expected_mat) - - -##################################################### -# Device-level integration tests -##################################################### - - -@pytest.mark.tf -class TestApply: - """Test application of PennyLane operations.""" - - def test_basis_state(self, tol): - """Test basis state initialization""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 0]) - - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - res = dev.state - expected = np.zeros([2**4]) - expected[np.ravel_multi_index(state, [2] * 4)] = 1 - - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_invalid_basis_state_length(self): - """Test that an exception is raised if the basis state is the wrong size""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 0]) - - with pytest.raises( - ValueError, match=r"BasisState parameter and wires must be of equal length" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) - - def test_invalid_basis_state(self): - """Test that an exception is raised if the basis state is invalid""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 2]) - - with pytest.raises( - ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - def test_qubit_state_vector(self, init_state, tol): - """Test qubit state vector application""" - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - res = dev.state - expected = state - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_full_subsystem_statevector(self, mocker): - """Test applying a state vector to the full subsystem""" - dev = DefaultQubitTF(wires=["a", "b", "c"]) - state = tf.constant([1, 0, 0, 0, 1, 0, 1, 1], dtype=tf.complex128) / 2.0 - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(tf.reshape(dev._state, [-1]) == state) - spy.assert_not_called() - - def test_partial_subsystem_statevector(self, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - dev = DefaultQubitTF(wires=["a", "b", "c"]) - state = tf.constant([1, 0, 1, 0], dtype=tf.complex128) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = tf.reshape(tf.reduce_sum(dev._state, axis=(1,)), [-1]) - - assert np.all(res == state) - spy.assert_called() - - def test_invalid_qubit_state_vector_size(self): - """Test that an exception is raised if the state - vector is the wrong size""" - dev = DefaultQubitTF(wires=2) - state = np.array([0, 1]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): - dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) - - def test_invalid_qubit_state_vector_norm(self): - """Test that an exception is raised if the state - vector is not normalized""" - dev = DefaultQubitTF(wires=2) - state = np.array([0, 12]) - - with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - def test_invalid_state_prep(self): - """Test that an exception is raised if a state preparation is not the - first operation in the circuit.""" - dev = DefaultQubitTF(wires=2) - state = np.array([0, 1]) - - with pytest.raises( - qml.DeviceError, - match=r"cannot be used after other Operations have already been applied", - ): - dev.apply([qml.PauliZ(0), qml.QubitStateVector(state, wires=[0])]) - - @pytest.mark.parametrize("op,mat", single_qubit) - def test_single_qubit_no_parameters(self, init_state, op, mat, tol): - """Test non-parametrized single qubit operations""" - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(wires=0)] - dev.apply(queue) - - res = dev.state - expected = mat @ state - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters(self, init_state, op, func, theta, tol): - """Test parametrized single qubit operations""" - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(theta, wires=0)] - dev.apply(queue) - - res = dev.state - expected = func(theta) @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation(self, init_state, tol): - """Test three axis rotation gate""" - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - a = 0.542 - b = 1.3432 - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - expected = Rot3(a, b, c) @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation(self, init_state, tol): - """Test three axis controlled-rotation gate""" - dev = DefaultQubitTF(wires=2) - state = init_state(2) - - a = 0.542 - b = 1.3432 - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = CRot3(a, b, c) @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op,mat", two_qubit) - def test_two_qubit_no_parameters(self, init_state, op, mat, tol): - """Test non-parametrized two qubit operations""" - dev = DefaultQubitTF(wires=2) - state = init_state(2) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = mat @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary(self, init_state, mat, tol): - """Test application of arbitrary qubit unitaries""" - N = int(np.log2(len(mat))) - dev = DefaultQubitTF(wires=N) - state = init_state(N) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = mat @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op, mat", three_qubit) - def test_three_qubit_no_parameters(self, init_state, op, mat, tol): - """Test non-parametrized three qubit operations""" - dev = DefaultQubitTF(wires=3) - state = init_state(3) - - queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] - queue += [op(wires=[0, 1, 2])] - dev.apply(queue) - - res = dev.state - expected = mat @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", two_qubit_param) - def test_two_qubit_parameters(self, init_state, op, func, theta, tol): - """Test two qubit parametrized operations""" - dev = DefaultQubitTF(wires=2) - state = init_state(2) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(theta, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = func(theta) @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", four_qubit_param) - def test_four_qubit_parameters(self, init_state, op, func, theta, tol): - """Test four qubit parametrized operations""" - dev = DefaultQubitTF(wires=4) - state = init_state(4) - - queue = [qml.QubitStateVector(state, wires=[0, 1, 2, 3])] - queue += [op(theta, wires=[0, 1, 2, 3])] - dev.apply(queue) - - res = dev.state - expected = func(theta) @ state - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_apply_ops_not_supported(self, mocker, monkeypatch): - """Test that when a version of TensorFlow before 2.3.0 is used, the _apply_ops dictionary is - empty and application of a CNOT gate is performed using _apply_unitary_einsum""" - with monkeypatch.context() as m: - m.setattr("pennylane.devices.default_qubit_tf.SUPPORTS_APPLY_OPS", False) - dev = DefaultQubitTF(wires=3) - assert dev._apply_ops == {} - - spy = mocker.spy(DefaultQubitTF, "_apply_unitary_einsum") - - queue = [qml.CNOT(wires=[1, 2])] - dev.apply(queue) - - spy.assert_called_once() - - def test_apply_ops_above_8_wires(self, mocker): - """Test that when 9 wires are used, the _apply_ops dictionary is empty and application of a - CNOT gate is performed using _apply_unitary_einsum""" - dev = DefaultQubitTF(wires=9) - assert dev._apply_ops == {} - - spy = mocker.spy(DefaultQubitTF, "_apply_unitary_einsum") - - queue = [qml.CNOT(wires=[1, 2])] - dev.apply(queue) - - spy.assert_called_once() - - @pytest.mark.xfail( - raises=tf.errors.UnimplementedError, - reason="Slicing is not supported for more than 8 wires", - strict=True, - ) - def test_apply_ops_above_8_wires_using_special(self): - """Test that special apply methods that involve slicing function correctly when using 9 - wires""" - dev = DefaultQubitTF(wires=9) - dev._apply_ops = {"CNOT": dev._apply_cnot} - - queue = [qml.CNOT(wires=[1, 2])] - dev.apply(queue) - - def test_do_not_split_analytic_tf(self, mocker): - """Tests that the Hamiltonian is not split for shots=None using the tf device.""" - dev = qml.device("default.qubit.tf", wires=2) - ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(): - return qml.expval(ham) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - -@pytest.mark.tf -class TestApplyBroadcasted: - """Test application of broadcasted PennyLane operations.""" - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_basis_state_broadcasted(self, tol): - """Test basis state initialization""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 0]) - - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - res = dev.state - expected = np.zeros([2**4]) - expected[np.ravel_multi_index(state, [2] * 4)] = 1 - - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_invalid_basis_state_length_broadcasted(self): - """Test that an exception is raised if the basis state is the wrong size""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 0]) - - with pytest.raises( - ValueError, match=r"BasisState parameter and wires must be of equal length" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_invalid_basis_state_broadcasted(self): - """Test that an exception is raised if the basis state is invalid""" - dev = DefaultQubitTF(wires=4) - state = np.array([0, 0, 1, 2]) - - with pytest.raises( - ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - @pytest.mark.parametrize("batch_size", [1, 3]) - def test_qubit_state_vector_broadcasted(self, broadcasted_init_state, tol, batch_size): - """Test broadcasted qubit state vector application""" - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, batch_size=batch_size) - - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - res = dev.state - expected = state - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_full_subsystem_statevector_broadcasted(self, mocker): - """Test applying a broadcasted state vector to the full subsystem""" - dev = DefaultQubitTF(wires=["a", "b", "c"]) - state = ( - tf.constant( - [[1, 0, 0, 0, 1, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 1]], - dtype=tf.complex128, - ) - / 2 - ) - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert np.all(tf.reshape(dev._state, [3, 8]) == state) - spy.assert_not_called() - - def test_error_partial_subsystem_statevector_broadcasted(self): - """Test applying a broadcasted state vector to a subset of wires of the full subsystem""" - dev = DefaultQubitTF(wires=["a", "b", "c"]) - state = tf.constant( - [[1, 0, 1, 0], [1, 1, 0, 0], [0, 1, 1, 0]], dtype=tf.complex128 - ) / np.sqrt(2.0) - state_wires = qml.wires.Wires(["a", "c"]) - - with pytest.raises(NotImplementedError, match="Parameter broadcasting is not supported"): - dev._apply_state_vector(state=state, device_wires=state_wires) - - def test_invalid_qubit_state_vector_size_broadcasted(self): - """Test that an exception is raised if the broadcasted state - vector is the wrong size""" - dev = DefaultQubitTF(wires=2) - state = np.array([[0, 1], [1, 0], [1, 1], [0, 0]]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): - dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) - - def test_invalid_qubit_state_vector_norm_broadcasted(self): - """Test that an exception is raised if the broadcasted state - vector is not normalized""" - dev = DefaultQubitTF(wires=2) - state = np.array([[1, 0], [0, 12], [1.3, 1]]) - - with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - @pytest.mark.parametrize("op,mat", single_qubit) - def test_single_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): - """Test non-parametrized single qubit operations""" - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, 3) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(wires=0)] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,kj->ki", mat, state) - assert isinstance(res, tf.Tensor) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_state( - self, broadcasted_init_state, op, func, theta, tol - ): - """Test parametrized single qubit operations with broadcasted initial state""" - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, 3) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(theta, wires=0)] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,kj->ki", func(theta), state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_par(self, init_state, op, func, theta, tol): - """Test parametrized single qubit operations with broadcasted parameters""" - theta = np.array(theta) - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(theta, wires=0)] - dev.apply(queue) - - res = dev.state - mat = np.array([func(t) for t in theta]) - expected = np.einsum("lij,j->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_both( - self, broadcasted_init_state, op, func, theta, tol - ): - """Test parametrized single qubit operations with broadcasted init state and parameters""" - theta = np.array(theta) - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, batch_size=len(theta)) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(theta, wires=0)] - dev.apply(queue) - - res = dev.state - mat = np.array([func(t) for t in theta]) - expected = np.einsum("lij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_state(self, broadcasted_init_state, tol): - """Test three axis rotation gate with broadcasted state""" - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, 3) - - a = 0.542 - b = 1.3432 - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,lj->li", Rot3(a, b, c), state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_par(self, init_state, tol): - """Test three axis rotation gate with broadcasted parameters""" - dev = DefaultQubitTF(wires=1) - state = init_state(1) - - a = np.array([0.542, 0.96, 0.213]) - b = -0.654 - c = np.array([1.3432, 0.6324, 6.32]) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - mat = np.array([Rot3(_a, b, _c) for _a, _c in zip(a, c)]) - expected = np.einsum("lij,j->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_both(self, broadcasted_init_state, tol): - """Test three axis rotation gate with broadcasted state and parameters""" - dev = DefaultQubitTF(wires=1) - state = broadcasted_init_state(1, 3) - - a = np.array([0.542, 0.96, 0.213]) - b = np.array([1.3432, 0.6324, 6.32]) - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - mat = np.array([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) - expected = np.einsum("lij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_state(self, broadcasted_init_state, tol): - """Test controlled three axis rotation gate with broadcasted state""" - dev = DefaultQubitTF(wires=2) - state = broadcasted_init_state(2, 3) - - a = 0.542 - b = 1.3432 - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,lj->li", CRot3(a, b, c), state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_par(self, init_state, tol): - """Test controlled three axis rotation gate with broadcasted parameters""" - dev = DefaultQubitTF(wires=2) - state = init_state(2) - - a = np.array([0.542, 0.96, 0.213]) - b = -0.654 - c = np.array([1.3432, 0.6324, 6.32]) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - mat = np.array([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) - expected = np.einsum("lij,j->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_both(self, broadcasted_init_state, tol): - """Test controlled three axis rotation gate with broadcasted state and parameters""" - dev = DefaultQubitTF(wires=2) - state = broadcasted_init_state(2, 3) - - a = np.array([0.542, 0.96, 0.213]) - b = np.array([1.3432, 0.6324, 6.32]) - c = -0.654 - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - mat = np.array([CRot3(_a, _b, c) for _a, _b in zip(a, b)]) - expected = np.einsum("lij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op,mat", two_qubit) - def test_two_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): - """Test non-parametrized two qubit operations""" - dev = DefaultQubitTF(wires=2) - state = broadcasted_init_state(2, 3) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_state(self, broadcasted_init_state, mat, tol): - """Test application of arbitrary qubit unitaries for broadcasted state""" - N = int(np.log2(len(mat))) - dev = DefaultQubitTF(wires=N) - state = broadcasted_init_state(N, 3) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_par(self, init_state, mat, tol): - """Test application of broadcasted arbitrary qubit unitaries""" - mat = np.array([mat, mat, mat]) - N = int(np.log2(mat.shape[-1])) - dev = DefaultQubitTF(wires=N) - state = init_state(N) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = np.einsum("lij,j->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_both(self, broadcasted_init_state, mat, tol): - """Test application of arbitrary qubit unitaries for broadcasted state and parameters""" - mat = np.array([mat, mat, mat]) - N = int(np.log2(mat.shape[-1])) - dev = DefaultQubitTF(wires=N) - state = broadcasted_init_state(N, 3) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = np.einsum("lij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op, mat", three_qubit) - def test_three_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, mat, tol): - """Test broadcasted non-parametrized three qubit operations""" - dev = DefaultQubitTF(wires=3) - state = broadcasted_init_state(3, 2) - - queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] - queue += [op(wires=[0, 1, 2])] - dev.apply(queue) - - res = dev.state - expected = np.einsum("ij,lj->li", mat, state) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_direct_eval_hamiltonian_broadcasted_error_tf(self): - """Tests that an error is raised when attempting to evaluate a Hamiltonian with - broadcasting and shots=None directly via its sparse representation with TF.""" - dev = qml.device("default.qubit.tf", wires=2) - ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(): - qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity - return qml.expval(ham) - - with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): - circuit() - - -THETA = np.linspace(0.11, 1, 3) -PHI = np.linspace(0.32, 1, 3) -VARPHI = np.linspace(0.02, 1, 3) - -scalar_angles = list(zip(THETA, PHI, VARPHI)) -broadcasted_angles = [(THETA, PHI, VARPHI), (THETA[0], PHI, VARPHI)] -all_angles = scalar_angles + broadcasted_angles - - -# pylint: disable=unused-argument -@pytest.mark.tf -@pytest.mark.parametrize("theta, phi, varphi", all_angles) -class TestExpval: - """Test expectation values""" - - # test data; each tuple is of the form (GATE, OBSERVABLE, EXPECTED) - single_wire_expval_test_data = [ - ( - qml.RX, - qml.Identity, - lambda t, p: np.array( - [np.ones_like(t) * np.ones_like(p), np.ones_like(t) * np.ones_like(p)] - ), - ), - ( - qml.RX, - qml.PauliZ, - lambda t, p: np.array([np.cos(t) * np.ones_like(p), np.cos(t) * np.cos(p)]), - ), - ( - qml.RY, - qml.PauliX, - lambda t, p: np.array([np.sin(t) * np.sin(p), np.sin(p) * np.ones_like(t)]), - ), - ( - qml.RX, - qml.PauliY, - lambda t, p: np.array([np.zeros_like(t) * np.zeros_like(p), -np.cos(t) * np.sin(p)]), - ), - ( - qml.RY, - qml.Hadamard, - lambda t, p: np.array( - [np.sin(t) * np.sin(p) + np.cos(t), np.cos(t) * np.cos(p) + np.sin(p)] - ) - / np.sqrt(2), - ), - ] - - @pytest.mark.parametrize("gate,obs,expected", single_wire_expval_test_data) - def test_single_wire_expectation(self, gate, obs, expected, theta, phi, varphi, tol): - """Test that identity expectation value (i.e. the trace) is 1""" - dev = DefaultQubitTF(wires=2) - - with qml.queuing.AnnotatedQueue() as q: - _ = [gate(theta, wires=0), gate(phi, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(obs(wires=[i])) for i in range(2)] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - assert np.allclose(res, expected(theta, phi), atol=tol, rtol=0) - - def test_hermitian_expectation(self, theta, phi, varphi, tol): - """Test that arbitrary Hermitian expectation values are correct""" - dev = DefaultQubitTF(wires=2) - - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(qml.Hermitian(A, wires=[i])) for i in range(2)] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - ev1 = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - ev2 = ((a - d) * np.cos(theta) * np.cos(phi) + 2 * re_b * np.sin(phi) + a + d) / 2 - expected = np.array([ev1, ev2]) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_multi_mode_hermitian_expectation(self, theta, phi, varphi, tol): - """Test that arbitrary multi-mode Hermitian expectation values are correct""" - _A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - dev = DefaultQubitTF(wires=2) - - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(qml.Hermitian(_A, wires=[0, 1]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - - # below is the analytic expectation value for this circuit with arbitrary - # Hermitian observable A - expected = 0.5 * ( - 6 * np.cos(theta) * np.sin(phi) - - np.sin(theta) * (8 * np.sin(phi) + 7 * np.cos(phi) + 3) - - 2 * np.sin(phi) - - 6 * np.cos(phi) - - 6 - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_paulix_pauliy(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - dev.reset() - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.sin(theta) * np.sin(phi) * np.sin(varphi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_identity(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - dev.reset() - - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = np.cos(varphi) * np.cos(phi) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = -(np.cos(varphi) * np.sin(phi) + np.sin(varphi) * np.cos(theta)) / np.sqrt(2) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - dev.reset() - - _A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(_A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.5 * ( - -6 * np.cos(theta) * (np.cos(varphi) + 1) - - 2 * np.sin(varphi) * (np.cos(theta) + np.sin(phi) - 2 * np.cos(phi)) - + 3 * np.cos(varphi) * np.sin(phi) - + np.sin(phi) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - - A1 = np.array([[1, 2], [2, 4]]) - - A2 = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.25 * ( - -30 - + 4 * np.cos(phi) * np.sin(theta) - + 3 * np.cos(varphi) * (-10 + 4 * np.cos(phi) * np.sin(theta) - 3 * np.sin(phi)) - - 3 * np.sin(phi) - - 2 - * (5 + np.cos(phi) * (6 + 4 * np.sin(theta)) + (-3 + 8 * np.sin(theta)) * np.sin(phi)) - * np.sin(varphi) - + np.cos(theta) - * ( - 18 - + 5 * np.sin(phi) - + 3 * np.cos(varphi) * (6 + 5 * np.sin(phi)) - + 2 * (3 + 10 * np.cos(phi) - 5 * np.sin(phi)) * np.sin(varphi) - ) - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = qml.device("default.qubit.tf", wires=2) - - obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = qml.device("default.qubit.tf", wires=3, shots=None) - Identity = np.array([[1, 0], [0, 1]]) - ham = np.kron(np.kron(Identity, Identity), A) - obs = qml.Hermitian(ham, wires=[2, 1, 0]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - - expected = ((a - d) * np.cos(theta) + 2 * re_b * np.sin(theta) * np.sin(phi) + a + d) / 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.tf -@pytest.mark.parametrize("theta, phi, varphi", all_angles) -class TestVar: - """Tests for the variance""" - - def test_var(self, theta, phi, varphi, tol): - """Tests for variance calculation""" - dev = DefaultQubitTF(wires=1) - # test correct variance for of a rotated state - - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] - _ = [qml.var(qml.PauliZ(wires=[0]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi)) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_var_hermitian(self, theta, phi, varphi, tol): - """Tests for variance calculation using an arbitrary Hermitian observable""" - dev = DefaultQubitTF(wires=2) - - # test correct variance for of a rotated state - ham = np.array([[4, -1 + 6j], [-1 - 6j, 2]]) - - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] - _ = [qml.var(qml.Hermitian(ham, wires=[0]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - expected = 0.5 * ( - 2 * np.sin(2 * theta) * np.cos(phi) ** 2 - + 24 * np.sin(phi) * np.cos(phi) * (np.sin(theta) - np.cos(theta)) - + 35 * np.cos(2 * phi) - + 39 - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_paulix_pauliy(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 8 * np.sin(theta) ** 2 * np.cos(2 * varphi) * np.sin(phi) ** 2 - - np.cos(2 * (theta - phi)) - - np.cos(2 * (theta + phi)) - + 2 * np.cos(2 * theta) - + 2 * np.cos(2 * phi) - + 14 - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 3 - + np.cos(2 * phi) * np.cos(varphi) ** 2 - - np.cos(2 * theta) * np.sin(varphi) ** 2 - - 2 * np.cos(theta) * np.sin(phi) * np.sin(2 * varphi) - ) / 4 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=3) - - _A = np.array( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ] - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(_A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 1057 - - np.cos(2 * phi) - + 12 * (27 + np.cos(2 * phi)) * np.cos(varphi) - - 2 * np.cos(2 * varphi) * np.sin(phi) * (16 * np.cos(phi) + 21 * np.sin(phi)) - + 16 * np.sin(2 * phi) - - 8 * (-17 + np.cos(2 * phi) + 2 * np.sin(2 * phi)) * np.sin(varphi) - - 8 * np.cos(2 * theta) * (3 + 3 * np.cos(varphi) + np.sin(varphi)) ** 2 - - 24 * np.cos(phi) * (np.cos(phi) + 2 * np.sin(phi)) * np.sin(2 * varphi) - - 8 - * np.cos(theta) - * ( - 4 - * np.cos(phi) - * ( - 4 - + 8 * np.cos(varphi) - + np.cos(2 * varphi) - - (1 + 6 * np.cos(varphi)) * np.sin(varphi) - ) - + np.sin(phi) - * ( - 15 - + 8 * np.cos(varphi) - - 11 * np.cos(2 * varphi) - + 42 * np.sin(varphi) - + 3 * np.sin(2 * varphi) - ) - ) - ) / 16 - - assert np.allclose(res, expected, atol=tol, rtol=0) - - -##################################################### -# QNode-level integration tests -##################################################### - - -@pytest.mark.tf -class TestQNodeIntegration: - """Integration tests for default.qubit.tf. This test ensures it integrates - properly with the PennyLane UI, in particular the new QNode.""" - - def test_defines_correct_capabilities(self): - """Test that the device defines the right capabilities""" - - dev = qml.device("default.qubit.tf", wires=1) - cap = dev.capabilities() - capabilities = { - "model": "qubit", - "supports_finite_shots": True, - "supports_tensor_observables": True, - "returns_probs": True, - "returns_state": True, - "supports_inverse_operations": True, - "supports_analytic_computation": True, - "supports_broadcasting": True, - "passthru_interface": "tf", - "passthru_devices": { - "torch": "default.qubit.torch", - "tf": "default.qubit.tf", - "autograd": "default.qubit.autograd", - "jax": "default.qubit.jax", - }, - } - assert cap == capabilities - - def test_load_tensornet_tf_device(self): - """Test that the tensor network plugin loads correctly""" - dev = qml.device("default.qubit.tf", wires=2) - assert dev.num_wires == 2 - assert dev.shots is None - assert dev.short_name == "default.qubit.tf" - assert dev.capabilities()["passthru_interface"] == "tf" - - def test_qubit_circuit(self, tol): - """Test that the tensor network plugin provides correct - result for a simple circuit using the old QNode.""" - p = tf.Variable(0.543) - - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -tf.math.sin(p) - - assert circuit.gradient_fn == "backprop" - assert np.isclose(circuit(p), expected, atol=tol, rtol=0) - - def test_qubit_circuit_broadcasted(self, tol): - """Test that the tensor network plugin provides correct - result for a simple circuit with broadcasting using the old QNode.""" - p = tf.Variable([0.543, 0.21, 2.41]) - - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -tf.math.sin(p) - - assert circuit.gradient_fn == "backprop" - assert np.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_correct_state(self, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - - dev = qml.device("default.qubit.tf", wires=2) - - state = dev.state - expected = np.array([1, 0, 0, 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(np.pi / 4, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - amplitude = np.exp(-1j * np.pi / 8) / np.sqrt(2) - - expected = np.array([amplitude, 0, np.conj(amplitude), 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_broadcasted(self, tol): - """Test that the device state is correct after applying a - broadcasted quantum function on the device""" - - dev = qml.device("default.qubit.tf", wires=2) - - state = dev.state - expected = np.array([1, 0, 0, 0]) - assert np.allclose(state, expected, atol=tol, rtol=0) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(tf.constant([np.pi / 4, np.pi / 2]), wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - phase = np.exp(-1j * np.pi / 8) - - expected = np.array( - [ - [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], - [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], - ] - ) - assert np.allclose(state, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_one_qubit_param_gates(self, theta, op, func, init_state, tol): - """Test the integration of the one-qubit single parameter rotations by passing - a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=1) - state = init_state(1) - - @qml.qnode(dev, interface="tf") - def circuit(params): - qml.QubitStateVector(state, wires=[0]) - op(params[0], wires=[0]) - return qml.expval(qml.PauliZ(0)) - - # Pass a TF Variable to the qfunc - params = tf.Variable(np.array([theta])) - circuit(params) - res = dev.state - expected = func(theta) @ state - assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, 4.213]) - @pytest.mark.parametrize("op,func", two_qubit_param) - def test_two_qubit_param_gates(self, theta, op, func, init_state, tol): - """Test the integration of the two-qubit single parameter rotations by passing - a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=2) - state = init_state(2) - - @qml.qnode(dev, interface="tf") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1]) - op(params[0], wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - # Pass a TF Variable to the qfunc - params = tf.Variable(np.array([theta])) - circuit(params) - res = dev.state - expected = func(theta) @ state - assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, 4.213]) - @pytest.mark.parametrize("op,func", four_qubit_param) - def test_four_qubit_param_gates(self, theta, op, func, init_state, tol): - """Test the integration of the four-qubit single parameter rotations by passing - a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=4) - state = init_state(4) - - @qml.qnode(dev, interface="tf") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1, 2, 3]) - op(params[0], wires=[0, 1, 2, 3]) - return qml.expval(qml.PauliZ(0)) - - # Pass a TF Variable to the qfunc - params = tf.Variable(np.array([theta])) - circuit(params) - res = dev.state - expected = func(theta) @ state - assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) - - def test_controlled_rotation_integration(self, init_state, tol): - """Test the integration of the two-qubit controlled rotation by passing - a TF data structure as a parameter""" - dev = qml.device("default.qubit.tf", wires=2) - a = 1.7 - b = 1.3432 - c = -0.654 - state = init_state(2) - - @qml.qnode(dev, interface="tf") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1]) - qml.CRot(params[0], params[1], params[2], wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - # Pass a TF Variable to the qfunc - params = tf.Variable(np.array([a, b, c])) - circuit(params) - res = dev.state - expected = CRot3(a, b, c) @ state - assert np.allclose(res.numpy(), expected, atol=tol, rtol=0) - - -@pytest.mark.tf -class TestPassthruIntegration: - """Tests for integration with the PassthruQNode""" - - def test_jacobian_variable_multiply(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.tf device - gives the correct result in the case of parameters multiplied by scalars""" - x = tf.Variable(0.43316321) - y = tf.Variable(0.2162158) - z = tf.Variable(0.75110998) - - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - with tf.GradientTape() as tape: - res = circuit([x, y, z]) - - expected = tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - tf.math.sin( - 3 * x - ) * tf.math.sin(z / 2) - assert np.allclose(res, expected, atol=tol, rtol=0) - - res = tf.stack(tape.jacobian(res, [x, y, z]), axis=0) - - expected = np.array( - [ - -3 - * ( - tf.math.sin(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - + tf.math.cos(3 * x) * tf.math.sin(z / 2) - ), - -tf.math.cos(3 * x) * tf.math.sin(y) * tf.math.cos(z / 2), - -0.5 - * ( - tf.math.sin(3 * x) * tf.math.cos(z / 2) - + tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.sin(z / 2) - ), - ] - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_variable_multiply_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.tf device - gives the correct result in the case of broadcasted parameters multiplied by scalars""" - x = tf.Variable([0.43316321, 92.1, -0.5129]) - y = tf.Variable([0.2162158, 0.241, -0.51]) - z = tf.Variable([0.75110998, 0.12512, 9.12]) - - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - with tf.GradientTape() as tape: - res = circuit([x, y, z]) - - expected = tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - tf.math.sin( - 3 * x - ) * tf.math.sin(z / 2) - assert qml.math.shape(res) == (3,) - assert np.allclose(res, expected, atol=tol, rtol=0) - - jac = tape.jacobian(res, [x, y, z]) - res = qml.math.stack([qml.math.diag(j.numpy()) for j in jac]) - - expected = np.array( - [ - -3 - * ( - tf.math.sin(3 * x) * tf.math.cos(y) * tf.math.cos(z / 2) - + tf.math.cos(3 * x) * tf.math.sin(z / 2) - ), - -tf.math.cos(3 * x) * tf.math.sin(y) * tf.math.cos(z / 2), - -0.5 - * ( - tf.math.sin(3 * x) * tf.math.cos(z / 2) - + tf.math.cos(3 * x) * tf.math.cos(y) * tf.math.sin(z / 2) - ), - ] - ) - - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_repeated(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.tf device - gives the correct result in the case of repeated parameters""" - x = 0.43316321 - y = 0.2162158 - z = 0.75110998 - p = tf.Variable([x, y, z]) - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - with tf.GradientTape() as tape: - res = circuit(p) - - expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - res = tape.jacobian(res, p) - - expected = np.array( - [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0] - ) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_jacobian_repeated_broadcasted(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.tf device - gives the correct result in the case of repeated broadcasted parameters""" - x = tf.Variable([0.433, 92.1, -0.512]) - y = tf.Variable([0.218, 0.241, -0.51]) - z = tf.Variable([0.71, 0.152, 9.12]) - p = tf.Variable([x, y, z]) - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - with tf.GradientTape() as tape: - res = circuit(p) - - expected = np.cos(y) ** 2 - np.sin(x) * np.sin(y) ** 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - res = tape.jacobian(res, p) - - expected = np.array( - [-np.cos(x) * np.sin(y) ** 2, -2 * (np.sin(x) + 1) * np.sin(y) * np.cos(y), 0 * x] - ) - assert all(np.allclose(res[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - def test_backprop_jacobian_agrees_parameter_shift(self, tol): - """Test that jacobian of a QNode with an attached default.qubit.tf device - gives the correct result with respect to the parameter-shift method""" - p = pnp.array([0.43316321, 0.2162158, 0.75110998, 0.94714242]) - p_tf = tf.Variable(p, trainable=True) - - def circuit(x): - for i in range(0, len(p), 2): - qml.RX(x[i], wires=0) - qml.RY(x[i + 1], wires=1) - for i in range(2): - qml.CNOT(wires=[i, i + 1]) - return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - - dev1 = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=3) - - def cost(x): - return qml.math.stack(circuit(x)) - - circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="tf") - circuit2 = qml.QNode(cost, dev2, diff_method="parameter-shift") - - with tf.GradientTape() as tape: - res = tf.experimental.numpy.hstack(circuit1(p_tf)) - - assert np.allclose(res, circuit2(p), atol=tol, rtol=0) - - assert circuit1.gradient_fn == "backprop" - assert circuit2.gradient_fn is qml.gradients.param_shift - - res = tape.jacobian(res, p_tf) - assert np.allclose(res, qml.jacobian(circuit2)(p), atol=tol, rtol=0) - - @pytest.mark.parametrize("wires", [[0], ["abc"]]) - def test_state_differentiability(self, wires, tol): - """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.tf", wires=wires) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a): - qml.RY(a, wires=wires[0]) - return qml.state() - - a = tf.Variable(0.54) - - with tf.GradientTape() as tape: - res = tf.abs(circuit(a)) ** 2 - res = res[1] - res[0] - - grad = tape.gradient(res, a) - expected = tf.sin(a) - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_state_differentiability_broadcasted(self, tol): - """Test that the broadcasted device state can be differentiated""" - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a): - qml.RY(a, wires=0) - return qml.expval(qml.PauliZ(0)) - - a = tf.Variable([0.54, 0.32, 1.2]) - - with tf.GradientTape() as tape: - circuit(a) - res = tf.abs(dev.state) ** 2 - res = res[:, 1] - res[:, 0] - - jac = tape.jacobian(res, a) - expected = tf.sin(a) - assert np.allclose(qml.math.diag(jac.numpy()), expected, atol=tol, rtol=0) - - def test_prob_differentiability(self, tol): - """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.tf", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = tf.Variable(0.54) - b = tf.Variable(0.12) - - with tf.GradientTape() as tape: - # 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] - - expected = -tf.cos(a) * tf.cos(b) - assert np.allclose(res, expected, atol=tol, rtol=0) - - grad = tape.gradient(res, [a, b]) - expected = [tf.sin(a) * tf.cos(b), tf.cos(a) * tf.sin(b)] - assert np.allclose(grad, expected, atol=tol, rtol=0) - - def test_prob_differentiability_broadcasted(self, tol): - """Test that the broadcasted device probability can be differentiated""" - dev = qml.device("default.qubit.tf", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = tf.Variable([0.54, 0.32, 1.2]) - b = tf.Variable(0.12) - - with tf.GradientTape() as tape: - # 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] - - expected = -tf.cos(a) * tf.cos(b) - assert np.allclose(res, expected, atol=tol, rtol=0) - - jac = tape.jacobian(res, [a, b]) - expected = [tf.sin(a) * tf.cos(b), tf.cos(a) * tf.sin(b)] - assert np.allclose(qml.math.diag(jac[0].numpy()), expected[0]) - assert np.allclose(jac[1], expected[1]) - - def test_backprop_gradient(self, tol): - """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.tf", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = -0.234 - b = 0.654 - - a_tf = tf.Variable(a, dtype=tf.float64) - b_tf = tf.Variable(b, dtype=tf.float64) - - with tf.GradientTape() as tape: - tape.watch([a_tf, b_tf]) - res = circuit(a_tf, b_tf) - - # the analytic result of evaluating circuit(a, b) - expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) - - # the analytic result of evaluating grad(circuit(a, b)) - expected_grad = np.array( - [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] - ) - - assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) - - res = tape.gradient(res, [a_tf, b_tf]) - assert np.allclose(res, expected_grad, atol=tol, rtol=0) - - def test_backprop_gradient_broadcasted(self, tol): - """Tests that the gradient of the broadcasted qnode is correct""" - dev = qml.device("default.qubit.tf", wires=2) - - @qml.qnode(dev, diff_method="backprop", interface="tf") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = np.array(0.12) - b = np.array([0.54, 0.32, 1.2]) - - a_tf = tf.Variable(a, dtype=tf.float64) - b_tf = tf.Variable(b, dtype=tf.float64) - - with tf.GradientTape() as tape: - tape.watch([a_tf, b_tf]) - res = circuit(a_tf, b_tf) - - # the analytic result of evaluating circuit(a, b) - expected_cost = 0.5 * (np.cos(a) * np.cos(b) + np.cos(a) - np.cos(b) + 1) - - # the analytic result of evaluating grad(circuit(a, b)) - expected_jac = np.array( - [-0.5 * np.sin(a) * (np.cos(b) + 1), 0.5 * np.sin(b) * (1 - np.cos(a))] - ) - - assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) - - jac = tape.jacobian(res, [a_tf, b_tf]) - assert np.allclose(jac[0], expected_jac[0], atol=tol, rtol=0) - assert np.allclose(qml.math.diag(jac[1].numpy()), expected_jac[1], atol=tol, rtol=0) - - @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) - def test_hessian_at_zero(self, x, shift): - """Tests that the Hessian at vanishing state vector amplitudes - is correct.""" - dev = qml.device("default.qubit.tf", wires=1) - - shift = tf.constant(shift) - x = tf.Variable(x) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(x): - qml.RY(shift, wires=0) - qml.RY(x, wires=0) - return qml.expval(qml.PauliZ(0)) - - with tf.GradientTape(persistent=True) as t2: - with tf.GradientTape(persistent=True) as t1: - value = circuit(x) - grad = t1.gradient(value, x) - jac = t1.jacobian(value, x) - hess_grad = t2.gradient(grad, x) - hess_jac = t2.jacobian(jac, x) - - assert qml.math.isclose(grad, 0.0) - assert qml.math.isclose(hess_grad, -1.0) - assert qml.math.isclose(hess_jac, -1.0) - - @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) - @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) - def test_tf_interface_gradient(self, operation, diff_method, tol): - """Tests that the gradient of an arbitrary U3 gate is correct - using the TensorFlow interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, diff_method=diff_method, interface="tf") - def circuit(x, weights, w): - """In this example, a mixture of scalar - arguments, array arguments, and keyword arguments are used.""" - qml.QubitStateVector(1j * np.array([1, -1]) / np.sqrt(2), wires=w) - operation(x, weights[0], weights[1], wires=w) - return qml.expval(qml.PauliX(w)) - - # Check that the correct QNode type is being used. - if diff_method == "backprop": - assert circuit.gradient_fn == "backprop" - elif diff_method == "parameter-shift": - assert circuit.gradient_fn is qml.gradients.param_shift - elif diff_method == "finite-diff": - assert circuit.gradient_fn is qml.gradients.finite_diff - - def cost(params): - """Perform some classical processing""" - return circuit(params[0], params[1:], w=0) ** 2 - - theta = 0.543 - phi = -0.234 - lam = 0.654 - - params = tf.Variable([theta, phi, lam], dtype=tf.float64) - - with tf.GradientTape() as tape: - tape.watch(params) - res = cost(params) - - # check that the result is correct - expected_cost = (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) ** 2 - assert np.allclose(res.numpy(), expected_cost, atol=tol, rtol=0) - - res = tape.gradient(res, params) - - # check that the gradient is correct - expected_grad = ( - np.array( - [ - np.sin(theta) * np.cos(lam) * np.cos(phi), - np.cos(theta) * np.cos(lam) * np.sin(phi) + np.sin(lam) * np.cos(phi), - np.cos(theta) * np.sin(lam) * np.cos(phi) + np.cos(lam) * np.sin(phi), - ] - ) - * 2 - * (np.sin(lam) * np.sin(phi) - np.cos(theta) * np.cos(lam) * np.cos(phi)) - ) - assert np.allclose(res.numpy(), expected_grad, atol=tol, rtol=0) - - @pytest.mark.parametrize("interface", ["autograd", "torch"]) - def test_error_backprop_wrong_interface(self, interface, tol): - """Tests that an error is raised if diff_method='backprop' but not using - the TF interface""" - dev = qml.device("default.qubit.tf", wires=1) - - def circuit(x, w=None): - qml.RZ(x, wires=w) - return qml.expval(qml.PauliX(w)) - - with pytest.raises( - qml.QuantumFunctionError, - match="default.qubit.tf only supports diff_method='backprop' when using the tf interface", - ): - qml.qnode(dev, diff_method="backprop", interface=interface)(circuit) - - def test_hermitian_backprop(self, tol): - """Test that backprop with qml.Hermitian works correctly""" - dev = qml.device("default.qubit.tf", wires=2) - - K = tf.linalg.diag([1, 2, 3, 4]) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def circuit(op): - qml.PauliX(0) - qml.PauliX(1) - return qml.expval(op) - - res = circuit(qml.Hermitian(K, wires=range(2))) - assert isinstance(res, tf.Tensor) - assert res == 4.0 - - -@pytest.mark.tf -class TestSamples: - """Tests for sampling outputs""" - - def test_sample_observables(self): - """Test that the device allows for sampling from observables.""" - shots = 100 - dev = qml.device("default.qubit.tf", wires=2, shots=shots) - - @qml.qnode(dev, diff_method="best", interface="tf") - def circuit(a): - qml.RX(a, wires=0) - return qml.sample(qml.PauliZ(0)) - - a = tf.Variable(0.54, dtype=tf.float64) - res = circuit(a) - - assert isinstance(res, tf.Tensor) - assert res.shape == (shots,) - assert set(res.numpy()) == {-1, 1} - - def test_estimating_marginal_probability(self, tol): - """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(): - qml.PauliX(0) - return qml.probs(wires=[0]) - - res = circuit() - - assert isinstance(res, tf.Tensor) - - expected = np.array([0, 1]) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_estimating_full_probability(self, tol): - """Test that the probability of all wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(): - qml.PauliX(0) - qml.PauliX(1) - return qml.probs(wires=[0, 1]) - - res = circuit() - - assert isinstance(res, tf.Tensor) - - expected = np.array([0, 0, 0, 1]) - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_estimating_expectation_values(self, tol): - """Test that estimating expectation values using a finite number - of shots produces a numeric tensor""" - dev = qml.device("default.qubit.tf", wires=3, shots=1000) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(a, b): - qml.RX(a, wires=[0]) - qml.RX(b, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) - - a = tf.Variable(0.543, dtype=tf.float64) - b = tf.Variable(0.43, dtype=tf.float64) - - res = circuit(a, b) - assert isinstance(res, tuple) - - # We don't check the expected value due to stochasticity, but - # leave it here for completeness. - # expected = [tf.cos(a), tf.cos(a) * tf.cos(b)] - # assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.tf -class TestSamplesBroadcasted: - """Tests for broadcasted sampling outputs""" - - def test_sample_observables_broadcasted(self): - """Test that the device allows for broadcasted sampling from observables.""" - shots = 100 - dev = qml.device("default.qubit.tf", wires=2, shots=shots) - - @qml.qnode(dev, diff_method="best", interface="tf") - def circuit(a): - qml.RX(a, wires=0) - return qml.sample(qml.PauliZ(0)) - - a = tf.Variable([0.54, -0.32, 0.19], dtype=tf.float64) - res = circuit(a) - - assert isinstance(res, tf.Tensor) - assert res.shape == (3, shots) - assert set(res.numpy().flat) == {-1, 1} - - @pytest.mark.parametrize("batch_size", [2, 3]) - def test_estimating_marginal_probability_broadcasted(self, batch_size, tol): - """Test that the broadcasted probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(): - qml.RX(tf.zeros(batch_size), 0) - qml.PauliX(0) - return qml.probs(wires=[0]) - - res = circuit() - - assert isinstance(res, tf.Tensor) - assert qml.math.shape(res) == (batch_size, 2) - - expected = np.array([[0, 1]] * batch_size) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("batch_size", [2, 3]) - def test_estimating_full_probability_broadcasted(self, batch_size, tol): - """Test that the broadcasted probability of all wires is accurately estimated.""" - dev = qml.device("default.qubit.tf", wires=2, shots=1000) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(): - qml.RX(tf.zeros(batch_size), 0) - qml.PauliX(0) - qml.PauliX(1) - return qml.probs(wires=[0, 1]) - - res = circuit() - - assert isinstance(res, tf.Tensor) - assert qml.math.shape(res) == (batch_size, 4) - - expected = np.array([[0, 0, 0, 1]] * batch_size) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.skip("Parameter broadcasting is not supported for multiple return values yet") - @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) - def test_estimating_expectation_values_broadcasted(self, a, tol): - """Test that estimating broadcasted expectation values using a finite number - of shots produces a numeric tensor""" - batch_size = len(a) - dev = qml.device("default.qubit.tf", wires=3, shots=None) - - @qml.qnode(dev, diff_method=None, interface="tf") - def circuit(a, b): - qml.RX(a, wires=[0]) - qml.RX(b, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) - - a = tf.Variable(a, dtype=tf.float64) - b = tf.Variable(0.43, dtype=tf.float64) - - res = circuit(a, b) - assert isinstance(res, tf.Tensor) - assert qml.math.shape(res) == (batch_size, 2) - - -@pytest.mark.tf -def test_asarray_ragged_dtype_conversion(monkeypatch): - """Test that the _asarray internal method handles ragged arrays well when - the dtype argument was provided.""" - from tensorflow.python.framework.errors_impl import InvalidArgumentError - - dev = qml.device("default.qubit.tf", wires=2) - - def mock_func(arr, dtype): - raise InvalidArgumentError( - None, None, "SomeMessage" - ) # args passed are non-significant for test case - - monkeypatch.setattr(tf, "convert_to_tensor", mock_func) - res = dev._asarray(np.array([1]), tf.float32) - assert res.dtype == tf.float32 - - -@pytest.mark.tf -class TestGetBatchSize: - """Tests for the updated helper method ``_get_batch_size`` of ``DefaultQubitTF``.""" - - @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) - def test_batch_size_None(self, shape): - """Test that a ``batch_size=None`` is reported correctly.""" - dev = qml.device("default.qubit.tf", wires=2) - tensor0 = np.ones(shape, dtype=complex) - assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None - - @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) - @pytest.mark.parametrize("batch_size", [1, 3]) - def test_batch_size_int(self, shape, batch_size): - """Test that an integral ``batch_size`` is reported correctly.""" - dev = qml.device("default.qubit.tf", wires=2) - full_shape = (batch_size,) + shape - tensor0 = np.ones(full_shape, dtype=complex) - assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size - - def test_invalid_tensor(self): - """Test that an error is raised if a tensor is provided that does not - have a proper shape/ndim.""" - dev = qml.device("default.qubit.tf", wires=2) - with pytest.raises(ValueError, match="Can't convert non-rectangular Python"): - dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) - - @pytest.mark.parametrize("jit_compile", [True, False]) - def test_no_error_abstract_tensor(self, jit_compile): - """Test that no error is raised if an abstract tensor is provided""" - dev = qml.device("default.qubit.tf", wires=2) - signature = (tf.TensorSpec(shape=None, dtype=tf.float32),) - - @tf.function(jit_compile=jit_compile, input_signature=signature) - def get_batch_size(tensor): - return dev._get_batch_size(tensor, (2,), 2) - - assert get_batch_size(tf.Variable(0.2)) is None diff --git a/tests/devices/test_default_qubit_torch.py b/tests/devices/test_default_qubit_torch.py deleted file mode 100644 index b3b5266e390..00000000000 --- a/tests/devices/test_default_qubit_torch.py +++ /dev/null @@ -1,2492 +0,0 @@ -# Copyright 2018-2021 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 and integration tests for the ``default.qubit.torch`` device. -""" -# pylint: disable=too-many-arguments,too-many-public-methods,too-few-public-methods,protected-access -import math - -import numpy as np -import pytest -from gate_data import ( - CNOT, - CSWAP, - CZ, - CH, - SWAP, - ControlledPhaseShift, - CRot3, - CRotx, - CRoty, - CRotz, - DoubleExcitation, - DoubleExcitationMinus, - DoubleExcitationPlus, - H, - IsingXX, - IsingYY, - IsingZZ, - MultiRZ1, - MultiRZ2, - OrbitalRotation, - FermionicSWAP, - Rot3, - Rotx, - Roty, - Rotz, - Rphi, - S, - SingleExcitation, - SingleExcitationMinus, - SingleExcitationPlus, - T, - Toffoli, - CCZ, - X, - Y, - Z, -) - -import pennylane as qml -from pennylane import DeviceError -from pennylane import numpy as pnp - -torch = pytest.importorskip("torch", minversion="1.8.1") -from pennylane.devices.default_qubit_torch import ( # pylint: disable=wrong-import-position - DefaultQubitTorch, -) - -pytestmark = pytest.mark.gpu - -torch_devices = [None] - -if torch.cuda.is_available(): - torch_devices.append("cuda") - - -np.random.seed(42) - -##################################################### -# Test matrices -##################################################### - -U = np.array( - [ - [0.83645892 - 0.40533293j, -0.20215326 + 0.30850569j], - [-0.23889780 - 0.28101519j, -0.88031770 - 0.29832709j], - ] -) - -U2 = np.array([[0, 1, 1, 1], [1, 0, 1, -1], [1, -1, 0, 1], [1, 1, -1, 0]]) / np.sqrt(3) - -################################## -# Define standard qubit operations -################################## - -# Note: determining the torch device of the input parameters is done in the -# test cases - -single_qubit = [ - (qml.S, S), - (qml.T, T), - (qml.PauliX, X), - (qml.PauliY, Y), - (qml.PauliZ, Z), - (qml.Hadamard, H), -] - -single_qubit_param = [ - (qml.PhaseShift, Rphi), - (qml.RX, Rotx), - (qml.RY, Roty), - (qml.RZ, Rotz), - (qml.MultiRZ, MultiRZ1), -] -two_qubit = [(qml.CZ, CZ), (qml.CNOT, CNOT), (qml.SWAP, SWAP), (qml.CH, CH)] -two_qubit_param = [ - (qml.CRX, CRotx), - (qml.CRY, CRoty), - (qml.CRZ, CRotz), - (qml.IsingXX, IsingXX), - (qml.IsingYY, IsingYY), - (qml.IsingZZ, IsingZZ), - (qml.MultiRZ, MultiRZ2), - (qml.ControlledPhaseShift, ControlledPhaseShift), - (qml.SingleExcitation, SingleExcitation), - (qml.SingleExcitationPlus, SingleExcitationPlus), - (qml.SingleExcitationMinus, SingleExcitationMinus), - (qml.FermionicSWAP, FermionicSWAP), -] -three_qubit = [(qml.Toffoli, Toffoli), (qml.CSWAP, CSWAP), (qml.CCZ, CCZ)] -four_qubit_param = [ - (qml.DoubleExcitation, DoubleExcitation), - (qml.DoubleExcitationPlus, DoubleExcitationPlus), - (qml.DoubleExcitationMinus, DoubleExcitationMinus), - (qml.OrbitalRotation, OrbitalRotation), -] - - -##################################################### -# Fixtures -##################################################### - - -# pylint: disable=unused-argument -@pytest.fixture(name="init_state") -def init_state_fixture(scope="session"): - """Generates a random initial state""" - - def _init_state(n, torch_device): - """random initial state""" - torch.manual_seed(42) - state = torch.rand([2**n], dtype=torch.complex128) + torch.rand([2**n]) * 1j - state /= torch.linalg.norm(state) - return state.to(torch_device) - - return _init_state - - -# pylint: disable=unused-argument -@pytest.fixture(name="broadcasted_init_state") -def broadcasted_init_state_fixture(scope="session"): - """Generates a broadcasted random initial state""" - - def _broadcasted_init_state(n, batch_size, torch_device): - """random initial state""" - torch.manual_seed(42) - state = ( - torch.rand([batch_size, 2**n], dtype=torch.complex128) - + torch.rand([batch_size, 2**n]) * 1j - ) - state /= torch.linalg.norm(state, axis=1)[:, np.newaxis] - return state.to(torch_device) - - return _broadcasted_init_state - - -# pylint: disable=unused-argument -@pytest.fixture(name="device") -def device_fixture(scope="function"): - """Creates a Torch device""" - - def _dev(wires, torch_device=None): - """Torch device""" - dev = DefaultQubitTorch(wires=wires, torch_device=torch_device) - return dev - - return _dev - - -##################################################### -# Initialization test -##################################################### - - -@pytest.mark.torch -def test_analytic_deprecation(): - """Tests if the kwarg `analytic` is used and displays error message.""" - msg = "The analytic argument has been replaced by shots=None. " - msg += "Please use shots=None instead of analytic=True." - - with pytest.raises(DeviceError, match=msg): - qml.device("default.qubit.torch", wires=1, shots=1, analytic=True) - - -##################################################### -# Helper Method Test -##################################################### - - -def test_conj_helper_method(): - """Unittests the _conj helper method.""" - - dev = qml.device("default.qubit.torch", wires=1) - - x = qml.numpy.array(1.0 + 1j) - conj_x = dev._conj(x) - assert qml.math.allclose(conj_x, qml.math.conj(x)) - - -##################################################### -# Device-level integration tests -##################################################### - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestApply: - """Test application of PennyLane operations.""" - - def test_conj_array(self, device, torch_device, tol): - """Test using conj method from the device.""" - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([-1.0 + 1j, 1.0 + 1j], dtype=torch.complex128, device=torch_device) - assert torch.allclose( - dev._conj(state), - torch.tensor([-1.0 - 1j, 1.0 - 1j], dtype=torch.complex128, device=torch_device), - atol=tol, - rtol=0, - ) - - def test_basis_state(self, device, torch_device, tol): - """Test basis state initialization""" - - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([0, 0, 1, 0], dtype=torch.complex128, device=torch_device) - - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - res = dev.state - expected = torch.zeros([2**4], dtype=torch.complex128, device=torch_device) - expected[2] = 1 - - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_invalid_basis_state_length(self, device, torch_device): - """Test that an exception is raised if the basis state is the wrong size""" - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([0, 0, 1, 0]) - - with pytest.raises( - ValueError, match=r"BasisState parameter and wires must be of equal length" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) - - def test_invalid_basis_state(self, device, torch_device): - """Test that an exception is raised if the basis state is invalid""" - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([0, 0, 1, 2]) - - with pytest.raises( - ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - def test_qubit_state_vector(self, device, torch_device, init_state, tol): - """Test qubit state vector application""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - res = dev.state - expected = state - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_full_subsystem_statevector(self, device, torch_device, mocker): - """Test applying a state vector to the full subsystem""" - dev = device(wires=["a", "b", "c"], torch_device=torch_device) - state = ( - torch.tensor([1, 0, 0, 0, 1, 0, 1, 1], dtype=torch.complex128, device=torch_device) - / 2.0 - ) - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert torch.allclose(torch.reshape(dev._state, (-1,)), state) - spy.assert_not_called() - - def test_partial_subsystem_statevector(self, device, torch_device, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - dev = device(wires=["a", "b", "c"], torch_device=torch_device) - state = torch.tensor( - [1, 0, 1, 0], dtype=torch.complex128, device=torch_device - ) / torch.tensor(math.sqrt(2.0)) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = torch.reshape(torch.sum(dev._state, axis=(1,)), [-1]) - - assert torch.allclose(res, state) - spy.assert_called() - - def test_invalid_qubit_state_vector_size(self, device, torch_device): - """Test that an exception is raised if the state - vector is the wrong size""" - dev = device(wires=2, torch_device=torch_device) - state = torch.tensor([0, 1]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): - dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) - - @pytest.mark.parametrize( - "state", [torch.tensor([0, 12]), torch.tensor([1.0, -1.0], requires_grad=True)] - ) - def test_invalid_qubit_state_vector_norm(self, device, torch_device, state): - """Test that an exception is raised if the state - vector is not normalized""" - dev = device(wires=2, torch_device=torch_device) - - with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - def test_invalid_state_prep(self, device, torch_device): - """Test that an exception is raised if a state preparation is not the - first operation in the circuit.""" - dev = device(wires=2, torch_device=torch_device) - state = torch.tensor([0, 1]) - - with pytest.raises( - qml.DeviceError, - match=r"cannot be used after other Operations have already been applied", - ): - dev.apply([qml.PauliZ(0), qml.QubitStateVector(state, wires=[0])]) - - @pytest.mark.parametrize("op,mat", single_qubit) - def test_single_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): - """Test non-parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(wires=0)] - dev.apply(queue) - - res = dev.state - # assert mat.dtype == state.dtype - mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - expected = torch.matmul(mat, state) - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): - """Test parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(par, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) - expected = torch.matmul(op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation(self, device, torch_device, init_state, tol): - """Test three axis rotation gate""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) - b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(Rot3(a, b, c), dtype=torch.complex128, device=torch_device) - expected = op_mat @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation(self, device, torch_device, init_state, tol): - """Test three axis controlled-rotation gate""" - dev = device(wires=2, torch_device=torch_device) - state = init_state(2, torch_device=torch_device) - - a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) - b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) - expected = op_mat @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op,mat", two_qubit) - def test_two_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): - """Test non-parametrized two qubit operations""" - dev = device(wires=2, torch_device=torch_device) - state = init_state(2, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(wires=[0, 1])] - dev.apply(queue) - - res = dev.state - expected = torch.tensor(mat, dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary(self, device, torch_device, init_state, mat, tol): - """Test application of arbitrary qubit unitaries""" - N = int(math.log(len(mat), 2)) - - mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - dev = device(wires=N, torch_device=torch_device) - state = init_state(N, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = mat @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_diagonal_qubit_unitary(self, device, torch_device, init_state, tol): - """Tests application of a diagonal qubit unitary""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - diag = torch.tensor( - [-1.0 + 1j, 1.0 + 1j], requires_grad=True, dtype=torch.complex128, device=torch_device - ) / math.sqrt(2) - - queue = [qml.QubitStateVector(state, wires=0), qml.DiagonalQubitUnitary(diag, wires=0)] - dev.apply(queue) - - res = dev.state - expected = torch.diag(diag) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op, mat", three_qubit) - def test_three_qubit_no_parameters(self, device, torch_device, init_state, op, mat, tol): - """Test non-parametrized three qubit operations""" - dev = device(wires=3, torch_device=torch_device) - state = init_state(3, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] - queue += [op(wires=[0, 1, 2])] - dev.apply(queue) - - res = dev.state - expected = torch.tensor(mat, dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", two_qubit_param) - def test_two_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): - """Test two qubit parametrized operations""" - dev = device(wires=2, torch_device=torch_device) - state = init_state(2, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(theta, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) - expected = op_mat @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", four_qubit_param) - def test_four_qubit_parameters(self, device, torch_device, init_state, op, func, theta, tol): - """Test two qubit parametrized operations""" - dev = device(wires=4, torch_device=torch_device) - state = init_state(4, torch_device=torch_device) - - par = torch.tensor(theta, device=torch_device) - queue = [qml.QubitStateVector(state, wires=[0, 1, 2, 3])] - queue += [op(par, wires=[0, 1, 2, 3])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) - expected = op_mat @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_apply_ops_above_8_wires_using_special(self, device, torch_device): - """Test that special apply methods that involve slicing function correctly when using 9 - wires""" - dev = device(wires=9, torch_device=torch_device) - dev._apply_ops = {"CNOT": dev._apply_cnot} - - queue = [qml.CNOT(wires=[1, 2])] - dev.apply(queue) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestApplyBroadcasted: - """Test application of broadcasted PennyLane operations.""" - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_basis_state_broadcasted(self, device, torch_device, tol): - """Test basis state initialization""" - - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor( - [[0, 0, 1, 0], [1, 0, 0, 0]], dtype=torch.complex128, device=torch_device - ) - - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - res = dev.state - expected = torch.zeros([2**4], dtype=torch.complex128, device=torch_device) - expected[0, 2] = expected[1, 0] = 1 - - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_invalid_basis_state_length_broadcasted(self, device, torch_device): - """Test that an exception is raised if the basis state is the wrong size""" - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([0, 0, 1, 0, 1]) - - with pytest.raises( - ValueError, match=r"BasisState parameter and wires must be of equal length" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2])]) - - @pytest.mark.skip("Applying a BasisState does not support broadcasting yet") - def test_invalid_basis_state_broadcasted(self, device, torch_device): - """Test that an exception is raised if the basis state is invalid""" - dev = device(wires=4, torch_device=torch_device) - state = torch.tensor([0, 0, 1, 2]) - - with pytest.raises( - ValueError, match=r"BasisState parameter must consist of 0 or 1 integers" - ): - dev.apply([qml.BasisState(state, wires=[0, 1, 2, 3])]) - - @pytest.mark.parametrize("batch_size", [1, 3]) - def test_qubit_state_vector_broadcasted( - self, device, torch_device, broadcasted_init_state, batch_size, tol - ): - """Test broadcasted qubit state vector application""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, batch_size, torch_device=torch_device) - - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - res = dev.state - expected = state - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_full_subsystem_statevector_broadcasted(self, device, torch_device, mocker): - """Test applying a state vector to the full subsystem""" - dev = device(wires=["a", "b", "c"], torch_device=torch_device) - state = ( - torch.tensor( - [[1, 0, 0, 0, 1, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 1]], - dtype=torch.complex128, - device=torch_device, - ) - / 2 - ) - state_wires = qml.wires.Wires(["a", "b", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - - assert torch.allclose(torch.reshape(dev._state, [3, 8]), state) - spy.assert_not_called() - - def test_partial_subsystem_statevector_broadcasted(self, device, torch_device, mocker): - """Test applying a state vector to a subset of wires of the full subsystem""" - dev = device(wires=["a", "b", "c"], torch_device=torch_device) - state = torch.tensor( - [[1, 0, 1, 0], [1, 1, 0, 0], [0, 1, 1, 0]], dtype=torch.complex128, device=torch_device - ) / torch.tensor(math.sqrt(2.0)) - state_wires = qml.wires.Wires(["a", "c"]) - - spy = mocker.spy(dev, "_scatter") - dev._apply_state_vector(state=state, device_wires=state_wires) - res = torch.reshape(torch.sum(dev._state, axis=(2,)), [3, 4]) - - assert torch.allclose(res, state) - spy.assert_called() - - def test_invalid_qubit_state_vector_size_broadcasted(self, device, torch_device): - """Test that an exception is raised if the state - vector is the wrong size""" - dev = device(wires=2, torch_device=torch_device) - state = torch.tensor([[0, 1], [1, 0], [1, 1], [0, 0]]) - - with pytest.raises(ValueError, match=r"State vector must have shape \(2\*\*wires,\)"): - dev.apply([qml.QubitStateVector(state, wires=[0, 1])]) - - def test_invalid_qubit_state_vector_norm_broadcasted(self, device, torch_device): - """Test that an exception is raised if the state - vector is not normalized""" - dev = device(wires=2, torch_device=torch_device) - state = torch.tensor([[1, 0], [0, 12], [1.3, 1]], requires_grad=True) - - with pytest.raises(ValueError, match=r"Sum of amplitudes-squared does not equal one"): - dev.apply([qml.QubitStateVector(state, wires=[0])]) - - @pytest.mark.parametrize("op,mat", single_qubit) - def test_single_qubit_no_parameters_broadcasted( - self, device, torch_device, broadcasted_init_state, op, mat, tol - ): - """Test non-parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, 3, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(wires=0)] - dev.apply(queue) - - res = dev.state - mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,kj->ki", mat, state) - assert isinstance(res, torch.Tensor) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_state( - self, device, torch_device, broadcasted_init_state, op, func, theta, tol - ): - """Test parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, 3, torch_device=torch_device) - - par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(par, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,kj->ki", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_par( - self, device, torch_device, init_state, op, func, theta, tol - ): - """Test parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(par, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor( - np.array([func(t) for t in theta]), dtype=torch.complex128, device=torch_device - ) - expected = qml.math.einsum("lij,j->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [[np.pi / 3], [0.5432, -0.232, 0.1]]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_single_qubit_parameters_broadcasted_both( - self, device, torch_device, broadcasted_init_state, op, func, theta, tol - ): - """Test parametrized single qubit operations""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, 3, torch_device=torch_device) - - par = torch.tensor(theta, dtype=torch.complex128, device=torch_device) - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [op(par, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor( - np.array([func(t) for t in theta]), dtype=torch.complex128, device=torch_device - ) - expected = qml.math.einsum("lij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_state(self, device, torch_device, broadcasted_init_state, tol): - """Test three axis rotation gate""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, 3, torch_device=torch_device) - - a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) - b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(Rot3(a, b, c), dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_par(self, device, torch_device, init_state, tol): - """Test three axis rotation gate""" - dev = device(wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) - b = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.stack([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) - expected = qml.math.einsum("lij,j->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_rotation_broadcasted_both(self, device, torch_device, broadcasted_init_state, tol): - """Test three axis rotation gate""" - dev = device(wires=1, torch_device=torch_device) - state = broadcasted_init_state(1, 3, torch_device=torch_device) - - a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) - b = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0])] - queue += [qml.Rot(a, b, c, wires=0)] - dev.apply(queue) - - res = dev.state - op_mat = torch.stack([Rot3(_a, _b, c) for _a, _b in zip(a, b)]) - expected = qml.math.einsum("lij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_state( - self, device, torch_device, broadcasted_init_state, tol - ): - """Test three axis controlled-rotation gate""" - dev = device(wires=2, torch_device=torch_device) - state = broadcasted_init_state(2, 3, torch_device=torch_device) - - a = torch.tensor(0.542, dtype=torch.complex128, device=torch_device) - b = torch.tensor(1.3432, dtype=torch.complex128, device=torch_device) - c = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_par(self, device, torch_device, init_state, tol): - """Test three axis controlled-rotation gate""" - dev = device(wires=2, torch_device=torch_device) - state = init_state(2, torch_device=torch_device) - - a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) - b = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - c = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.stack([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) - expected = qml.math.einsum("lij,j->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_broadcasted_both( - self, device, torch_device, broadcasted_init_state, tol - ): - """Test three axis controlled-rotation gate""" - dev = device(wires=2, torch_device=torch_device) - state = broadcasted_init_state(2, 3, torch_device=torch_device) - - a = torch.tensor([0.542, 0.96, 0.213], dtype=torch.complex128, device=torch_device) - b = torch.tensor(-0.654, dtype=torch.complex128, device=torch_device) - c = torch.tensor([1.3432, 0.6324, 6.32], dtype=torch.complex128, device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [qml.CRot(a, b, c, wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.stack([CRot3(_a, b, _c) for _a, _c in zip(a, c)]) - expected = qml.math.einsum("lij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op,mat", two_qubit) - def test_two_qubit_no_parameters_broadcasted( - self, device, torch_device, broadcasted_init_state, op, mat, tol - ): - """Test non-parametrized two qubit operations""" - dev = device(wires=2, torch_device=torch_device) - state = broadcasted_init_state(2, 3, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1])] - queue += [op(wires=[0, 1])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_state( - self, device, torch_device, broadcasted_init_state, mat, tol - ): - """Test application of arbitrary qubit unitaries""" - N = int(math.log(len(mat), 2)) - - mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - dev = device(wires=N, torch_device=torch_device) - state = broadcasted_init_state(N, 3, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = qml.math.einsum("ij,lj->li", mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_par(self, device, torch_device, init_state, mat, tol): - """Test application of arbitrary qubit unitaries""" - N = int(math.log(len(mat), 2)) - - mat = torch.tensor([mat, mat, mat], dtype=torch.complex128, device=torch_device) - dev = device(wires=N, torch_device=torch_device) - state = init_state(N, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = qml.math.einsum("lij,j->li", mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("mat", [U, U2]) - def test_qubit_unitary_broadcasted_both( - self, device, torch_device, broadcasted_init_state, mat, tol - ): - """Test application of arbitrary qubit unitaries""" - N = int(math.log(len(mat), 2)) - - mat = torch.tensor([mat, mat, mat], dtype=torch.complex128, device=torch_device) - dev = device(wires=N, torch_device=torch_device) - state = broadcasted_init_state(N, 3, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=range(N))] - queue += [qml.QubitUnitary(mat, wires=range(N))] - dev.apply(queue) - - res = dev.state - expected = qml.math.einsum("lij,lj->li", mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("op, mat", three_qubit) - def test_three_qubit_no_parameters_broadcasted( - self, device, torch_device, broadcasted_init_state, op, mat, tol - ): - """Test non-parametrized three qubit operations""" - dev = device(wires=3, torch_device=torch_device) - state = broadcasted_init_state(3, 2, torch_device=torch_device) - - queue = [qml.QubitStateVector(state, wires=[0, 1, 2])] - queue += [op(wires=[0, 1, 2])] - dev.apply(queue) - - res = dev.state - op_mat = torch.tensor(mat, dtype=torch.complex128, device=torch_device) - expected = qml.math.einsum("ij,lj->li", op_mat, state) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_direct_eval_hamiltonian_broadcasted_error_torch(self, device, torch_device, mocker): - """Tests that an error is raised when attempting to evaluate a Hamiltonian with - broadcasting and shots=None directly via its sparse representation with torch.""" - - dev = device(wires=2, torch_device=torch_device) - ham = qml.Hamiltonian( - torch.tensor([0.1, 0.2], requires_grad=True), [qml.PauliX(0), qml.PauliZ(1)] - ) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(): - qml.RX(np.zeros(5), 0) # Broadcast the state by applying a broadcasted identity - return qml.expval(ham) - - with pytest.raises(NotImplementedError, match="Hamiltonians for interface!=None"): - circuit() - - -THETA = torch.linspace(0.11, 1, 3, dtype=torch.float64) -PHI = torch.linspace(0.32, 1, 3, dtype=torch.float64) -VARPHI = torch.linspace(0.02, 1, 3, dtype=torch.float64) - -scalar_angles = list(zip(THETA, PHI, VARPHI)) -broadcasted_angles = [(THETA, PHI, VARPHI), (THETA[0], PHI, VARPHI)] -all_angles = scalar_angles + broadcasted_angles - - -# pylint: disable=unused-argument -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -@pytest.mark.parametrize("theta, phi, varphi", all_angles) -class TestExpval: - """Test expectation values""" - - # test data; each tuple is of the form (GATE, OBSERVABLE, EXPECTED) - single_wire_expval_test_data = [ - ( - qml.RX, - qml.Identity, - lambda t, p, t_device: torch.tensor( - qml.math.stack([torch.ones_like(t) * torch.ones_like(p)] * 2), - dtype=torch.float64, - device=t_device, - ), - ), - ( - qml.RX, - qml.PauliZ, - lambda t, p, t_device: torch.tensor( - qml.math.stack([torch.cos(t) * torch.ones_like(p), torch.cos(t) * torch.cos(p)]), - dtype=torch.float64, - device=t_device, - ), - ), - ( - qml.RY, - qml.PauliX, - lambda t, p, t_device: torch.tensor( - qml.math.stack([torch.sin(t) * torch.sin(p), torch.sin(p) * torch.ones_like(t)]), - dtype=torch.float64, - device=t_device, - ), - ), - ( - qml.RX, - qml.PauliY, - lambda t, p, t_device: torch.tensor( - qml.math.stack( - [torch.zeros_like(p) * torch.zeros_like(t), -torch.cos(t) * torch.sin(p)] - ), - dtype=torch.float64, - device=t_device, - ), - ), - ( - qml.RY, - qml.Hadamard, - lambda t, p, t_device: torch.tensor( - qml.math.stack( - [ - torch.sin(t) * torch.sin(p) + torch.cos(t), - torch.cos(t) * torch.cos(p) + torch.sin(p), - ] - ), - dtype=torch.float64, - device=t_device, - ) - / math.sqrt(2), - ), - ] - - @pytest.mark.parametrize("gate,obs,expected", single_wire_expval_test_data) - def test_single_wire_expectation( - self, device, torch_device, gate, obs, expected, theta, phi, varphi, tol - ): - """Test that single qubit gates with single qubit expectation values""" - dev = device(wires=2, torch_device=torch_device) - if qml.math.ndim(theta) == 1 or qml.math.ndim(phi) == 1: - pytest.skip("Multiple return values are not supported with broadcasting") - - par1 = theta.to(device=torch_device) - par2 = phi.to(device=torch_device) - with qml.queuing.AnnotatedQueue() as q: - _ = [gate(par1, wires=0), gate(par2, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(obs(wires=[i])) for i in range(2)] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - - expected_res = expected(theta, phi, torch_device) - assert torch.allclose(qml.math.stack(res), expected_res, atol=tol, rtol=0) - - def test_hermitian_expectation(self, device, torch_device, theta, phi, varphi, tol): - """Test that arbitrary Hermitian expectation values are correct""" - if qml.math.ndim(theta) == 1 or qml.math.ndim(phi) == 1: - pytest.skip("Multiple return values are not supported with broadcasting") - dev = device(wires=2, torch_device=torch_device) - - Hermitian_mat = torch.tensor( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], - dtype=torch.complex128, - device=torch_device, - ) - - par1 = theta.to(device=torch_device) - par2 = phi.to(device=torch_device) - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RY(par1, wires=0), qml.RY(par2, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(qml.Hermitian(Hermitian_mat, wires=[i])) for i in range(2)] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - - a = Hermitian_mat[0, 0] - re_b = Hermitian_mat[0, 1].real - d = Hermitian_mat[1, 1] - ev1 = ( - (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d - ) / 2 - ev2 = ((a - d) * torch.cos(theta) * torch.cos(phi) + 2 * re_b * torch.sin(phi) + a + d) / 2 - expected = torch.tensor([ev1, ev2], dtype=torch.float64, device=torch_device) - - assert torch.allclose(qml.math.stack(res), expected, atol=tol, rtol=0) - - def test_do_not_split_analytic_torch( - self, device, torch_device, theta, phi, varphi, tol, mocker - ): - """Tests that the Hamiltonian is not split for shots=None using the Torch device.""" - - dev = device(wires=2, torch_device=torch_device) - ham = qml.Hamiltonian( - torch.tensor([0.1, 0.2], requires_grad=True), [qml.PauliX(0), qml.PauliZ(1)] - ) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(): - return qml.expval(ham) - - spy = mocker.spy(dev, "expval") - - circuit() - # evaluated one expval altogether - assert spy.call_count == 1 - - def test_multi_mode_hermitian_expectation(self, device, torch_device, theta, phi, varphi, tol): - """Test that arbitrary multi-mode Hermitian expectation values are correct""" - Hermit_mat2 = torch.tensor( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ], - dtype=torch.complex128, - ) - - dev = device(wires=2, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RY(theta, wires=0), qml.RY(phi, wires=1), qml.CNOT(wires=[0, 1])] - _ = [qml.expval(qml.Hermitian(Hermit_mat2, wires=[0, 1]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - - # below is the analytic expectation value for this circuit with arbitrary - # Hermitian observable Hermit_mat2 - expected = 0.5 * ( - 6 * torch.cos(theta) * torch.sin(phi) - - torch.sin(theta) * (8 * torch.sin(phi) + 7 * torch.cos(phi) + 3) - - 2 * torch.sin(phi) - - 6 * torch.cos(phi) - - 6 - ) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_paulix_pauliy(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = device(wires=3, torch_device=torch_device) - dev.reset() - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = torch.sin(theta) * torch.sin(phi) * torch.sin(varphi) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_identity(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = device(wires=3, torch_device=torch_device) - dev.reset() - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = torch.cos(varphi) * torch.cos(phi) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = device(wires=3, torch_device=torch_device) - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = -( - torch.cos(varphi) * torch.sin(phi) + torch.sin(varphi) * torch.cos(theta) - ) / math.sqrt(2) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = device(wires=3, torch_device=torch_device) - dev.reset() - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - Hermit_mat3 = torch.tensor( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ], - dtype=torch.complex128, - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(Hermit_mat3, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.5 * ( - -6 * torch.cos(theta) * (torch.cos(varphi) + 1) - - 2 * torch.sin(varphi) * (torch.cos(theta) + torch.sin(phi) - 2 * torch.cos(phi)) - + 3 * torch.cos(varphi) * torch.sin(phi) - + torch.sin(phi) - ) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_hermitian(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = device(wires=3, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - A1 = torch.tensor([[1, 2], [2, 4]], dtype=torch.complex128) - - A2 = torch.tensor( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ], - dtype=torch.complex128, - ) - A1 = A1.to(device=torch_device) - A2 = A2.to(device=torch_device) - - obs = qml.Hermitian(A1, wires=[0]) @ qml.Hermitian(A2, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - expected = 0.25 * ( - -30 - + 4 * torch.cos(phi) * torch.sin(theta) - + 3 - * torch.cos(varphi) - * (-10 + 4 * torch.cos(phi) * torch.sin(theta) - 3 * torch.sin(phi)) - - 3 * torch.sin(phi) - - 2 - * ( - 5 - + torch.cos(phi) * (6 + 4 * torch.sin(theta)) - + (-3 + 8 * torch.sin(theta)) * torch.sin(phi) - ) - * torch.sin(varphi) - + torch.cos(theta) - * ( - 18 - + 5 * torch.sin(phi) - + 3 * torch.cos(varphi) * (6 + 5 * torch.sin(phi)) - + 2 * (3 + 10 * torch.cos(phi) - 5 * torch.sin(phi)) * torch.sin(varphi) - ) - ) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian_identity_expectation(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = device(wires=2, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - - A = torch.tensor( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], - dtype=torch.complex128, - ) - A = A.to(device=torch_device) - - obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - expected = ( - (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d - ) / 2 - - assert torch.allclose(res, torch.real(expected), atol=tol, rtol=0) - - def test_hermitian_two_wires_identity_expectation( - self, device, torch_device, theta, phi, varphi, tol - ): - """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = device(wires=3, torch_device=torch_device) - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - - A = torch.tensor( - [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]], - dtype=torch.complex128, - ) - A = A.to(device=torch_device) - - Identity = torch.tensor([[1, 0], [0, 1]]) - Identity = Identity.to(device=torch_device) - - ham = torch.kron(torch.kron(Identity, Identity), A) - obs = qml.Hermitian(ham, wires=[2, 1, 0]) - - dev.apply( - [qml.RY(theta, wires=[0]), qml.RY(phi, wires=[1]), qml.CNOT(wires=[0, 1])], - obs.diagonalizing_gates(), - ) - res = dev.expval(obs) - - a = A[0, 0] - re_b = A[0, 1].real - d = A[1, 1] - - expected = ( - (a - d) * torch.cos(theta) + 2 * re_b * torch.sin(theta) * torch.sin(phi) + a + d - ) / 2 - assert torch.allclose(res, torch.real(expected), atol=tol, rtol=0) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -@pytest.mark.parametrize("theta, phi, varphi", all_angles) -class TestVar: - """Tests for the variance - - Note: the following tests use DefaultQubitTorch.execute that contains logic - to transfer tensors created by default on the CPU to the GPU. Therefore, gate - parameters do not have to explicitly be put on the GPU, it suffices to - specify torch_device='cuda' when creating the PennyLane device. - """ - - def test_var(self, device, torch_device, theta, phi, varphi, tol): - """Tests for variance calculation""" - dev = device(wires=1, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - - # test correct variance for of a rotated state - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RX(theta, wires=0), qml.RY(phi, wires=0)] - _ = [qml.var(qml.PauliZ(wires=[0]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - expected = 0.25 * ( - 3 - torch.cos(2 * theta) - 2 * torch.cos(theta) ** 2 * torch.cos(2 * phi) - ) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_var_hermitian(self, device, torch_device, theta, phi, varphi, tol): - """Tests for variance calculation using an arbitrary Hermitian observable""" - dev = device(wires=2, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - - # test correct variance for of a rotated state - ham = torch.tensor( - [[4, -1 + 6j], [-1 - 6j, 2]], dtype=torch.complex128, device=torch_device - ) - - with qml.queuing.AnnotatedQueue() as q: - _ = [qml.RX(phi, wires=0), qml.RY(theta, wires=0)] - _ = [qml.var(qml.Hermitian(ham, wires=[0]))] - - tape = qml.tape.QuantumScript.from_queue(q) - res = dev.execute(tape) - expected = 0.5 * ( - 2 * torch.sin(2 * theta) * torch.cos(phi) ** 2 - + 24 * torch.sin(phi) * torch.cos(phi) * (torch.sin(theta) - torch.cos(theta)) - + 35 * torch.cos(2 * phi) - + 39 - ) - expected = expected.to(device=torch_device) - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_paulix_pauliy(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = device(wires=3, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - obs = qml.PauliX(0) @ qml.PauliY(2) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 8 * torch.sin(theta) ** 2 * torch.cos(2 * varphi) * torch.sin(phi) ** 2 - - torch.cos(2 * (theta - phi)) - - torch.cos(2 * (theta + phi)) - + 2 * torch.cos(2 * theta) - + 2 * torch.cos(2 * phi) - + 14 - ) / 16 - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_pauliz_hadamard(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = device(wires=3, torch_device=torch_device) - obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - dev.reset() - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 3 - + torch.cos(2 * phi) * torch.cos(varphi) ** 2 - - torch.cos(2 * theta) * torch.sin(varphi) ** 2 - - 2 * torch.cos(theta) * torch.sin(phi) * torch.sin(2 * varphi) - ) / 4 - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_hermitian(self, device, torch_device, theta, phi, varphi, tol): - """Test that a tensor product involving qml.Hermitian works correctly""" - dev = device(wires=3, torch_device=torch_device) - - theta = theta.to(device=torch_device) - phi = phi.to(device=torch_device) - varphi = varphi.to(device=torch_device) - - A = torch.tensor( - [ - [-6, 2 + 1j, -3, -5 + 2j], - [2 - 1j, 0, 2 - 1j, -5 + 4j], - [-3, 2 + 1j, 0, -4 + 3j], - [-5 - 2j, -5 - 4j, -4 - 3j, -6], - ], - dtype=torch.complex128, - device=torch_device, - ) - - obs = qml.PauliZ(0) @ qml.Hermitian(A, wires=[1, 2]) - - dev.apply( - [ - qml.RX(theta, wires=[0]), - qml.RX(phi, wires=[1]), - qml.RX(varphi, wires=[2]), - qml.CNOT(wires=[0, 1]), - qml.CNOT(wires=[1, 2]), - ], - obs.diagonalizing_gates(), - ) - - res = dev.var(obs) - - expected = ( - 1057 - - torch.cos(2 * phi) - + 12 * (27 + torch.cos(2 * phi)) * torch.cos(varphi) - - 2 - * torch.cos(2 * varphi) - * torch.sin(phi) - * (16 * torch.cos(phi) + 21 * torch.sin(phi)) - + 16 * torch.sin(2 * phi) - - 8 * (-17 + torch.cos(2 * phi) + 2 * torch.sin(2 * phi)) * torch.sin(varphi) - - 8 * torch.cos(2 * theta) * (3 + 3 * torch.cos(varphi) + torch.sin(varphi)) ** 2 - - 24 * torch.cos(phi) * (torch.cos(phi) + 2 * torch.sin(phi)) * torch.sin(2 * varphi) - - 8 - * torch.cos(theta) - * ( - 4 - * torch.cos(phi) - * ( - 4 - + 8 * torch.cos(varphi) - + torch.cos(2 * varphi) - - (1 + 6 * torch.cos(varphi)) * torch.sin(varphi) - ) - + torch.sin(phi) - * ( - 15 - + 8 * torch.cos(varphi) - - 11 * torch.cos(2 * varphi) - + 42 * torch.sin(varphi) - + 3 * torch.sin(2 * varphi) - ) - ) - ) / 16 - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - -##################################################### -# QNode-level integration tests -##################################################### - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestQNodeIntegration: - """Integration tests for default.qubit.torch. This test ensures it integrates - properly with the PennyLane UI, in particular the new QNode.""" - - def test_defines_correct_capabilities(self, torch_device): - """Test that the device defines the right capabilities""" - - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - cap = dev.capabilities() - capabilities = { - "model": "qubit", - "supports_finite_shots": True, - "supports_tensor_observables": True, - "returns_probs": True, - "returns_state": True, - "supports_inverse_operations": True, - "supports_analytic_computation": True, - "supports_broadcasting": True, - "passthru_interface": "torch", - "passthru_devices": { - "torch": "default.qubit.torch", - "tf": "default.qubit.tf", - "autograd": "default.qubit.autograd", - "jax": "default.qubit.jax", - }, - } - assert cap == capabilities - - def test_load_torch_device(self, torch_device): - """Test that the torch device plugin loads correctly""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - assert dev.num_wires == 2 - assert dev.shots is None - assert dev.short_name == "default.qubit.torch" - assert dev.capabilities()["passthru_interface"] == "torch" - assert dev._torch_device == torch_device - - def test_qubit_circuit(self, torch_device, tol): - """Test that the torch device provides correct - result for a simple circuit using the old QNode.""" - p = torch.tensor(0.543, dtype=torch.float64, device=torch_device) - - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -torch.sin(p) - - assert circuit.gradient_fn == "backprop" - assert torch.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_qubit_circuit_broadcasted(self, torch_device, tol): - """Test that the torch device provides correct - result for a simple circuit using the old QNode.""" - p = torch.tensor([0.543, 0.21, 2.41], dtype=torch.float64, device=torch_device) - - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - expected = -torch.sin(p) - - assert circuit.gradient_fn == "backprop" - assert torch.allclose(circuit(p), expected, atol=tol, rtol=0) - - def test_correct_state(self, torch_device, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - state = dev.state - expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) - assert torch.allclose(state, expected, atol=tol, rtol=0) - - input_param = torch.tensor(math.pi / 4, device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(input_param, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - amplitude = np.exp(-1j * math.pi / 8) / math.sqrt(2) - - expected = torch.tensor( - [amplitude, 0, amplitude.conjugate(), 0], dtype=torch.complex128, device=torch_device - ) - assert torch.allclose(state, expected, atol=tol, rtol=0) - - def test_correct_state_broadcasted(self, torch_device, tol): - """Test that the device state is correct after applying a - quantum function on the device""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - state = dev.state - expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) - assert torch.allclose(state, expected, atol=tol, rtol=0) - - input_param = torch.tensor([math.pi / 4, math.pi / 2], device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(): - qml.Hadamard(wires=0) - qml.RZ(input_param, wires=0) - return qml.expval(qml.PauliZ(0)) - - circuit() - state = dev.state - - phase = np.exp(-1j * np.pi / 8) - - expected = torch.tensor( - [ - [phase / np.sqrt(2), 0, np.conj(phase) / np.sqrt(2), 0], - [phase**2 / np.sqrt(2), 0, np.conj(phase) ** 2 / np.sqrt(2), 0], - ], - dtype=torch.complex128, - device=torch_device, - ) - assert torch.allclose(state, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_param) - def test_one_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): - """Test the integration of the one-qubit single parameter rotations by passing - a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - state = init_state(1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(params): - qml.QubitStateVector(state, wires=[0]) - op(params[0], wires=[0]) - return qml.expval(qml.PauliZ(0)) - - params = torch.tensor([theta]) - circuit(params) - res = dev.state - expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, 4.213]) - @pytest.mark.parametrize("op,func", two_qubit_param) - def test_two_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): - """Test the integration of the two-qubit single parameter rotations by passing - a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - state = init_state(2, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1]) - op(params[0], wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - # Pass a Torch Variable to the qfunc - params = torch.tensor([theta], device=torch_device) - params = params.to(device=torch_device) - circuit(params) - res = dev.state - expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("theta", [0.5432, 4.213]) - @pytest.mark.parametrize("op,func", four_qubit_param) - def test_four_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): - """Test the integration of the four-qubit single parameter rotations by passing - a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=4, torch_device=torch_device) - state = init_state(4, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1, 2, 3]) - op(params[0], wires=[0, 1, 2, 3]) - return qml.expval(qml.PauliZ(0)) - - # Pass a Torch Variable to the qfunc - params = torch.tensor([theta], device=torch_device) - circuit(params) - res = dev.state - expected = torch.tensor(func(theta), dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_controlled_rotation_integration(self, torch_device, init_state, tol): - """Test the integration of the two-qubit controlled rotation by passing - a Torch data structure as a parameter""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - a = torch.tensor(1.7, device=torch_device) - b = torch.tensor(1.3432, device=torch_device) - c = torch.tensor(-0.654, device=torch_device) - state = init_state(2, torch_device=torch_device) - - @qml.qnode(dev, interface="torch") - def circuit(params): - qml.QubitStateVector(state, wires=[0, 1]) - qml.CRot(params[0], params[1], params[2], wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - # Pass a Torch Variable to the qfunc - params = torch.tensor([a, b, c], device=torch_device) - circuit(params) - res = dev.state - expected = torch.tensor(CRot3(a, b, c), dtype=torch.complex128, device=torch_device) @ state - assert torch.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestPassthruIntegration: - """Tests for integration with the PassthruQNode""" - - def test_jacobian_variable_multiply(self, torch_device, tol): - """Test that jacobian of a QNode with an attached default.qubit.torch device - gives the correct result in the case of parameters multiplied by scalars""" - x = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - y = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - z = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit([x, y, z]) - res.backward() - - expected = torch.cos(3 * x) * torch.cos(y) * torch.cos(z / 2) - torch.sin( - 3 * x - ) * torch.sin(z / 2) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - x_grad = -3 * ( - torch.sin(3 * x) * torch.cos(y) * torch.cos(z / 2) + torch.cos(3 * x) * torch.sin(z / 2) - ) - y_grad = -torch.cos(3 * x) * torch.sin(y) * torch.cos(z / 2) - z_grad = -0.5 * ( - torch.sin(3 * x) * torch.cos(z / 2) + torch.cos(3 * x) * torch.cos(y) * torch.sin(z / 2) - ) - - assert torch.allclose(x.grad, x_grad) - assert torch.allclose(y.grad, y_grad) - assert torch.allclose(z.grad, z_grad) - - def test_jacobian_variable_multiply_broadcasted(self, torch_device, tol): - """Test that jacobian of a QNode with an attached default.qubit.torch device - gives the correct result in the case of parameters multiplied by scalars""" - x = torch.tensor( - [0.431, 92.1, -0.5129], dtype=torch.float64, requires_grad=True, device=torch_device - ) - y = torch.tensor( - [0.2162158, 0.241, -0.51], dtype=torch.float64, requires_grad=True, device=torch_device - ) - z = torch.tensor( - [0.75110998, 0.12512, 9.12], - dtype=torch.float64, - requires_grad=True, - device=torch_device, - ) - - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(p): - qml.RX(3 * p[0], wires=0) - qml.RY(p[1], wires=0) - qml.RX(p[2] / 2, wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit([x, y, z]) - - expected = torch.cos(3 * x) * torch.cos(y) * torch.cos(z / 2) - torch.sin( - 3 * x - ) * torch.sin(z / 2) - assert qml.math.shape(res) == (3,) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - jac = torch.autograd.functional.jacobian(circuit, (qml.math.stack([x, y, z]),))[0] - expected = qml.math.stack( - [ - -3 - * ( - torch.sin(3 * x) * torch.cos(y) * torch.cos(z / 2) - + torch.cos(3 * x) * torch.sin(z / 2) - ), - -torch.cos(3 * x) * torch.sin(y) * torch.cos(z / 2), - -0.5 - * ( - torch.sin(3 * x) * torch.cos(z / 2) - + torch.cos(3 * x) * torch.cos(y) * torch.sin(z / 2) - ), - ] - ) - - assert all(torch.allclose(jac[i, :, i], expected[:, i], atol=tol, rtol=0) for i in range(3)) - - def test_jacobian_repeated(self, torch_device, tol): - """Test that jacobian of a QNode with an attached default.qubit.torch device - gives the correct result in the case of repeated parameters""" - x = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - y = torch.tensor(0.2162158, dtype=torch.float64, requires_grad=True, device=torch_device) - z = torch.tensor(0.75110998, dtype=torch.float64, requires_grad=True, device=torch_device) - p = torch.tensor([x, y, z], requires_grad=True, device=torch_device) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - res.backward() - - expected = torch.cos(y) ** 2 - torch.sin(x) * torch.sin(y) ** 2 - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - expected_grad = torch.tensor( - [ - -torch.cos(x) * torch.sin(y) ** 2, - -2 * (torch.sin(x) + 1) * torch.sin(y) * torch.cos(y), - 0, - ], - dtype=torch.float64, - device=torch_device, - ) - assert torch.allclose(p.grad, expected_grad, atol=tol, rtol=0) - - def test_jacobian_repeated_broadcasted(self, torch_device, tol): - """Test that jacobian of a QNode with an attached default.qubit.torch device - gives the correct result in the case of repeated parameters""" - p = torch.tensor( - [[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]], - dtype=torch.float64, - device=torch_device, - requires_grad=True, - ) - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(x): - qml.RX(x[1], wires=0) - qml.Rot(x[0], x[1], x[2], wires=0) - return qml.expval(qml.PauliZ(0)) - - res = circuit(p) - - x, y, _ = p - expected = torch.cos(y) ** 2 - torch.sin(x) * torch.sin(y) ** 2 - - assert torch.allclose(res, expected, atol=tol, rtol=0) - - jac = torch.autograd.functional.jacobian(circuit, (p,))[0] - expected_jac = torch.stack( - [ - -torch.cos(x) * torch.sin(y) ** 2, - -2 * (torch.sin(x) + 1) * torch.sin(y) * torch.cos(y), - torch.zeros_like(x) * torch.zeros_like(y), - ], - ) - assert all( - torch.allclose(jac[i, :, i], expected_jac[:, i], atol=tol, rtol=0) for i in range(3) - ) - - def test_jacobian_agrees_backprop_parameter_shift(self, torch_device, tol): - """Test that jacobian of a QNode with an attached default.qubit.torch device - gives the correct result with respect to the parameter-shift method""" - p = pnp.array([0.43316321, 0.2162158, 0.75110998, 0.94714242], requires_grad=True) - - def circuit(x): - for i in range(0, len(p), 2): - qml.RX(x[i], wires=0) - qml.RY(x[i + 1], wires=1) - for i in range(2): - qml.CNOT(wires=[i, i + 1]) - return qml.expval(qml.PauliZ(0)) # , qml.var(qml.PauliZ(1)) - - dev1 = qml.device("default.qubit.torch", wires=3, torch_device=torch_device) - dev2 = qml.device("default.qubit", wires=3) - - circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="torch") - circuit2 = qml.QNode(circuit, dev2, diff_method="parameter-shift") - - p_torch = torch.tensor(p, requires_grad=True, device=torch_device) - res = circuit1(p_torch) - res.backward() - - assert qml.math.allclose(res, circuit2(p), atol=tol, rtol=0) - - p_grad = p_torch.grad - assert qml.math.allclose(p_grad, qml.jacobian(circuit2)(p), atol=tol, rtol=0) - - @pytest.mark.parametrize("wires", [[0], ["abc"]]) - def test_state_differentiability(self, torch_device, wires, tol): - """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.torch", wires=wires, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a): - qml.RY(a, wires=wires[0]) - return qml.state() - - a = torch.tensor(0.54, requires_grad=True, device=torch_device) - - res = torch.abs(circuit(a)) ** 2 - res = res[1] - res[0] - res.backward() - - grad = a.grad - expected = torch.sin(a) - assert torch.allclose(grad, expected, atol=tol, rtol=0) - - def test_state_differentiability_broadcasted(self, torch_device, tol): - """Test that the device state can be differentiated""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a): - qml.RY(a, wires=0) - return qml.expval(qml.PauliZ(0)) - - a = torch.tensor([0.54, 0.32, 1.2], requires_grad=True, device=torch_device) - - def cost(a): - circuit(a) - res = torch.abs(dev.state) ** 2 - return res[:, 1] - res[:, 0] - - jac = torch.autograd.functional.jacobian(cost, (a,))[0] - expected = torch.sin(a) - assert torch.allclose(qml.math.diag(jac), expected, atol=tol, rtol=0) - - def test_prob_differentiability(self, torch_device, tol): - """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = torch.tensor(0.54, requires_grad=True, dtype=torch.float64, device=torch_device) - b = torch.tensor(0.12, requires_grad=True, dtype=torch.float64, device=torch_device) - - # 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.backward() - - expected = -torch.cos(a) * torch.cos(b) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - assert torch.allclose(a.grad, torch.sin(a) * torch.cos(b), atol=tol, rtol=0) - assert torch.allclose(b.grad, torch.cos(a) * torch.sin(b), atol=tol, rtol=0) - - def test_prob_differentiability_broadcasted(self, torch_device, tol): - """Test that the device probability can be differentiated""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a, b): - qml.RX(a, wires=0) - qml.RY(b, wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[1]) - - a = torch.tensor( - [0.54, 0.32, 1.2], requires_grad=True, dtype=torch.float64, device=torch_device - ) - b = torch.tensor(0.12, requires_grad=True, dtype=torch.float64, device=torch_device) - - 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] - return res - - res = cost(a, b) - expected = -torch.cos(a) * torch.cos(b) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - jac = torch.autograd.functional.jacobian(cost, (a, b)) - assert torch.allclose(qml.math.diag(jac[0]), torch.sin(a) * torch.cos(b), atol=tol, rtol=0) - assert torch.allclose(jac[1], torch.cos(a) * torch.sin(b), atol=tol, rtol=0) - - def test_backprop_gradient(self, torch_device, tol): - """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = torch.tensor(-0.234, dtype=torch.float64, requires_grad=True, device=torch_device) - b = torch.tensor(0.654, dtype=torch.float64, requires_grad=True, device=torch_device) - - res = circuit(a, b) - res.backward() - - # 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) - - assert torch.allclose(res, expected_cost, atol=tol, rtol=0) - - assert torch.allclose(a.grad, -0.5 * torch.sin(a) * (torch.cos(b) + 1), atol=tol, rtol=0) - assert torch.allclose(b.grad, 0.5 * torch.sin(b) * (1 - torch.cos(a))) - - def test_backprop_gradient_broadcasted(self, torch_device, tol): - """Tests that the gradient of the qnode is correct""" - dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) - - @qml.qnode(dev, diff_method="backprop", interface="torch") - def circuit(a, b): - qml.RX(a, wires=0) - qml.CRX(b, wires=[0, 1]) - return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) - - a = torch.tensor(-0.234, dtype=torch.float64, requires_grad=True, device=torch_device) - b = torch.tensor( - [0.54, 0.32, 1.2], dtype=torch.float64, requires_grad=True, device=torch_device - ) - - res = circuit(a, b) - # 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) - - assert torch.allclose(res, expected_cost, atol=tol, rtol=0) - - jac = torch.autograd.functional.jacobian(circuit, (a, b)) - assert torch.allclose(jac[0], -0.5 * torch.sin(a) * (torch.cos(b) + 1), atol=tol, rtol=0) - assert torch.allclose(qml.math.diag(jac[1]), 0.5 * torch.sin(b) * (1 - torch.cos(a))) - - @pytest.mark.parametrize("x, shift", [(0.0, 0.0), (0.5, -0.5)]) - def test_hessian_at_zero(self, torch_device, x, shift): - """Tests that the Hessian at vanishing state vector amplitudes - is correct.""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - x = torch.tensor(x, requires_grad=True) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(x): - qml.RY(shift, wires=0) - qml.RY(x, wires=0) - return qml.expval(qml.PauliZ(0)) - - grad = torch.autograd.functional.jacobian(circuit, x) - hess = torch.autograd.functional.hessian(circuit, x) - - assert qml.math.isclose(grad, torch.tensor(0.0)) - assert qml.math.isclose(hess, torch.tensor(-1.0)) - - @pytest.mark.parametrize("operation", [qml.U3, qml.U3.compute_decomposition]) - @pytest.mark.parametrize("diff_method", ["backprop", "parameter-shift", "finite-diff"]) - def test_torch_interface_gradient(self, torch_device, operation, diff_method, tol): - """Tests that the gradient of an arbitrary U3 gate is correct - using the PyTorch interface, using a variety of differentiation methods.""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - input_state = torch.tensor(1j * np.array([1, -1]) / math.sqrt(2), device=torch_device) - - @qml.qnode(dev, diff_method=diff_method, interface="torch") - def circuit(x, weights, w): - """In this example, a mixture of scalar - arguments, array arguments, and keyword arguments are used.""" - qml.QubitStateVector(input_state, wires=w) - operation(x, weights[0], weights[1], wires=w) - return qml.expval(qml.PauliX(w)) - - # Check that the correct QNode type is being used. - if diff_method == "backprop": - assert circuit.gradient_fn == "backprop" - elif diff_method == "finite-diff": - assert circuit.gradient_fn is qml.gradients.finite_diff - - def cost(params): - """Perform some classical processing""" - return circuit(params[0], params[1:], w=0) ** 2 - - theta = torch.tensor(0.543, dtype=torch.float64, device=torch_device) - phi = torch.tensor(-0.234, dtype=torch.float64, device=torch_device) - lam = torch.tensor(0.654, dtype=torch.float64, device=torch_device) - - params = torch.tensor( - [theta, phi, lam], dtype=torch.float64, requires_grad=True, device=torch_device - ) - - res = cost(params) - res.backward() - - # check that the result is correct - expected_cost = ( - torch.sin(lam) * torch.sin(phi) - torch.cos(theta) * torch.cos(lam) * torch.cos(phi) - ) ** 2 - assert torch.allclose(res, expected_cost, atol=tol, rtol=0) - - # check that the gradient is correct - expected_grad = ( - torch.tensor( - [ - torch.sin(theta) * torch.cos(lam) * torch.cos(phi), - torch.cos(theta) * torch.cos(lam) * torch.sin(phi) - + torch.sin(lam) * torch.cos(phi), - torch.cos(theta) * torch.sin(lam) * torch.cos(phi) - + torch.cos(lam) * torch.sin(phi), - ], - device=torch_device, - ) - * 2 - * (torch.sin(lam) * torch.sin(phi) - torch.cos(theta) * torch.cos(lam) * torch.cos(phi)) - ) - assert torch.allclose(params.grad, expected_grad, atol=tol, rtol=0) - - @pytest.mark.parametrize("interface", ["autograd", "torch"]) - def test_error_backprop_wrong_interface(self, torch_device, interface): - """Tests that an error is raised if diff_method='backprop' but not using - the torch interface""" - dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) - - def circuit(x, w=None): - qml.RZ(x, wires=w) - return qml.expval(qml.PauliX(w)) - - with pytest.raises(Exception) as e: - assert qml.qnode(dev, diff_method="autograd", interface=interface)(circuit) - assert str(e.value) == ( - "Differentiation method autograd not recognized. Allowed options are ('best', " - "'parameter-shift', 'backprop', 'finite-diff', 'device', 'adjoint', 'spsa', 'hadamard')." - ) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestSamples: - """Tests for sampling outputs""" - - def test_sample_observables(self, torch_device): - """Test that the device allows for sampling from observables.""" - shots = 100 - dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(a): - qml.RX(a, wires=0) - return qml.sample(qml.PauliZ(0)) - - a = torch.tensor(0.54, dtype=torch.float64, device=torch_device) - res = circuit(a) - - assert torch.is_tensor(res) - assert res.shape == (shots,) - assert torch.allclose( - torch.unique(res), torch.tensor([-1, 1], dtype=torch.int64, device=torch_device) - ) - - def test_estimating_marginal_probability(self, torch_device, tol): - """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(): - qml.PauliX(0) - return qml.probs(wires=[0]) - - res = circuit() - - assert torch.is_tensor(res) - - expected = torch.tensor([0, 1], dtype=torch.float64, device=torch_device) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_estimating_full_probability(self, torch_device, tol): - """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(): - qml.PauliX(0) - qml.PauliX(1) - return qml.probs(wires=[0, 1]) - - res = circuit() - - assert torch.is_tensor(res) - - expected = torch.tensor([0, 0, 0, 1], dtype=torch.float64, device=torch_device) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - def test_estimating_expectation_values(self, torch_device): - """Test that estimating expectation values using a finite number - of shots produces a numeric tensor""" - dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(a, b): - qml.RX(a, wires=[0]) - qml.RX(b, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) - - a = torch.tensor(0.543, dtype=torch.float64, device=torch_device) - b = torch.tensor(0.43, dtype=torch.float64, device=torch_device) - - res = circuit(a, b) - assert isinstance(res, tuple) - - # We don't check the expected value due to stochasticity, but - # leave it here for completeness. - # expected = [torch.cos(a), torch.cos(a) * torch.cos(b)] - # assert np.allclose(res, expected, atol=tol, rtol=0) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestSamplesBroadcasted: - """Tests for sampling outputs""" - - @pytest.mark.skip("Sampling from observables is not supported with broadcasting") - @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) - def test_sample_observables_broadcasted(self, torch_device, a): - """Test that the device allows for sampling from observables.""" - batch_size = len(a) - shots = 100 - dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(a): - qml.RX(a, wires=0) - return qml.sample(qml.PauliZ(0)) - - a = torch.tensor(a, dtype=torch.float64, device=torch_device) - res = circuit(a) - - assert torch.is_tensor(res) - assert res.shape == (batch_size, shots) - assert torch.allclose( - torch.unique(res), torch.tensor([-1, 1], dtype=torch.int64, device=torch_device) - ) - - @pytest.mark.parametrize("batch_size", [2, 3]) - def test_estimating_marginal_probability_broadcasted(self, torch_device, batch_size, tol): - """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(): - qml.RX(torch.zeros(batch_size), 0) - qml.PauliX(0) - return qml.probs(wires=[0]) - - res = circuit() - - assert torch.is_tensor(res) - assert qml.math.shape(res) == (batch_size, 2) - - expected = torch.tensor([[0, 1]] * batch_size, dtype=torch.float64, device=torch_device) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("batch_size", [2, 3]) - def test_estimating_full_probability_broadcasted(self, torch_device, batch_size, tol): - """Test that the probability of a subset of wires is accurately estimated.""" - dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(): - qml.RX(torch.zeros(batch_size), 0) - qml.PauliX(0) - qml.PauliX(1) - return qml.probs(wires=[0, 1]) - - res = circuit() - - assert torch.is_tensor(res) - assert qml.math.shape(res) == (batch_size, 4) - - expected = torch.tensor( - [[0, 0, 0, 1]] * batch_size, dtype=torch.float64, device=torch_device - ) - assert torch.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.skip("Multiple return values are not supported with broadcasting") - @pytest.mark.parametrize("a", [[0.54, -0.32, 0.19], [0.52]]) - def test_estimating_expectation_values_broadcasted(self, torch_device, a): - """Test that estimating expectation values using a finite number - of shots produces a numeric tensor""" - batch_size = len(a) - dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) - - @qml.qnode(dev, diff_method=None, interface="torch") - def circuit(a, b): - qml.RX(a, wires=[0]) - qml.RX(b, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)) - - a = torch.tensor(a, dtype=torch.float64, device=torch_device) - b = torch.tensor(0.43, dtype=torch.float64, device=torch_device) - - res = circuit(a, b) - assert torch.is_tensor(res) - assert qml.math.shape(res) == (batch_size, 2) - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestHighLevelIntegration: - """Tests for integration with higher level components of PennyLane.""" - - def test_sampling_analytic_mode(self, torch_device): - """Test that when sampling with shots=None, dev uses 1000 shots and - raises an error. - """ - dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(): - return qml.sample(qml.PauliZ(wires=0)) - - with pytest.raises( - qml.QuantumFunctionError, - match="The number of shots has to be explicitly set on the device", - ): - circuit() - - def test_sampling_analytic_mode_with_counts(self, torch_device): - """Test that when sampling with counts and shots=None an error is raised.""" - dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(): - return qml.counts(qml.PauliZ(wires=0)) - - with pytest.raises( - qml.QuantumFunctionError, - match="The number of shots has to be explicitly set on the device " - "when using sample-based measurements.", - ): - circuit() - - -@pytest.mark.torch -@pytest.mark.parametrize("torch_device", torch_devices) -class TestCtrlOperator: - """Test-case for qml.ctrl operator with in-built parametric gates.""" - - @pytest.mark.parametrize( - "ops", - [ - ( - qml.RX, - torch.tensor( - [ - 0.70172985 - 0.08687008j, - -0.0053667 + 0.0j, - 0.70039457 - 0.08703569j, - 0.0 - 0.04326927j, - ], - dtype=torch.complex128, - ), - ), - ( - qml.RY, - torch.tensor( - [ - 0.70172985 - 0.08687008j, - 0.0 - 0.0053667j, - 0.70039457 - 0.08703569j, - 0.04326927 + 0.0j, - ], - dtype=torch.complex128, - ), - ), - ( - qml.RZ, - torch.tensor( - [0.69636316 - 0.08687008j, 0.0 + 0.0j, 0.70039457 - 0.13030496j, 0.0 + 0.0j], - dtype=torch.complex128, - ), - ), - ], - ) - def test_ctrl_r_operators(self, torch_device, ops, tol): - """Test qml.ctrl using R-gate targets""" - dev = qml.device("default.qubit.torch", wires=2, shots=None, torch_device=torch_device) - par = torch.tensor([0.12345, 0.2468], dtype=torch.float64, device=torch_device) - - @qml.qnode(dev, interface="torch", diff_method="backprop") - def circuit(params): - qml.Hadamard(0) - qml.ctrl(op=ops[0](params[0], wires=1), control=0) - qml.RX(params[1], wires=0) - return qml.state() - - result = circuit(par) - assert torch.allclose( - result, - ops[1].to(device=torch_device), - atol=tol, - rtol=0, - ) From 42ea50f95403545489f78cf71e612fed8346f7d7 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 3 Aug 2023 10:02:09 -0400 Subject: [PATCH 03/78] a few test fixes --- pennylane/ops/qubit/matrix_ops.py | 4 +++- pennylane/transforms/specs.py | 4 ++-- tests/ops/qubit/test_sparse.py | 15 ++++++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pennylane/ops/qubit/matrix_ops.py b/pennylane/ops/qubit/matrix_ops.py index 083e984cb50..82987a43448 100644 --- a/pennylane/ops/qubit/matrix_ops.py +++ b/pennylane/ops/qubit/matrix_ops.py @@ -293,7 +293,9 @@ def compute_matrix(D): # pylint: disable=arguments-differ """ D = qml.math.asarray(D) - if not qml.math.allclose(D * qml.math.conj(D), qml.math.ones_like(D)): + if not qml.math.is_abstract(D) and not qml.math.allclose( + D * qml.math.conj(D), qml.math.ones_like(D) + ): raise ValueError("Operator must be unitary.") # The diagonal is supposed to have one-dimension. If it is broadcasted, it has two diff --git a/pennylane/transforms/specs.py b/pennylane/transforms/specs.py index e508b808a46..29fe2c2fc37 100644 --- a/pennylane/transforms/specs.py +++ b/pennylane/transforms/specs.py @@ -123,8 +123,8 @@ def specs_qnode(*args, **kwargs): info = qnode.qtape.specs.copy() - info["num_device_wires"] = qnode.device.num_wires - info["device_name"] = qnode.device.short_name + info["num_device_wires"] = getattr(qnode.device, "num_wires", None) + info["device_name"] = getattr(qnode.device, "short_name", qnode.device.name) info["expansion_strategy"] = qnode.expansion_strategy info["gradient_options"] = qnode.gradient_kwargs info["interface"] = qnode.interface 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) From 840f30adf5aaa2d4e2a63fd6d4a942cbeeada6a3 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 3 Aug 2023 12:16:18 -0400 Subject: [PATCH 04/78] add is_state_batched to mp.process_state; probs supports jitting --- pennylane/devices/qubit/measure.py | 4 +++- pennylane/devices/qubit/sampling.py | 4 +++- pennylane/devices/tests/test_measurements.py | 4 ++-- pennylane/measurements/expval.py | 12 +++++++++--- pennylane/measurements/measurements.py | 10 +++++++--- pennylane/measurements/mutual_info.py | 4 +++- pennylane/measurements/probs.py | 13 ++++--------- pennylane/measurements/purity.py | 4 +++- pennylane/measurements/state.py | 4 +++- pennylane/measurements/var.py | 12 +++++++++--- pennylane/measurements/vn_entropy.py | 4 +++- 11 files changed, 49 insertions(+), 26 deletions(-) diff --git a/pennylane/devices/qubit/measure.py b/pennylane/devices/qubit/measure.py index e30a0c809b0..fc35d861661 100644 --- a/pennylane/devices/qubit/measure.py +++ b/pennylane/devices/qubit/measure.py @@ -49,7 +49,9 @@ def state_diagonalizing_gates( flattened_state = ( math.reshape(state, (state.shape[0], -1)) if is_state_batched else math.flatten(state) ) - return measurementprocess.process_state(flattened_state, wires) + return measurementprocess.process_state( + flattened_state, wires, is_state_batched=is_state_batched + ) def csr_dot_products( diff --git a/pennylane/devices/qubit/sampling.py b/pennylane/devices/qubit/sampling.py index 13b99ea8999..f53acbcc5f7 100644 --- a/pennylane/devices/qubit/sampling.py +++ b/pennylane/devices/qubit/sampling.py @@ -210,7 +210,9 @@ def sample_state( num_wires = len(wires_to_sample) basis_states = np.arange(2**num_wires) - probs = qml.probs(wires=wires_to_sample).process_state(state, state_wires) + probs = qml.probs(wires=wires_to_sample).process_state( + state, state_wires, is_state_batched=is_state_batched + ) if is_state_batched: # rng.choice doesn't support broadcasting diff --git a/pennylane/devices/tests/test_measurements.py b/pennylane/devices/tests/test_measurements.py index 203305c0f96..69c8debb121 100644 --- a/pennylane/devices/tests/test_measurements.py +++ b/pennylane/devices/tests/test_measurements.py @@ -1680,7 +1680,7 @@ def test_custom_state_measurement(self, device): class MyMeasurement(StateMeasurement): """Dummy state measurement.""" - def process_state(self, state, wire_order): + def process_state(self, state, wire_order, is_state_batched=False): return 1 @qml.qnode(dev) @@ -1701,7 +1701,7 @@ def test_sample_measurement_with_shots(self, device): class MyMeasurement(StateMeasurement): """Dummy state measurement.""" - def process_state(self, state, wire_order): + def process_state(self, state, wire_order, is_state_batched=False): return 1 @qml.qnode(dev) diff --git a/pennylane/measurements/expval.py b/pennylane/measurements/expval.py index e696546ff56..267797d9c56 100644 --- a/pennylane/measurements/expval.py +++ b/pennylane/measurements/expval.py @@ -121,15 +121,21 @@ def process_samples( # TODO: do we need to squeeze here? Maybe remove with new return types return qml.math.squeeze(qml.math.mean(samples, axis=axis)) - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): if isinstance(self.obs, Projector): # branch specifically to handle the projector observable idx = int("".join(str(i) for i in self.obs.parameters[0]), 2) - probs = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) + probs = qml.probs(wires=self.wires).process_state( + state=state, wire_order=wire_order, is_state_batched=is_state_batched + ) return probs[idx] eigvals = qml.math.asarray(self.obs.eigvals(), dtype="float64") # we use ``self.wires`` instead of ``self.obs`` because the observable was # already applied to the state - prob = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) + prob = qml.probs(wires=self.wires).process_state( + state=state, wire_order=wire_order, is_state_batched=is_state_batched + ) # In case of broadcasting, `prob` has two axes and this is a matrix-vector product return qml.math.dot(prob, eigvals) diff --git a/pennylane/measurements/measurements.py b/pennylane/measurements/measurements.py index 5391b860520..2c0c075d70e 100644 --- a/pennylane/measurements/measurements.py +++ b/pennylane/measurements/measurements.py @@ -543,16 +543,17 @@ class StateMeasurement(MeasurementProcess): * state (Sequence[complex]): quantum state * wire_order (Wires): wires determining the subspace that ``state`` acts on; a matrix of dimension :math:`2^n` acts on a subspace of :math:`n` wires + * is_state_batched (Optional[bool]): whether the state is batched or not **Example:** Let's create a measurement that returns the diagonal of the reduced density matrix. >>> class MyMeasurement(StateMeasurement): - ... def process_state(self, state, wire_order): + ... def process_state(self, state, wire_order, is_state_batched=False): ... # use the already defined `qml.density_matrix` measurement to compute the ... # reduced density matrix from the given state - ... density_matrix = qml.density_matrix(wires=self.wires).process_state(state, wire_order) + ... density_matrix = qml.density_matrix(wires=self.wires).process_state(state, wire_order, is_state_batched=is_state_batched) ... return qml.math.diagonal(qml.math.real(density_matrix)) We can now execute it in a QNode: @@ -568,13 +569,16 @@ class StateMeasurement(MeasurementProcess): """ @abstractmethod - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): """Process the given quantum state. Args: state (Sequence[complex]): quantum state wire_order (Wires): wires determining the subspace that ``state`` acts on; a matrix of dimension :math:`2^n` acts on a subspace of :math:`n` wires + is_state_batched (Optional[bool]): whether the state is batched or not """ diff --git a/pennylane/measurements/mutual_info.py b/pennylane/measurements/mutual_info.py index 991d56a7554..9cc8d697f1c 100644 --- a/pennylane/measurements/mutual_info.py +++ b/pennylane/measurements/mutual_info.py @@ -145,7 +145,9 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): state = qml.math.dm_from_state_vector(state) return qml.math.mutual_info( state, diff --git a/pennylane/measurements/probs.py b/pennylane/measurements/probs.py index 0fa8c9a32e7..d039cf7b896 100644 --- a/pennylane/measurements/probs.py +++ b/pennylane/measurements/probs.py @@ -194,18 +194,13 @@ def process_samples( prob = self._count_samples(indices, batch_size, dim) return qml.math.squeeze(prob) if bin_size is None else prob - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): num_wires = len(wire_order) dim = 2**num_wires # Compute batch_size - expected_shape = [2] * num_wires - expected_size = dim - size = qml.math.size(state) - batch_size = ( - size // expected_size - if qml.math.ndim(state) > len(expected_shape) or size > expected_size - else None - ) + batch_size = qml.math.size(state) // dim if is_state_batched else None flat_state = qml.math.reshape( state, (batch_size, dim) if batch_size is not None else (dim,) ) diff --git a/pennylane/measurements/purity.py b/pennylane/measurements/purity.py index 7bf411007e8..fea6cf010af 100644 --- a/pennylane/measurements/purity.py +++ b/pennylane/measurements/purity.py @@ -98,7 +98,9 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): wire_map = dict(zip(wire_order, list(range(len(wire_order))))) indices = [wire_map[w] for w in self.wires] state = qml.math.dm_from_state_vector(state) diff --git a/pennylane/measurements/state.py b/pennylane/measurements/state.py index 22e89d2aae2..7116dab7a67 100644 --- a/pennylane/measurements/state.py +++ b/pennylane/measurements/state.py @@ -183,7 +183,9 @@ def shape(self, device, shots): return (dim,) if num_shot_elements == 1 else tuple((dim,) for _ in range(num_shot_elements)) # pylint: disable=redefined-outer-name - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): if self.wires: # qml.density_matrix wire_map = dict(zip(wire_order, range(len(wire_order)))) diff --git a/pennylane/measurements/var.py b/pennylane/measurements/var.py index 60fd35da323..59a1e5df262 100644 --- a/pennylane/measurements/var.py +++ b/pennylane/measurements/var.py @@ -124,19 +124,25 @@ def process_samples( # TODO: do we need to squeeze here? Maybe remove with new return types return qml.math.squeeze(qml.math.var(samples, axis=axis)) - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): if isinstance(self.obs, Projector): # branch specifically to handle the projector observable idx = int("".join(str(i) for i in self.obs.parameters[0]), 2) # we use ``self.wires`` instead of ``self.obs`` because the observable was # already applied to the state - probs = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) + probs = qml.probs(wires=self.wires).process_state( + state=state, wire_order=wire_order, is_state_batched=is_state_batched + ) return probs[idx] - probs[idx] ** 2 eigvals = qml.math.asarray(self.obs.eigvals(), dtype=float) # we use ``wires`` instead of ``op`` because the observable was # already applied to the state - prob = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) + prob = qml.probs(wires=self.wires).process_state( + state=state, wire_order=wire_order, is_state_batched=is_state_batched + ) # In case of broadcasting, `prob` has two axes and these are a matrix-vector products return qml.math.dot(prob, (eigvals**2)) - qml.math.dot(prob, eigvals) ** 2 diff --git a/pennylane/measurements/vn_entropy.py b/pennylane/measurements/vn_entropy.py index 67228cadfb1..9ce76a6621a 100644 --- a/pennylane/measurements/vn_entropy.py +++ b/pennylane/measurements/vn_entropy.py @@ -122,7 +122,9 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state(self, state: Sequence[complex], wire_order: Wires): + def process_state( + self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False + ): state = qml.math.dm_from_state_vector(state) return qml.math.vn_entropy( state, indices=self.wires, c_dtype=state.dtype, base=self.log_base From 4d295fb7fb9e7490cc3ba9930d8971b08c1e1485 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 3 Aug 2023 14:02:14 -0400 Subject: [PATCH 05/78] copy from DQ (wires init and Pow support); fix tests/ops --- pennylane/devices/experimental/device_api.py | 11 ++++++- pennylane/devices/qubit/preprocess.py | 2 ++ tests/ops/functions/test_map_wires.py | 26 ++++++--------- tests/ops/op_math/test_exp.py | 10 +++--- tests/ops/op_math/test_prod.py | 33 +++++++++++--------- tests/ops/op_math/test_sprod.py | 18 +++++------ tests/ops/qubit/test_hamiltonian.py | 10 +++--- 7 files changed, 58 insertions(+), 52 deletions(-) diff --git a/pennylane/devices/experimental/device_api.py b/pennylane/devices/experimental/device_api.py index a45a94c7050..2fa5af71963 100644 --- a/pennylane/devices/experimental/device_api.py +++ b/pennylane/devices/experimental/device_api.py @@ -17,12 +17,14 @@ # pylint: disable=comparison-with-callable import abc +from collections.abc import Iterable from numbers import Number from typing import Callable, Union, Sequence, Tuple, Optional from pennylane.measurements import Shots from pennylane.tape import QuantumTape, QuantumScript from pennylane.typing import Result, ResultBatch +from pennylane.wires import Wires from pennylane import Tracker from .execution_config import ExecutionConfig, DefaultExecutionConfig @@ -157,6 +159,13 @@ def __init__(self, wires=None, shots=None) -> None: # each instance should have its own Tracker. self.tracker = Tracker() self._shots = Shots(shots) + + if wires is not None: + if not isinstance(wires, Iterable): + # interpret wires as the number of consecutive wires + wires = range(wires) + wires = Wires(wires) + self._wires = wires @property @@ -170,7 +179,7 @@ def shots(self) -> Shots: return self._shots @property - def wires(self): + def wires(self) -> Wires: """The device wires. None means any wires can be used.""" return self._wires diff --git a/pennylane/devices/qubit/preprocess.py b/pennylane/devices/qubit/preprocess.py index ee389d0a1e9..127649b661c 100644 --- a/pennylane/devices/qubit/preprocess.py +++ b/pennylane/devices/qubit/preprocess.py @@ -68,6 +68,8 @@ def _accepted_operator(op: qml.operation.Operator) -> bool: return False if op.name == "Snapshot": return True + if op.__class__.__name__ == "Pow" and qml.operation.is_trainable(op): + return False return op.has_matrix diff --git a/tests/ops/functions/test_map_wires.py b/tests/ops/functions/test_map_wires.py index 33b6643ac78..e570275cf77 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 @@ -110,13 +110,13 @@ def test_map_wires_tape(self, shots): s_tape = qml.map_wires(tape, wire_map=wire_map) assert len(s_tape) == 1 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) @@ -130,13 +130,10 @@ def test_execute_mapped_tape(self, shots): m_tape = qml.map_wires(tape, wire_map=wire_map) 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: @@ -149,23 +146,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 4980f449ad5..2cfbcbff739 100644 --- a/tests/ops/op_math/test_exp.py +++ b/tests/ops/op_math/test_exp.py @@ -616,7 +616,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]))" @@ -766,7 +766,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 @@ -841,7 +841,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) @@ -872,7 +872,7 @@ def test_tf_measurement(self): """Test Exp in a measurement with gradient and tensorflow.""" 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): @@ -980,7 +980,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 cfede95992f..a0692856e82 100644 --- a/tests/ops/op_math/test_prod.py +++ b/tests/ops/op_math/test_prod.py @@ -965,7 +965,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 +1016,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 +1050,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 +1100,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 +1116,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 +1128,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 @@ -1301,9 +1301,9 @@ def my_circ(): results = my_circ() - assert sum(results.values()) == 20 - assert 1 in results - assert -1 not in results + assert sum(results.values()) == 20 # pylint:disable=no-member + assert 1 in results # pylint:disable=unsupported-membership-test + assert -1 not in results # pylint:disable=unsupported-membership-test def test_differentiable_measurement_process(self): """Test that the gradient can be computed with a Prod op in the measurement process.""" @@ -1321,7 +1321,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 +1332,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 +1387,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 e21df800582..7f982f17b32 100644 --- a/tests/ops/op_math/test_sprod.py +++ b/tests/ops/op_math/test_sprod.py @@ -785,7 +785,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)), @@ -794,7 +794,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 @@ -832,7 +832,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 @@ -1004,9 +1004,9 @@ def my_circ(): results = my_circ() - assert sum(results.values()) == 20 - assert 1.23 in results - assert -1.23 not in results + assert sum(results.values()) == 20 # pylint:disable=no-member + assert 1.23 in results # pylint:disable=unsupported-membership-test + assert -1.23 not in results # pylint:disable=unsupported-membership-test def test_differentiable_scalar(self): """Test that the gradient can be computed of the scalar when a SProd op @@ -1040,7 +1040,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) @@ -1051,7 +1051,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 @@ -1101,7 +1101,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) From efe288a7b34d09897427058a5af821a401fb65e2 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 4 Aug 2023 09:59:30 -0400 Subject: [PATCH 06/78] fix tests/test_*.py --- pennylane/qnode.py | 7 +- tests/test_debugging.py | 30 +-- tests/test_device.py | 2 +- tests/test_operation.py | 2 +- tests/test_qnode.py | 158 ++++++------- tests/test_qubit_device.py | 64 +++--- tests/test_return_types.py | 79 +++---- tests/test_return_types_qnode.py | 361 +++++++++++++++--------------- tests/test_tensor_measurements.py | 55 ----- tests/test_vqe.py | 135 ++++++----- 10 files changed, 420 insertions(+), 473 deletions(-) diff --git a/pennylane/qnode.py b/pennylane/qnode.py index 4a02926e49b..653af9c6490 100644 --- a/pennylane/qnode.py +++ b/pennylane/qnode.py @@ -882,10 +882,9 @@ def construct(self, args, kwargs): # pylint: disable=too-many-branches ) for obj in self.tape.operations + self.tape.observables: - if ( - getattr(obj, "num_wires", None) is qml.operation.WiresEnum.AllWires - and len(obj.wires) != self.device.num_wires - ): + if getattr(obj, "num_wires", None) is qml.operation.WiresEnum.AllWires and len( + obj.wires + ) != getattr(self.device, "num_wires", len(obj.wires)): # check here only if enough wires raise qml.QuantumFunctionError(f"Operator {obj.name} must act on all wires") diff --git a/tests/test_debugging.py b/tests/test_debugging.py index 2bcec651d36..ae825a65622 100644 --- a/tests/test_debugging.py +++ b/tests/test_debugging.py @@ -24,9 +24,9 @@ class TestSnapshot: # pylint: disable=protected-access @pytest.mark.parametrize("method", [None, "backprop", "parameter-shift", "adjoint"]) - def test_default_qubit(self, method): + def test_default_qubit1(self, method): """Test that multiple snapshots are returned correctly on the state-vector simulator.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) @qml.qnode(dev, diff_method=method) def circuit(): @@ -188,32 +188,6 @@ def circuit(): with pytest.raises(qml.DeviceError, match="Device does not support snapshots."): qml.snapshots(circuit)() - def test_unsupported_device(self): - """Test that an error is raised on unsupported devices.""" - dev = qml.device("default.qubit", wires=2) - # remove attributes to simulate unsupported device - delattr(dev, "_debugger") - dev.operations.remove("Snapshot") - - @qml.qnode(dev, interface=None) # iterface=None prevents new device creation internally - 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)) - - # can run the circuit - result = circuit() - assert result == 0 - - with pytest.raises(qml.DeviceError, match="Device does not support snapshots."): - qml.snapshots(circuit)() - - # need to revert change to not affect other tests (since operations a static attribute) - dev.operations.add("Snapshot") - def test_unsupported_device_new(self): """Test that an error is raised on unsupported devices.""" diff --git a/tests/test_device.py b/tests/test_device.py index ceec1ada8a8..bdf7f350ae2 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -876,7 +876,7 @@ def test_hot_refresh_entrypoints(self, monkeypatch): def test_shot_vector_property(self): """Tests shot vector initialization.""" - dev = qml.device("default.qubit", wires=1, shots=[1, 3, 3, 4, 4, 4, 3]) + dev = qml.devices.DefaultQubit(wires=1, shots=[1, 3, 3, 4, 4, 4, 3]) shot_vector = dev.shot_vector assert len(shot_vector) == 4 assert shot_vector[0].shots == 1 diff --git a/tests/test_operation.py b/tests/test_operation.py index 13c93332bc9..300bdf98648 100644 --- a/tests/test_operation.py +++ b/tests/test_operation.py @@ -1035,7 +1035,7 @@ def test_all_wires_defined_but_init_with_one(self): """Test that an exception is raised if the class is defined with ALL wires, but then instantiated with only one""" - dev1 = qml.device("default.qubit", wires=2) + dev1 = qml.devices.DefaultQubit(wires=2) class DummyOp(qml.operation.Operation): r"""Dummy custom operator""" diff --git a/tests/test_qnode.py b/tests/test_qnode.py index 8489b48e29d..198312a2caa 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -40,7 +40,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.devices.DefaultQubit(wires=1) test_interface = "something" expected_error = rf"Unknown interface {test_interface}\. Interface must be one of" @@ -50,7 +50,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.devices.DefaultQubit(wires=1) test_interface = "something" @qnode(dev) @@ -69,7 +69,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.devices.DefaultQubit(wires=1) @qnode(dev, interface="autograd", diff_method="best") def circuit(x): @@ -92,7 +92,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.devices.DefaultQubit(wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -121,7 +121,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.devices.DefaultQubit(wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -133,7 +133,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.devices.DefaultQubit(wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -151,7 +151,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.devices.DefaultQubit(wires=1) diff_method, _, new_dev = QNode._validate_backprop_method(dev, accepted_name) @@ -162,7 +162,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.devices.DefaultQubit(wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -179,7 +179,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.devices.DefaultQubit(wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -206,7 +206,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.devices.DefaultQubit(wires=1) gradient_fn = QNode._validate_parameter_shift(dev) assert gradient_fn[0] is qml.gradients.param_shift @@ -239,7 +239,7 @@ def capabilities(cls): return capabilities monkeypatch.setattr(qml.devices.DefaultQubit, "capabilities", capabilities) - dev = qml.device("default.qubit", wires=1) + dev = qml.devices.DefaultQubit(wires=1) with pytest.raises( qml.QuantumFunctionError, match="does not support the parameter-shift rule" @@ -251,7 +251,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", True) @@ -267,7 +267,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -279,7 +279,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -292,7 +292,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -310,7 +310,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", True) @@ -326,7 +326,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -338,7 +338,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -351,7 +351,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.devices.DefaultQubit(wires=1) monkeypatch.setitem(dev._capabilities, "passthru_interface", "some_interface") monkeypatch.setitem(dev._capabilities, "provides_jacobian", False) @@ -369,7 +369,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.devices.DefaultQubit(wires=1) mock_best = mocker.patch("pennylane.QNode.get_best_method") mock_best.return_value = ("best", {}, dev) @@ -434,7 +434,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.devices.DefaultQubit(wires=1) spy = mocker.spy(qml.gradients.finite_difference, "finite_diff_coeffs") @qnode(dev, diff_method=qml.gradients.finite_diff) @@ -448,7 +448,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.devices.DefaultQubit(wires=1) with pytest.raises( qml.QuantumFunctionError, match="Differentiation method hello not recognized" @@ -457,7 +457,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.devices.DefaultQubit(wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -477,7 +477,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.devices.DefaultQubit(wires=1, shots=1) with pytest.warns( UserWarning, match="Requested adjoint differentiation to be computed with finite shots." @@ -489,7 +489,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.devices.DefaultQubit(wires=1, shots=1) @qnode(dev, diff_method="adjoint") def circ(): @@ -504,7 +504,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.devices.DefaultQubit(wires=2, shots=None) @qnode(dev, diff_method="backprop") def circuit(param): @@ -520,7 +520,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.devices.DefaultQubit(wires=1) def func(x): qml.RX(x, wires=0) @@ -544,7 +544,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.devices.DefaultQubit(wires=1) @qnode(dev, diff_method=None) def circuit(x): @@ -566,7 +566,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.devices.DefaultQubit(wires=2) with warnings.catch_warnings(record=True) as w: @@ -582,7 +582,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.devices.DefaultQubit(wires=2) with warnings.catch_warnings(record=True) as w: @@ -602,7 +602,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.devices.DefaultQubit(wires=1) @qml.qnode(dev) def circuit(params): @@ -624,7 +624,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.devices.DefaultQubit(wires=1) @qml.qnode(dev, interface="autograd") def circuit(params): @@ -639,14 +639,14 @@ 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.devices.DefaultQubit(wires=1)) assert len(record) == 0 def test_giving_mode_kwarg_raises_warning(self): """Test that providing a value for mode raises a warning.""" with pytest.warns(UserWarning, match="The `mode` keyword argument is deprecated"): - _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1), mode="best") + _ = qml.QNode(lambda f: f, qml.devices.DefaultQubit(wires=1), mode="best") def test_giving_mode_kwarg_raises_warning_old_return(self): """Test that providing a value for mode raises a custom warning with disable_return.""" @@ -654,7 +654,7 @@ def test_giving_mode_kwarg_raises_warning_old_return(self): with pytest.warns( UserWarning, match="In the new return system, you should set the `grad_on_execution`" ): - _ = qml.QNode(lambda f: f, qml.device("default.qubit", wires=1), mode="best") + _ = qml.QNode(lambda f: f, qml.devices.DefaultQubit(wires=1), mode="best") qml.enable_return() @@ -663,7 +663,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.devices.DefaultQubit(wires=2) def func(x, y): qml.RX(x, wires=0) @@ -696,7 +696,7 @@ def func(x, y): def test_jacobian(self): """Test the jacobian computation""" - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) def func(x, y): qml.RX(x, wires=0) @@ -720,7 +720,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.devices.DefaultQubit(wires=2) def func0(x, y): qml.RX(x, wires=0) @@ -764,7 +764,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.devices.DefaultQubit(wires=2) def func(x, y): qml.RX(x, wires=0) @@ -784,7 +784,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.devices.DefaultQubit(wires=2) contents = [] @@ -815,13 +815,13 @@ def circuit(x): qml.RX(x, wires=0) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(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.devices.DefaultQubit(wires=1) qn = QNode(circuit, dev) assert np.allclose(qn(0.5), np.cos(0.5), atol=tol, rtol=0) @@ -831,7 +831,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.devices.DefaultQubit(wires=2, shots=5) def circuit1(param): qml.Hadamard(0) @@ -865,7 +865,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.devices.DefaultQubit(wires=2) @qnode(dev) def func(x, y): @@ -911,7 +911,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) qn = QNode(func, dev, interface="autograd") for _ in range(2): @@ -935,7 +935,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -964,7 +964,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -987,7 +987,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.devices.DefaultQubit(wires=2) cache = {} @@ -1008,7 +1008,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.devices.DefaultQubit(wires=2) cache = {} @@ -1043,7 +1043,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.devices.DefaultQubit(wires=3) x = pnp.array(0.543, requires_grad=True) y = pnp.array(-0.654, requires_grad=True) @@ -1073,7 +1073,7 @@ def test_defer_meas_if_mcm_unsupported(self, first_par, sec_par, return_type): """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=2) + dev = qml.devices.DefaultQubit(wires=2) @qml.qnode(dev) def cry_qnode(x, y): @@ -1101,7 +1101,7 @@ def conditional_ry_qnode(x, y): def test_sampling_with_mcm(self, basis_state): """Tests that a QNode with qml.sample and mid-circuit measurements returns the expected results.""" - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.devices.DefaultQubit(wires=2, shots=1000) first_par = np.pi @@ -1131,7 +1131,7 @@ def test_conditional_ops_tensorflow(self, interface): """Test conditional operations with TensorFlow.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1174,7 +1174,7 @@ def test_conditional_ops_torch(self, interface): """Test conditional operations with Torch.""" import torch - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1213,7 +1213,7 @@ def test_conditional_ops_jax(self, jax_interface): import jax jnp = jax.numpy - dev = qml.device("default.qubit", wires=2) + dev = qml.devices.DefaultQubit(wires=2) @qml.qnode(dev, interface=jax_interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1245,7 +1245,7 @@ def conditional_ry_qnode(x): def test_already_measured_error_operation(self): """Test that attempting to apply an operation on a wires that has been measured raises an error.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.devices.DefaultQubit(wires=3) @qml.qnode(dev) def circuit(): @@ -1258,7 +1258,7 @@ def circuit(): 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.devices.DefaultQubit(wires=1) @qml.qnode(dev) def circuit(): @@ -1278,7 +1278,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.devices.DefaultQubit(wires=1, shots=10) @qnode(dev) def circuit(a): @@ -1294,7 +1294,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.devices.DefaultQubit(wires=1, shots=None) @qnode(dev) def circuit(): @@ -1320,7 +1320,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.devices.DefaultQubit(wires=2, shots=10) def circuit(a, shots=0): qml.RX(a, wires=shots) @@ -1344,7 +1344,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.devices.DefaultQubit(wires=[0, 1], shots=10) def ansatz0(a, shots): qml.RX(a, wires=shots) @@ -1359,7 +1359,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.devices.DefaultQubit(wires=2, shots=10) with pytest.warns( UserWarning, match="The 'shots' argument name is reserved for overriding" @@ -1377,7 +1377,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.devices.DefaultQubit(wires=1, shots=3) @qnode(dev) def circuit(a): @@ -1391,7 +1391,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.devices.DefaultQubit(wires=1, shots=5) @qml.qnode(dev, cache={}) def circuit(x): @@ -1406,7 +1406,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) + dev = qml.devices.DefaultQubit(wires=1) @qml.qnode(dev, cache={}) def circuit(x): @@ -1420,7 +1420,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.devices.DefaultQubit(wires=1, shots=5) with qml.queuing.AnnotatedQueue() as q: qml.RZ(0.3, wires=0) @@ -1435,7 +1435,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.devices.DefaultQubit(wires=1) @qml.qnode(dev, cache={}) def circuit(x): @@ -1450,7 +1450,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.devices.DefaultQubit(wires=1, shots=5) @qml.qnode(dev, cache=True) def circuit(x): @@ -1473,7 +1473,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.devices.DefaultQubit(wires=2, shots=5) def func(x, y): qml.RX(x, wires=0) @@ -1516,7 +1516,7 @@ class TestSpecs: def test_specs_error(self): """Tests an error is raised if the tape is not constructed.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.devices.DefaultQubit(wires=4) @qnode(dev) def circuit(): @@ -1531,7 +1531,7 @@ def circuit(): def test_specs(self, diff_method, len_info): """Tests the specs property with backprop, parameter-shift and adjoint diff_method""" - dev = qml.device("default.qubit", wires=4) + dev = qml.devices.DefaultQubit(wires=4) @qnode(dev, diff_method=diff_method) def circuit(x, y): @@ -1726,7 +1726,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.devices.DefaultQubit(wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1759,7 +1759,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.devices.DefaultQubit(wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1804,7 +1804,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.devices.DefaultQubit(wires=1) # pylint: disable=too-few-public-methods class PhaseShift(qml.PhaseShift): @@ -1849,7 +1849,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.devices.DefaultQubit(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]) @@ -1868,7 +1868,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.devices.DefaultQubit(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]) @@ -1893,7 +1893,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.devices.DefaultQubit(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]) @@ -1914,7 +1914,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.devices.DefaultQubit(wires=2) x = pnp.array(0.5, requires_grad=True) @qnode(dev, diff_method="parameter-shift", expansion_strategy="device") @@ -1940,7 +1940,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.devices.DefaultQubit(wires=2) obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliY(1)] @qml.qnode(dev) diff --git a/tests/test_qubit_device.py b/tests/test_qubit_device.py index 18b93e37858..41e9c280064 100644 --- a/tests/test_qubit_device.py +++ b/tests/test_qubit_device.py @@ -1146,7 +1146,7 @@ class TestExecution: def test_device_executions(self): """Test the number of times a qubit device is executed over a QNode's - lifetime is tracked by `num_executions`""" + lifetime is tracked by the device's tracker""" dev_1 = qml.device("default.qubit", wires=2) @@ -1159,9 +1159,10 @@ def circuit_1(x, y): node_1 = qml.QNode(circuit_1, dev_1) num_evals_1 = 10 - for _ in range(num_evals_1): - node_1(0.432, 0.12) - assert dev_1.num_executions == num_evals_1 + with qml.Tracker(dev_1, persistent=True) as tracker1: + for _ in range(num_evals_1): + node_1(0.432, 0.12) + assert tracker1.totals["executions"] == num_evals_1 # test a second instance of a default qubit device dev_2 = qml.device("default.qubit", wires=2) @@ -1174,9 +1175,10 @@ def circuit_2(x): node_2 = qml.QNode(circuit_2, dev_2) num_evals_2 = 5 - for _ in range(num_evals_2): - node_2(0.432) - assert dev_2.num_executions == num_evals_2 + with qml.Tracker(dev_2) as tracker2: + for _ in range(num_evals_2): + node_2(0.432) + assert tracker2.totals["executions"] == num_evals_2 # test a new circuit on an existing instance of a qubit device def circuit_3(y): @@ -1187,9 +1189,10 @@ def circuit_3(y): node_3 = qml.QNode(circuit_3, dev_1) num_evals_3 = 7 - for _ in range(num_evals_3): - node_3(0.12) - assert dev_1.num_executions == num_evals_1 + num_evals_3 + with tracker1: + for _ in range(num_evals_3): + node_3(0.12) + assert tracker1.totals["executions"] == num_evals_1 + num_evals_3 # pylint: disable=protected-access def test_get_diagonalizing_gates(self, mock_qubit_device): @@ -1207,7 +1210,7 @@ class TestExecutionBroadcasted: def test_device_executions(self): """Test the number of times a qubit device is executed over a QNode's - lifetime is tracked by `num_executions`""" + lifetime is tracked by the device's tracker.""" dev_1 = qml.device("default.qubit", wires=2) @@ -1220,15 +1223,14 @@ def circuit_1(x, y): node_1 = qml.QNode(circuit_1, dev_1) num_evals_1 = 10 - for _ in range(num_evals_1): - node_1(0.432, np.array([0.12, 0.5, 3.2])) - assert dev_1.num_executions == num_evals_1 + 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) - assert dev_2.num_executions == 0 - def circuit_2(x, y): qml.RX(x, wires=[0]) qml.CNOT(wires=[0, 1]) @@ -1237,9 +1239,10 @@ def circuit_2(x, y): node_2 = qml.QNode(circuit_2, dev_2) num_evals_2 = 5 - for _ in range(num_evals_2): - node_2(np.array([0.432, 0.61, 8.2]), 0.12) - assert dev_2.num_executions == num_evals_2 + with qml.Tracker(dev_2) as tracker2: + for _ in range(num_evals_2): + node_2(np.array([0.432, 0.61, 8.2]), 0.12) + assert tracker2.totals["executions"] == num_evals_2 # test a new circuit on an existing instance of a qubit device def circuit_3(x, y): @@ -1250,9 +1253,10 @@ def circuit_3(x, y): node_3 = qml.QNode(circuit_3, dev_1) num_evals_3 = 7 - for _ in range(num_evals_3): - node_3(np.array([0.432, 0.2]), np.array([0.12, 1.214])) - assert dev_1.num_executions == num_evals_1 + num_evals_3 + with tracker1: + for _ in range(num_evals_3): + node_3(np.array([0.432, 0.2]), np.array([0.12, 1.214])) + assert tracker1.totals["executions"] == num_evals_1 + num_evals_3 class TestBatchExecution: @@ -1407,6 +1411,7 @@ class TestResourcesTracker: def test_tracker_single_execution(self, dev_name, qs_shots_wires, expected_resource): """Test that the tracker accurately tracks resources in a single execution""" qs, shots, wires = qs_shots_wires + qs._shots = Shots(shots) dev = qml.device(dev_name, shots=shots, wires=wires) with qml.Tracker(dev) as tracker: @@ -1416,21 +1421,20 @@ def test_tracker_single_execution(self, dev_name, qs_shots_wires, expected_resou assert tracker.history["resources"][0] == expected_resource @pytest.mark.all_interfaces - @pytest.mark.parametrize("dev_name", devices) - def test_tracker_multi_execution(self, dev_name): + def test_tracker_multi_execution(self): """Test that the tracker accurately tracks resources for multi executions""" - qs1 = qml.tape.QuantumScript([qml.Hadamard(0), qml.CNOT([0, 1])]) - qs2 = qml.tape.QuantumScript([qml.PauliZ(0), qml.CNOT([0, 1]), qml.RX(1.23, 2)]) + qs1 = qml.tape.QuantumScript([qml.Hadamard(0), qml.CNOT([0, 1])], shots=10) + qs2 = qml.tape.QuantumScript([qml.PauliZ(0), qml.CNOT([0, 1]), qml.RX(1.23, 2)], shots=10) exp_res1 = Resources(2, 2, {"Hadamard": 1, "CNOT": 1}, {1: 1, 2: 1}, 2, Shots(10)) exp_res2 = Resources(3, 3, {"PauliZ": 1, "CNOT": 1, "RX": 1}, {1: 2, 2: 1}, 2, Shots(10)) - dev = qml.device(dev_name, shots=10, wires=[0, 1, 2]) + dev = qml.device("default.qubit", wires=[0, 1, 2]) with qml.Tracker(dev) as tracker: - dev.batch_execute([qs1]) - dev.batch_execute([qs1, qs2]) + dev.execute([qs1]) + dev.execute([qs1, qs2]) - assert tracker.totals == {"batches": 2, "executions": 3, "shots": 30, "batch_len": 3} + assert tracker.totals == {"batches": 2, "executions": 3} assert len(tracker.history["resources"]) == 3 # 1 per qscript execution for tracked_r, expected_r in zip( diff --git a/tests/test_return_types.py b/tests/test_return_types.py index 14897361519..a2e1c8adb89 100644 --- a/tests/test_return_types.py +++ b/tests/test_return_types.py @@ -14,6 +14,7 @@ """ Unit tests for the new return types. """ +from functools import partial import warnings import numpy as np @@ -24,7 +25,7 @@ test_wires = [2, 3, 4] -devices = ["default.qubit", "default.mixed"] +devices = [qml.devices.DefaultQubit, partial(qml.device, "default.mixed")] @pytest.mark.parametrize("interface, shots", [["autograd", None], ["auto", 100]]) @@ -34,7 +35,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.devices.DefaultQubit(wires=wires, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -83,7 +84,7 @@ def circuit(x): @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) + dev = device(wires=4, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -107,7 +108,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_expval(self, device, interface, shots): """Return a single expval.""" - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -125,7 +126,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_var(self, device, interface, shots): """Return a single var.""" - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -143,7 +144,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -167,7 +168,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -201,7 +202,7 @@ def circuit(x): @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) + dev = device(wires=3, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -225,7 +226,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.devices.DefaultQubit(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -246,7 +247,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.devices.DefaultQubit(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -274,7 +275,7 @@ class TestMultipleReturns: @pytest.mark.parametrize("device", devices) def test_multiple_expval(self, device, shots): """Return multiple expvals.""" - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -298,7 +299,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_multiple_var(self, device, shots): """Return multiple vars.""" - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -336,7 +337,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -370,7 +371,7 @@ def circuit(x): 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) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -418,7 +419,7 @@ def circuit(x): @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) + dev = device(wires=wires, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -444,7 +445,7 @@ def test_expval_sample(self, measurement, shots, device): if shots is None: pytest.skip("Sample requires finite shots.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -471,7 +472,7 @@ def test_expval_counts(self, measurement, shots, device): if shots is None: pytest.skip("Counts requires finite shots.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -527,7 +528,7 @@ class TestShotVector: @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -548,7 +549,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -571,7 +572,7 @@ def circuit(x): @pytest.mark.xfail def test_density_matrix(self, shot_vector, wires, device): """Test a density matrix measurement.""" - dev = qml.device(device, wires=3, shots=shot_vector) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -597,7 +598,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -624,7 +625,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -651,7 +652,7 @@ class TestSameMeasurementShotVector: def test_scalar(self, shot_vector, device): """Test multiple scalar-valued measurements.""" - dev = qml.device(device, wires=2, shots=shot_vector) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -683,7 +684,7 @@ def circuit(x): @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) + dev = device(wires=4, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -711,7 +712,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -736,7 +737,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -827,7 +828,7 @@ class TestMixMeasurementsShotVector: @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) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -860,7 +861,7 @@ def circuit(x): 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) + dev = 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) ] @@ -895,7 +896,7 @@ def circuit(x): @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) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -928,7 +929,7 @@ def circuit(x): 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) + dev = 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) ] @@ -969,7 +970,7 @@ def circuit(x): @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) + dev = 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) ] @@ -1003,7 +1004,7 @@ def circuit(x): @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) + dev = 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) ] @@ -1051,7 +1052,7 @@ def circuit(x): @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) + dev = 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) ] @@ -1101,7 +1102,7 @@ def circuit(x): 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) + dev = 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) ] @@ -1154,7 +1155,7 @@ def circuit(x): 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) + dev = 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) ] @@ -1223,7 +1224,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.devices.DefaultQubit(wires=3) with pytest.raises( qml.QuantumFunctionError, match="Unsupported return type specified for observable" ): @@ -1233,7 +1234,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.devices.DefaultQubit(wires=2) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires=0) @@ -1250,7 +1251,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.devices.DefaultQubit(wires=["a", 1]) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires="a") @@ -1266,7 +1267,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.devices.DefaultQubit(wires=["a", "b"]) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires="a") diff --git a/tests/test_return_types_qnode.py b/tests/test_return_types_qnode.py index ca71b6401ef..716eb00fb6d 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -14,13 +14,19 @@ """ Unit tests for the new return types with QNode. """ +from functools import partial import numpy as np import pytest import pennylane as qml +from pennylane.devices import DefaultQubit, DefaultMixed +from pennylane.devices.default_qubit_torch import DefaultQubitTorch +from pennylane.devices.default_qubit_tf import DefaultQubitTF +from pennylane.devices.default_qubit_jax import DefaultQubitJax +from pennylane.devices.default_qutrit import DefaultQutrit test_wires = [2, 3, 4] -devices = ["default.qubit", "lightning.qubit", "default.mixed", "default.qutrit"] +devices = [DefaultQubit, partial(qml.device, "lightning.qubit"), DefaultMixed, DefaultQutrit] def qubit_ansatz(x): @@ -40,7 +46,7 @@ class TestIntegrationSingleReturn: @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires): """Return state with default.qubit.""" - dev = qml.device("default.qubit", wires=wires) + dev = DefaultQubit(wires=wires) def circuit(x): qubit_ansatz(x) @@ -55,7 +61,7 @@ def circuit(x): @pytest.mark.parametrize("wires", test_wires) def test_state_mixed(self, wires): """Return state with default.mixed.""" - dev = qml.device("default.mixed", wires=wires) + dev = DefaultMixed(wires=wires) def circuit(x): qubit_ansatz(x) @@ -71,8 +77,8 @@ def circuit(x): @pytest.mark.parametrize("d_wires", test_wires) def test_density_matrix(self, d_wires, device): """Return density matrix with default.qubit.""" - dev = qml.device(device, wires=4) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + dev = device(wires=4) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) @@ -81,20 +87,20 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - dim = 3 if device == "default.qutrit" else 2 + dim = 3 if device == DefaultQutrit else 2 assert res.shape == (dim**d_wires, dim**d_wires) assert isinstance(res, np.ndarray) @pytest.mark.parametrize("device", devices) def test_expval(self, device): """Return a single expval.""" - dev = qml.device(device, wires=2) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + dev = device(wires=2) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) return qml.expval( - qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) + qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) ) qnode = qml.QNode(circuit, dev, diff_method=None) @@ -106,14 +112,12 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_var(self, device): """Return a single var.""" - dev = qml.device(device, wires=2) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + dev = device(wires=2) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) - return qml.var( - qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) - ) + return qml.var(qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3)) qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) @@ -124,10 +128,10 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_vn_entropy(self, device): """Return a single vn entropy.""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("DefaultQutrit does not support VnEntropy.") - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qubit_ansatz(x) @@ -143,7 +147,7 @@ def circuit(x): @pytest.mark.filterwarnings("ignore:Requested Von Neumann entropy with finite shots") def test_vn_entropy_shot_vec_error(self): """Test an error is raised when using shot vectors with vn_entropy.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = DefaultQubit(wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -158,10 +162,10 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_mutual_info(self, device): """Return a single mutual information.""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("DefaultQutrit does not support MutualInfo.") - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qubit_ansatz(x) @@ -177,7 +181,7 @@ def circuit(x): @pytest.mark.filterwarnings("ignore:Requested mutual information with finite shots") def test_mutual_info_shot_vec_error(self): """Test an error is raised when using shot vectors with mutual_info.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = DefaultQubit(wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -201,11 +205,11 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, op, wires, device): """Return a single prob.""" - if device in ("lightning.qubit", "default.qutrit"): + if device == DefaultQutrit or isinstance(device, partial): pytest.skip( "Skip Lightning (wire reordering unsupported) and Qutrit (unsuported observables)." ) - dev = qml.device(device, wires=3) + dev = device(wires=3) def circuit(x): qubit_ansatz(x) @@ -230,7 +234,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data_qutrit) def test_probs_qutrit(self, op, wires): """Return a single prob.""" - dev = qml.device("default.qutrit", wires=3) + dev = DefaultQutrit(wires=3) def circuit(x): qutrit_ansatz(x) @@ -257,14 +261,14 @@ def circuit(x): ) def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" - if device == "default.qutrit": + if device == DefaultQutrit: if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = qml.device(device, wires=2, shots=shots) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + dev = device(wires=2, shots=shots) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) @@ -278,7 +282,7 @@ def circuit(x): if measurement.wires.tolist() != [0, 1]: assert res.shape == (shots,) else: - assert res.shape == (shots, 2) if device != "default.qutrit" else (shots, 3) + assert res.shape == (shots, 2) if device != DefaultQutrit else (shots, 3) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize( @@ -292,14 +296,14 @@ def circuit(x): ) def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" - if device == "default.qutrit": + if device == DefaultQutrit: if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = qml.device(device, wires=2, shots=shots) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + dev = device(wires=2, shots=shots) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) @@ -312,7 +316,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = ["default.qubit.tf", "default.mixed"] +devices = [DefaultQubitTF, DefaultMixed] @pytest.mark.tf @@ -324,7 +328,7 @@ def test_state_default(self, wires): """Return state with default.qubit.""" import tensorflow as tf - dev = qml.device("default.qubit.tf", wires=wires) + dev = DefaultQubitTF(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -342,7 +346,7 @@ def test_state_mixed(self, wires): """Return state with default.mixed.""" import tensorflow as tf - dev = qml.device("default.mixed", wires=wires) + dev = DefaultMixed(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -363,7 +367,7 @@ def test_density_matrix(self, d_wires, device): """Return density matrix.""" import tensorflow as tf - dev = qml.device(device, wires=3) + dev = device(wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -381,7 +385,7 @@ def test_expval(self, device): """Return a single expval.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -399,7 +403,7 @@ def test_var(self, device): """Return a single var.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -417,7 +421,7 @@ def test_vn_entropy(self, device): """Return a single vn entropy.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -435,7 +439,7 @@ def test_mutual_info(self, device): """Return a single mutual information.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -462,7 +466,7 @@ def test_probs(self, op, wires, device): """Return a single prob.""" import tensorflow as tf - dev = qml.device(device, wires=3) + dev = device(wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -486,10 +490,10 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import tensorflow as tf - if device in ["default.mixed", "default.qubit"]: + if device in [DefaultMixed, DefaultQubit]: pytest.skip("Sample need to be rewritten for Tf.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -514,7 +518,7 @@ def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" import tensorflow as tf - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -528,7 +532,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = ["default.qubit.torch", "default.mixed"] +devices = [DefaultQubitTorch, DefaultMixed] @pytest.mark.torch @@ -540,7 +544,7 @@ def test_state_default(self, wires): """Return state with default.qubit.""" import torch - dev = qml.device("default.qubit.torch", wires=wires) + dev = DefaultQubitTorch(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -558,7 +562,7 @@ def test_state_mixed(self, wires): """Return state with default.mixed.""" import torch - dev = qml.device("default.mixed", wires=wires) + dev = DefaultMixed(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -577,7 +581,7 @@ def test_density_matrix(self, d_wires, device): """Return density matrix.""" import torch - dev = qml.device(device, wires=4) + dev = device(wires=4) def circuit(x): qml.Hadamard(wires=[0]) @@ -595,7 +599,7 @@ def test_expval(self, device): """Return a single expval.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -613,7 +617,7 @@ def test_var(self, device): """Return a single var.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -631,7 +635,7 @@ def test_vn_entropy(self, device): """Return a single vn entropy.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -649,7 +653,7 @@ def test_mutual_info(self, device): """Return a single mutual information.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -676,7 +680,7 @@ def test_probs(self, op, wires, device): """Return a single prob.""" import torch - dev = qml.device(device, wires=3) + dev = device(wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -700,10 +704,10 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import torch - if device in ["default.mixed", "default.qubit"]: + if device in [DefaultMixed, DefaultQubit]: pytest.skip("Sample need to be rewritten for Torch.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -726,10 +730,10 @@ def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" import torch - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Counts need to be rewritten for Torch and default mixed.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -743,7 +747,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = ["default.qubit.jax", "default.mixed"] +devices = [DefaultQubitJax, DefaultMixed] @pytest.mark.jax @@ -758,7 +762,7 @@ def test_state_default(self, wires): config.update("jax_enable_x64", True) import jax - dev = qml.device("default.qubit.jax", wires=wires) + dev = DefaultQubitJax(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -779,7 +783,7 @@ def test_state_mixed(self, wires): config.update("jax_enable_x64", True) import jax - dev = qml.device("default.mixed", wires=wires) + dev = DefaultMixed(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -801,7 +805,7 @@ def test_density_matrix(self, d_wires, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=4) + dev = device(wires=4) def circuit(x): qml.Hadamard(wires=[0]) @@ -822,7 +826,7 @@ def test_expval(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -843,7 +847,7 @@ def test_var(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -864,7 +868,7 @@ def test_vn_entropy(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -885,7 +889,7 @@ def test_mutual_info(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -915,7 +919,7 @@ def test_probs(self, op, wires, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=3) + dev = device(wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -942,10 +946,10 @@ def test_sample(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Sample need to be rewritten for each interface in default mixed.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -973,7 +977,7 @@ def test_counts(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -989,7 +993,7 @@ def circuit(x): multi_return_wires = [([0], [1]), ([1], [0]), ([0], [0]), ([1], [1])] -devices = ["default.qubit", "lightning.qubit", "default.mixed", "default.qutrit"] +devices = [DefaultQubit, partial(qml.device, "lightning.qubit"), DefaultMixed, DefaultQutrit] class TestIntegrationMultipleReturns: @@ -1000,15 +1004,15 @@ class TestIntegrationMultipleReturns: @pytest.mark.parametrize("device", devices) def test_multiple_expval(self, device): """Return multiple expvals.""" - dev = qml.device(device, wires=2) + dev = device(wires=2) obs1 = ( qml.Projector([0], wires=0) - if device != "default.qutrit" + if device != DefaultQutrit else qml.THermitian(np.eye(3), wires=0) ) - obs2 = qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + obs2 = qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) @@ -1029,15 +1033,15 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_multiple_var(self, device): """Return multiple vars.""" - dev = qml.device(device, wires=2) + dev = device(wires=2) obs1 = ( qml.Projector([0], wires=0) - if device != "default.qutrit" + if device != DefaultQutrit else qml.THermitian(np.eye(3), wires=0) ) - obs2 = qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) - func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz + obs2 = qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) + func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz def circuit(x): func(x) @@ -1072,10 +1076,10 @@ def circuit(x): @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data) def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("Separate test for DefaultQutrit.") - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qubit_ansatz(x) @@ -1113,7 +1117,7 @@ def circuit(x): @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data_qutrit) def test_multiple_prob_qutrit(self, op1, op2, wires1, wires2): """Return multiple probs.""" - dev = qml.device("default.qutrit", wires=2) + dev = DefaultQutrit(wires=2) def circuit(x): qutrit_ansatz(x) @@ -1143,10 +1147,10 @@ def circuit(x): @pytest.mark.parametrize("wires3, wires4", multi_return_wires) def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("Different test for DefaultQutrit.") - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qubit_ansatz(x) @@ -1188,7 +1192,7 @@ def test_mix_meas_qutrit(self, op1, wires1, op2, wires2, wires3, wires4): """Return multiple different measurements.""" pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") - dev = qml.device("default.qutrit", wires=2) + dev = DefaultQutrit(wires=2) def circuit(x): qutrit_ansatz(x) @@ -1230,15 +1234,15 @@ def circuit(x): ) def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" - if device == "default.qutrit": + if device == DefaultQutrit: if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = qml.device(device, wires=2, shots=shots) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) + dev = device(wires=2, shots=shots) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1262,15 +1266,15 @@ def circuit(x): ) def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" - if device == "default.qutrit": + if device == DefaultQutrit: if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = qml.device(device, wires=2, shots=shots) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) + dev = device(wires=2, shots=shots) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1293,9 +1297,9 @@ def circuit(x): @pytest.mark.parametrize("wires", wires) def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" - dev = qml.device(device, wires=wires) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(0) if device != "default.qutrit" else qml.GellMann(0, 3) + dev = device(wires=wires) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ(0) if device != DefaultQutrit else qml.GellMann(0, 3) def circuit(x): func(x) @@ -1316,14 +1320,15 @@ def circuit(x): @pytest.mark.parametrize("shot_vector", shot_vectors) def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" - dev = qml.device(device, wires=wires, shots=shot_vector) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ if device != "default.qutrit" else qml.GellMann + # pylint:disable=unexpected-keyword-arg + dev = device(wires=wires, shots=shot_vector) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ if device != DefaultQutrit else qml.GellMann def circuit(x): func(x) return [ - qml.expval(obs(wires=i) if device != "default.qutrit" else obs(wires=i, index=3)) + qml.expval(obs(wires=i) if device != DefaultQutrit else obs(wires=i, index=3)) for i in range(0, wires) ] @@ -1349,12 +1354,12 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_array_multiple(self, device): """Return PennyLane array of multiple measurements""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") - dev = qml.device(device, wires=2) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) + dev = device(wires=2) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1365,20 +1370,20 @@ def circuit(x): assert isinstance(res, qml.numpy.ndarray) assert res[0].shape == () - assert res[1].shape == (4,) if device != "default.qutrit" else (9,) + assert res[1].shape == (4,) if device != DefaultQutrit else (9,) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize("comp_basis_sampling", [qml.sample(), qml.counts()]) def test_sample_counts_no_obs(self, device, comp_basis_sampling): """Measuring qml.sample()/qml.counts() works with other measurements even with the same wire being measured.""" - if device == "default.qutrit": + if device == DefaultQutrit: pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") shot_num = 1000 num_wires = 2 - dev = qml.device(device, wires=num_wires, shots=shot_num) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) + dev = device(wires=num_wires, shots=shot_num) + func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz + obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1400,7 +1405,7 @@ def circuit(x): assert res[2].shape == (2,) -devices = ["default.qubit.tf", "default.mixed"] +devices = [DefaultQubitTF, DefaultMixed] @pytest.mark.tf @@ -1414,7 +1419,7 @@ def test_multiple_expval(self, device): """Return multiple expvals.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1438,7 +1443,7 @@ def test_multiple_var(self, device): """Return multiple vars.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1476,7 +1481,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1509,7 +1514,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1551,10 +1556,10 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import tensorflow as tf - if device in ["default.mixed", "default.qubit"]: + if device in [DefaultMixed, DefaultQubit]: pytest.skip("Sample must be reworked with interfaces.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1578,9 +1583,9 @@ def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" import tensorflow as tf - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Mixed as array must be reworked for shots.") def circuit(x): @@ -1607,7 +1612,7 @@ def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" import tensorflow as tf - dev = qml.device(device, wires=wires) + dev = device(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -1631,13 +1636,13 @@ def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" import tensorflow as tf - if device == "default.mixed" and shot_vector: + if device == DefaultMixed and shot_vector: pytest.skip("No support for shot vector and Tensorflow because use of .T in statistics") - if device == "default.qubit.tf" and shot_vector: + if device == DefaultQubitTF and shot_vector: pytest.skip("No support for shot vector and mixed device with Tensorflow.") - dev = qml.device(device, wires=wires, shots=shot_vector) + dev = device(wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -1664,7 +1669,7 @@ def circuit(x): assert t.shape == () -devices = ["default.qubit.torch", "default.mixed"] +devices = [DefaultQubitTorch, DefaultMixed] @pytest.mark.torch @@ -1678,7 +1683,7 @@ def test_multiple_expval(self, device): """Return multiple expvals.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1702,7 +1707,7 @@ def test_multiple_var(self, device): """Return multiple vars.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1740,7 +1745,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1773,7 +1778,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1815,10 +1820,10 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import torch - if device in ["default.mixed", "default.qubit"]: + if device in [DefaultMixed, DefaultQubit]: pytest.skip("Sample need to be rewritten for interfaces.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1842,10 +1847,10 @@ def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" import torch - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Counts need to be rewritten for interfaces.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1871,7 +1876,7 @@ def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" import torch - dev = qml.device(device, wires=wires) + dev = device(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -1896,10 +1901,10 @@ def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" import torch - if device == "default.mixed" and shot_vector: + if device == DefaultMixed and shot_vector: pytest.skip("No support for shot vector and mixed device with Torch.") - dev = qml.device(device, wires=wires, shots=shot_vector) + dev = device(wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -1926,7 +1931,7 @@ def circuit(x): assert t.shape == () -devices = ["default.qubit.jax", "default.mixed"] +devices = [DefaultQubitJax, DefaultMixed] @pytest.mark.jax @@ -1943,7 +1948,7 @@ def test_multiple_expval(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1970,7 +1975,7 @@ def test_multiple_var(self, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2011,7 +2016,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2047,7 +2052,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2092,10 +2097,10 @@ def test_expval_sample(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Sample need to be rewritten for interfaces.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -2122,10 +2127,10 @@ def test_expval_counts(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == "default.mixed": + if device == DefaultMixed: pytest.skip("Counts need to be rewritten for interfaces and mixed device.") - dev = qml.device(device, wires=2, shots=shots) + dev = device(wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -2154,7 +2159,7 @@ def test_list_one_expval(self, wires, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=wires) + dev = device(wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -2181,10 +2186,10 @@ def test_list_multiple_expval(self, wires, device, shot_vector): config.update("jax_enable_x64", True) import jax - if device == "default.mixed" and shot_vector: + if device == DefaultMixed and shot_vector: pytest.skip("No support for shot vector and mixed device with Jax") - dev = qml.device(device, wires=wires, shots=shot_vector) + dev = device(wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2236,7 +2241,7 @@ def circuit(x): shot_vectors = [[10, 1000], [1, 10, 10, 1000], [1, (10, 2), 1000]] -devices = ["default.qubit", "default.mixed"] +devices = [DefaultQubit, DefaultMixed] @pytest.mark.parametrize("device", devices) @@ -2247,7 +2252,7 @@ class TestIntegrationShotVectors: @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2267,7 +2272,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, shot_vector, op, wires, device): """Test a single probability measurement.""" - dev = qml.device("default.qubit", wires=2, shots=shot_vector) + dev = DefaultQubit(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2291,7 +2296,7 @@ def circuit(x): @pytest.mark.xfail def test_density_matrix(self, shot_vector, wires, device): """Test a density matrix measurement.""" - dev = qml.device(device, wires=3, shots=shot_vector) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2312,7 +2317,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2338,7 +2343,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2364,7 +2369,7 @@ class TestIntegrationSameMeasurementShotVector: def test_scalar(self, shot_vector, device): """Test multiple scalar-valued measurements.""" - dev = qml.device(device, wires=2, shots=shot_vector) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2394,7 +2399,7 @@ def circuit(x): @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) + dev = device(wires=4, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2420,7 +2425,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2443,7 +2448,7 @@ def circuit(x): @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) + dev = device(wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2533,7 +2538,7 @@ class TestIntegrationMultipleMeasurementsShotVector: @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) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2564,7 +2569,7 @@ def circuit(x): 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) + dev = 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) ] @@ -2597,7 +2602,7 @@ def circuit(x): @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) + dev = device(wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2628,7 +2633,7 @@ def circuit(x): 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) + dev = 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) ] @@ -2668,7 +2673,7 @@ def circuit(x): @pytest.mark.xfail 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) + dev = 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) @@ -2701,7 +2706,7 @@ def circuit(x): @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) + dev = 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) @@ -2748,7 +2753,7 @@ def circuit(x): @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) + dev = 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) ] @@ -2796,7 +2801,7 @@ def circuit(x): 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) + dev = 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) ] @@ -2847,7 +2852,7 @@ def circuit(x): 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) + dev = 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) ] @@ -2905,7 +2910,7 @@ class TestIntegrationJacobianBackpropMultipleReturns: @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_expval_autograd(self, interface, device): """Return Jacobian of multiple expvals.""" - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2932,7 +2937,7 @@ def test_multiple_expval_torch(self, interface, device): """Return Jacobian of multiple expvals.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2959,7 +2964,7 @@ def test_multiple_expval_tf(self, interface, device): """Return Jacobian of multiple expvals.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2986,7 +2991,7 @@ def test_multiple_meas_tf_autograph(self, interface): """Return Jacobian of multiple measurements with Tf Autograph.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2) + dev = DefaultQubit(wires=2) @tf.function @qml.qnode(dev, interface=interface) @@ -3020,7 +3025,7 @@ def test_multiple_expval_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3049,7 +3054,7 @@ def test_multiple_expval_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3072,7 +3077,7 @@ def circuit(a): @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_probs_autograd(self, interface, device): """Return Jacobian of multiple probs.""" - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3099,7 +3104,7 @@ def test_multiple_probs_torch(self, interface, device): """Return Jacobian of multiple probs.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3126,7 +3131,7 @@ def test_multiple_probs_tf(self, interface, device): """Return Jacobian of multiple probs.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3157,7 +3162,7 @@ def test_multiple_probs_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3187,7 +3192,7 @@ def test_multiple_probs_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3211,7 +3216,7 @@ def circuit(a): @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_meas_autograd(self, interface, device): """Return Jacobian of multiple measurements.""" - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3238,7 +3243,7 @@ def test_multiple_meas_torch(self, interface, device): """Return Jacobian of multiple measurements.""" import torch - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3270,7 +3275,7 @@ def test_multiple_meas_tf(self, interface, device): """Return Jacobian of multiple measurements.""" import tensorflow as tf - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3305,7 +3310,7 @@ def test_multiple_meas_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3340,7 +3345,7 @@ def test_multiple_meas_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = qml.device(device, wires=2) + dev = device(wires=2) @qml.qnode(dev, interface=interface) def circuit(a): 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 073b2f43707..504690001b4 100644 --- a/tests/test_vqe.py +++ b/tests/test_vqe.py @@ -221,7 +221,7 @@ def mock_device_fixture(monkeypatch): m.setattr(qml.Device, "apply", lambda self, x, y, z: None) def get_device(wires=1): - return qml.Device(wires=wires) + return qml.Device(wires=wires) # pylint:disable=abstract-class-instantiated yield get_device @@ -347,15 +347,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) @@ -393,15 +397,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) @@ -439,15 +445,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) @@ -495,15 +503,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) @@ -551,15 +561,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) @@ -607,19 +619,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 @@ -648,12 +663,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) @@ -752,7 +768,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) @@ -845,10 +861,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) @@ -859,12 +879,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.""" @@ -911,7 +932,7 @@ def circuit2(): assert res[0] == circuit1() assert res[1] == circuit2() - def test_error_multiple_expvals_same_wire(self): + def test_multiple_expvals_same_wire_supported(self): """Tests that more than one Hamiltonian expval can be evaluated.""" coeffs = [1.0, 1.0, 1.0] @@ -924,8 +945,8 @@ def circuit(): qml.templates.StronglyEntanglingLayers(w, wires=range(4)) return qml.expval(H1), qml.expval(H1) - with pytest.raises(qml.QuantumFunctionError, match="Only observables that are qubit-wise"): - circuit() + res1, res2 = circuit() + assert np.isclose(res1, res2) def test_error_var_measurement(self): """Tests that error is thrown if var(H) is measured.""" @@ -938,9 +959,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): @@ -954,7 +973,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 @@ -1005,7 +1024,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) From e756ed0d89af4997b97054b9c34ad877682b640e Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 9 Aug 2023 14:04:14 -0400 Subject: [PATCH 07/78] only squeeze the 1-wire dim when sampling a pauli obs; tape test fixes --- pennylane/measurements/sample.py | 4 +- tests/tape/test_qscript.py | 86 +++++++++++++------------------- tests/tape/test_tape.py | 84 +++++++++++++++++-------------- 3 files changed, 83 insertions(+), 91 deletions(-) diff --git a/pennylane/measurements/sample.py b/pennylane/measurements/sample.py index 4bb3c4f1b12..89f40c78cf8 100644 --- a/pennylane/measurements/sample.py +++ b/pennylane/measurements/sample.py @@ -229,9 +229,7 @@ def process_samples( if str(name) in {"PauliX", "PauliY", "PauliZ", "Hadamard"}: # Process samples for observables with eigenvalues {1, -1} - samples = 1 - 2 * qml.math.squeeze(samples) - if samples.shape == (): - samples = samples.reshape((1,)) + samples = 1 - 2 * qml.math.squeeze(samples, axis=-1) else: # Replace the basis state in the computational basis with the correct eigenvalue. # Extract only the columns of the basis samples required based on ``wires``. diff --git a/tests/tape/test_qscript.py b/tests/tape/test_qscript.py index c5576505c5d..dcdad5bef71 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -906,13 +906,16 @@ def test_diagonalizing_gates_not_queued(self): (qml.var(qml.PauliZ(0)), ()), (qml.probs(wires=[0]), (2,)), (qml.probs(wires=[0, 1]), (4,)), - (qml.state(), (8,)), # Assumes 3-qubit device + (qml.state(), (2,)), (qml.density_matrix(wires=[0, 1]), (4, 4)), ( qml.sample(qml.PauliZ(0)), None, ), # Shape is None because the expected shape is in the test case - (qml.sample(), None), # Shape is None because the expected shape is in the test case + ( + qml.sample(wires=[0, 1, 2]), + None, + ), # Shape is None because the expected shape is in the test case (qml.mutual_info(wires0=[0], wires1=[1]), ()), (qml.vn_entropy(wires=[0, 1]), ()), ] @@ -928,12 +931,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""" @@ -1030,7 +1027,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: @@ -1051,10 +1048,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) @@ -1062,15 +1057,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) @@ -1132,7 +1122,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 @@ -1166,7 +1156,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) @@ -1191,7 +1181,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)) @@ -1229,7 +1221,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 @@ -1257,7 +1249,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) @@ -1276,7 +1268,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) @@ -1297,11 +1291,9 @@ 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 - ) + expected = tuple(tuple(() if s == 1 else (s,) for _ in range(num_samples)) for s in shots) res = qs.shape(dev) assert res == expected @@ -1321,7 +1313,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): @@ -1346,21 +1338,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,) @@ -1387,18 +1371,20 @@ def test_complex_state(self, ret): assert np.issubdtype(result.dtype, complex) assert qs.numeric_type is complex - @pytest.mark.parametrize("ret", [qml.sample(), qml.sample(qml.PauliZ(wires=0))]) - def test_sample_int_eigvals(self, ret): + @pytest.mark.parametrize( + "ret, dtype", [(qml.sample(), np.bool8), (qml.sample(qml.PauliZ(wires=0)), np.int64)] + ) + def test_sample_int_eigvals(self, ret, dtype): """Test that the tape can correctly determine the output domain for a 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] # Double-check the domain of the QNode output - assert np.issubdtype(result.dtype, np.int64) + assert np.issubdtype(result.dtype, dtype) assert qs.numeric_type is int # TODO: add cases for each interface once qml.Hermitian supports other @@ -1416,7 +1402,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] @@ -1442,7 +1428,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 6b167173423..fa99b31513d 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -1424,31 +1424,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: @@ -1580,11 +1575,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 @@ -1599,6 +1595,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,) @@ -1616,6 +1613,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) @@ -1637,22 +1635,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) @@ -2002,13 +2005,16 @@ def cost(tape, dev): (qml.var(qml.PauliZ(0)), ()), (qml.probs(wires=[0]), (2,)), (qml.probs(wires=[0, 1]), (4,)), - (qml.state(), (8,)), # Assumes 3-qubit device + (qml.state(), (2,)), (qml.density_matrix(wires=[0, 1]), (4, 4)), ( qml.sample(qml.PauliZ(0)), None, ), # Shape is None because the expected shape is in the test case - (qml.sample(), None), # Shape is None because the expected shape is in the test case + ( + qml.sample(wires=[0, 1, 2]), + None, + ), # Shape is None because the expected shape is in the test case ] multi_measurements = [ @@ -2046,7 +2052,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,) @@ -2090,7 +2096,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): @@ -2166,7 +2172,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) @@ -2205,7 +2211,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) @@ -2228,7 +2234,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: @@ -2254,7 +2260,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: @@ -2291,7 +2297,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 @@ -2318,7 +2324,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 @@ -2371,8 +2377,10 @@ def circuit(a, b): assert np.issubdtype(result.dtype, complex) assert circuit.qtape.numeric_type is complex - @pytest.mark.parametrize("ret", [qml.sample(), qml.sample(qml.PauliZ(wires=0))]) - def test_sample_int_eigvals(self, ret): + @pytest.mark.parametrize( + "ret,dtype", [(qml.sample(), bool), (qml.sample(qml.PauliZ(wires=0)), int)] + ) + def test_sample_int_eigvals(self, ret, dtype): """Test that the tape can correctly determine the output domain for a sampling measurement with a Hermitian observable with integer eigenvalues.""" @@ -2386,7 +2394,7 @@ def circuit(): result = circuit() # Double-check the domain of the QNode output - assert np.issubdtype(result.dtype, int) + assert np.issubdtype(result.dtype, dtype) assert circuit.qtape.numeric_type is int # TODO: add cases for each interface once qml.Hermitian supports other @@ -2413,7 +2421,7 @@ def circuit(a, b): result = circuit(0.3, 0.2) # Double-check the domain of the QNode output - assert np.issubdtype(result[0].dtype, float) + assert np.issubdtype(result[0].dtype, float) # pylint:disable=unsubscriptable-object assert circuit.qtape.numeric_type is float @pytest.mark.autograd @@ -2421,7 +2429,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( [ @@ -2440,8 +2448,8 @@ def circuit(a, b): result = circuit(0, 3) assert isinstance(result, tuple) assert len(result) == 2 - assert result[0].dtype == float - assert result[1].dtype == int + assert result[0].dtype == float # pylint:disable=no-member + assert result[1].dtype == int # pylint:disable=no-member assert circuit.qtape.numeric_type == (float, int) From d725ccc420934a00cd62ad29f9cc655a706c488d Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 9 Aug 2023 14:07:19 -0400 Subject: [PATCH 08/78] add old default.qubit as default.qubit.legacy --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b7e63a257a4..68aa6d24ffc 100644 --- a/setup.py +++ b/setup.py @@ -49,6 +49,7 @@ "pennylane.plugins": [ "default.qubit = pennylane.devices.experimental:DefaultQubit2", "default.gaussian = pennylane.devices:DefaultGaussian", + "default.qubit.legacy = pennylane.devices:DefaultQubit", "default.qubit.tf = pennylane.devices.default_qubit_tf:DefaultQubitTF", "default.qubit.torch = pennylane.devices.default_qubit_torch:DefaultQubitTorch", "default.qubit.autograd = pennylane.devices.default_qubit_autograd:DefaultQubitAutograd", From 6abc713f1ccbc0c87a8252013cfbe621e44accf1 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 10 Aug 2023 16:36:10 -0400 Subject: [PATCH 09/78] fix the transforms module --- pennylane/ops/qubit/state_preparation.py | 2 +- pennylane/qnode.py | 4 ++- pennylane/templates/embeddings/amplitude.py | 7 ++-- pennylane/transforms/metric_tensor.py | 17 ++++----- pennylane/transforms/qcut/cutstrategy.py | 6 ++-- pennylane/transforms/qcut/montecarlo.py | 6 ++-- pennylane/transforms/specs.py | 6 +++- .../transforms/test_adjoint_metric_tensor.py | 28 +++++++-------- tests/transforms/test_batch_input.py | 9 ++--- tests/transforms/test_batch_params.py | 24 +++++++------ tests/transforms/test_batch_transform.py | 10 +++--- tests/transforms/test_hamiltonian_expand.py | 30 ++++++++-------- tests/transforms/test_metric_tensor.py | 5 ++- .../test_merge_amplitude_embedding.py | 16 ++++----- tests/transforms/test_qcut.py | 7 ++-- tests/transforms/test_qmc_transform.py | 2 +- tests/transforms/test_sign_expand.py | 8 ++--- tests/transforms/test_specs.py | 36 ++++++++++++------- tests/transforms/test_tape_expand.py | 34 +++++++++--------- 19 files changed, 145 insertions(+), 112 deletions(-) diff --git a/pennylane/ops/qubit/state_preparation.py b/pennylane/ops/qubit/state_preparation.py index 54fdd010127..3e55bf36b6c 100644 --- a/pennylane/ops/qubit/state_preparation.py +++ b/pennylane/ops/qubit/state_preparation.py @@ -204,7 +204,7 @@ def state_vector(self, wire_order=None): wire_order = Wires(wire_order) if not wire_order.contains_wires(self.wires): - raise WireError("Custom wire_order must contain all QubitStateVector wires") + raise WireError(f"Custom wire_order must contain all {self.name} wires") num_total_wires = len(wire_order) indices = tuple( diff --git a/pennylane/qnode.py b/pennylane/qnode.py index 85518d449fd..9d744b5ad29 100644 --- a/pennylane/qnode.py +++ b/pennylane/qnode.py @@ -905,7 +905,9 @@ def construct(self, args, kwargs): # pylint: disable=too-many-branches if any(isinstance(m, MidMeasureMP) for m in self.tape.operations): self._tape = qml.defer_measurements(self._tape) - if self.expansion_strategy == "device": + if self.expansion_strategy == "device" and not isinstance( + self.device, qml.devices.experimental.Device + ): self._tape = self.device.expand_fn(self.tape, max_expansion=self.max_expansion) # If the gradient function is a transform, expand the tape so that diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index 5ea33431a37..dd08a58a53d 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -18,7 +18,7 @@ import numpy as np import pennylane as qml -from pennylane.operation import Operation, AnyWires +from pennylane.operation import AnyWires, StatePrep from pennylane.ops import QubitStateVector from pennylane.wires import Wires @@ -26,7 +26,7 @@ TOLERANCE = 1e-10 -class AmplitudeEmbedding(Operation): +class AmplitudeEmbedding(StatePrep): r"""Encodes :math:`2^n` features into the amplitude vector of :math:`n` qubits. By setting ``pad_with`` to a real or complex number, ``features`` is automatically padded to dimension @@ -138,6 +138,9 @@ def num_params(self): def ndim_params(self): return (1,) + def state_vector(self, wire_order=None): + return QubitStateVector(self.data[0], wires=self.wires).state_vector(wire_order=wire_order) + @staticmethod def compute_decomposition(features, wires): # pylint: disable=arguments-differ r"""Representation of the operator as a product of other operators. diff --git a/pennylane/transforms/metric_tensor.py b/pennylane/transforms/metric_tensor.py index cef48b5c3b0..e3d01d6dde0 100644 --- a/pennylane/transforms/metric_tensor.py +++ b/pennylane/transforms/metric_tensor.py @@ -17,9 +17,9 @@ """ import functools import warnings +import numpy as np import pennylane as qml -from pennylane import numpy as np from pennylane.circuit_graph import LayerData from .batch_transform import batch_transform @@ -841,14 +841,15 @@ def processing_fn(results): # Rescale first and second term coeffs_gen = (c for c in qml.math.hstack(coeffs_list)) # flattened coeffs_list but also with 0s where parameters are not in argnum - extended_coeffs_list = [ - next(coeffs_gen) if param_in_argnum else 0.0 - for param_in_argnum in qml.math.hstack(in_argnum_list) - ] - - scale = qml.math.convert_like( - qml.math.tensordot(extended_coeffs_list, extended_coeffs_list, axes=0), results[0] + interface = qml.math.get_interface(*results) + extended_coeffs_list = qml.math.asarray( + [ + next(coeffs_gen) if param_in_argnum else 0.0 + for param_in_argnum in qml.math.hstack(in_argnum_list) + ], + like=interface, ) + scale = qml.math.tensordot(extended_coeffs_list, extended_coeffs_list, axes=0) off_diag_mt = scale * off_diag_mt # Combine block-diagonal and off block-diagonal diff --git a/pennylane/transforms/qcut/cutstrategy.py b/pennylane/transforms/qcut/cutstrategy.py index b9f47b245c1..a79d67918a3 100644 --- a/pennylane/transforms/qcut/cutstrategy.py +++ b/pennylane/transforms/qcut/cutstrategy.py @@ -125,16 +125,16 @@ def __post_init__( if devices is None and self.max_free_wires is None: raise ValueError("One of arguments `devices` and max_free_wires` must be provided.") - if isinstance(devices, qml.Device): + if isinstance(devices, (qml.Device, qml.devices.experimental.Device)): devices = (devices,) if devices is not None: if not isinstance(devices, SequenceType) or any( - (not isinstance(d, qml.Device) for d in devices) + (not isinstance(d, (qml.Device, qml.devices.experimental.Device)) for d in devices) ): raise ValueError( "Argument `devices` must be a list or tuple containing elements of type " - "`qml.Device`" + "`qml.Device` or `qml.devices.experimental.Device`" ) device_wire_sizes = [len(d.wires) for d in devices] diff --git a/pennylane/transforms/qcut/montecarlo.py b/pennylane/transforms/qcut/montecarlo.py index 21d750dee95..5518fa661fe 100644 --- a/pennylane/transforms/qcut/montecarlo.py +++ b/pennylane/transforms/qcut/montecarlo.py @@ -499,11 +499,13 @@ def _wrapper(*args, **kwargs): shots = kwargs.pop("shots", False) shots = shots or qnode.device.shots - if shots is None: + if not shots: raise ValueError( "A shots value must be provided in the device " "or when calling the QNode to be cut" ) + if isinstance(shots, qml.measurements.Shots): + shots = shots.total_shots qnode.construct(args, kwargs) tapes, processing_fn = self.construct(qnode.qtape, *targs, **tkwargs, shots=shots) @@ -706,7 +708,7 @@ def expand_fragment_tapes_mc( meas_w = op.wires[0] MC_MEASUREMENTS[meas_settings[op.id][shot]](meas_w) - frag_config.append(QuantumScript.from_queue(q)) + frag_config.append(QuantumScript.from_queue(q, shots=1)) all_configs.append(frag_config) diff --git a/pennylane/transforms/specs.py b/pennylane/transforms/specs.py index 29fe2c2fc37..da03b023827 100644 --- a/pennylane/transforms/specs.py +++ b/pennylane/transforms/specs.py @@ -123,7 +123,11 @@ def specs_qnode(*args, **kwargs): info = qnode.qtape.specs.copy() - info["num_device_wires"] = getattr(qnode.device, "num_wires", None) + info["num_device_wires"] = ( + len(qnode.tape.wires) + if isinstance(qnode.device, qml.devices.experimental.Device) + else len(qnode.device.wires) + ) info["device_name"] = getattr(qnode.device, "short_name", qnode.device.name) info["expansion_strategy"] = qnode.expansion_strategy info["gradient_options"] = qnode.gradient_kwargs diff --git a/tests/transforms/test_adjoint_metric_tensor.py b/tests/transforms/test_adjoint_metric_tensor.py index 7da01150797..35d4b8478cb 100644 --- a/tests/transforms/test_adjoint_metric_tensor.py +++ b/tests/transforms/test_adjoint_metric_tensor.py @@ -26,7 +26,7 @@ class TestApplyOperations: """Tests the application of operations via the helper function _apply_operations used in the adjoint metric tensor.""" - device = qml.device("default.qubit", wires=2) + device = qml.device("default.qubit.legacy", wires=2) x = 0.5 def test_simple_operation(self): @@ -393,7 +393,7 @@ def fubini_ansatz10(weights, wires=None): def autodiff_metric_tensor(ansatz, num_wires): """Compute the metric tensor by full state vector differentiation via autograd.""" - dev = qml.device("default.qubit", wires=num_wires) + dev = qml.device("default.qubit.legacy", wires=num_wires) @qml.qnode(dev) def qnode(*params): @@ -565,7 +565,7 @@ def test_correct_output_qnode_autograd(self, ansatz, params, interface): """Test that the output is correct when using Autograd and calling the adjoint metric tensor on a QNode.""" expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) - dev = qml.device("default.qubit", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -594,7 +594,7 @@ def test_correct_output_qnode_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", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface="jax") def circuit(*params): @@ -650,7 +650,7 @@ def test_correct_output_qnode_tf(self, ansatz, params, interface): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) t_params = tuple(tf.Variable(p, dtype=tf.float64) for p in params) - dev = qml.device("default.qubit", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -674,7 +674,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) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) dev2 = qml.device("default.qubit.autograd", wires=self.num_wires) @qml.qnode(dev) @@ -718,7 +718,7 @@ def test_autograd(self, ansatz, params): calling the adjoint metric tensor on a QNode.""" exp_fn = autodiff_metric_tensor(ansatz, self.num_wires) expected = qml.jacobian(exp_fn)(*params) - dev = qml.device("default.qubit", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface="autograd") def circuit(*params): @@ -745,7 +745,7 @@ def test_correct_output_qnode_jax(self, ansatz, params): expected = qml.jacobian(autodiff_metric_tensor(ansatz, self.num_wires))(*params) j_params = tuple(jax.numpy.array(p) for p in params) - dev = qml.device("default.qubit", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface="jax") def circuit(*params): @@ -773,7 +773,7 @@ def test_correct_output_qnode_torch(self, ansatz, params): expected = qml.jacobian(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", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface="torch") def circuit(*params): @@ -798,7 +798,7 @@ def test_correct_output_qnode_tf(self, ansatz, params): expected = qml.jacobian(autodiff_metric_tensor(ansatz, self.num_wires))(*params) t_params = tuple(tf.Variable(p, dtype=tf.float64) for p in params) - dev = qml.device("default.qubit", wires=self.num_wires) + dev = qml.device("default.qubit.legacy", wires=self.num_wires) @qml.qnode(dev, interface="tf") def circuit(*params): @@ -828,7 +828,7 @@ def ansatz(x, y): qml.RX(x, wires=0) qml.RY(y, wires=1) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with pytest.raises(qml.QuantumFunctionError, match="The passed object is not a "): qml.adjoint_metric_tensor(ansatz, device=dev) @@ -839,7 +839,7 @@ def test_error_finite_shots(self): qml.RX(0.2, wires=0) qml.RY(1.9, wires=1) tape = qml.tape.QuantumScript.from_queue(q) - dev = qml.device("default.qubit", wires=2, shots=1) + dev = qml.device("default.qubit.legacy", wires=2, shots=1) with pytest.raises(ValueError, match="The adjoint method for the metric tensor"): qml.adjoint_metric_tensor(tape, device=dev) @@ -847,8 +847,8 @@ def test_error_finite_shots(self): def test_warning_multiple_devices(self): """Test that a warning is issued if an ExpvalCost with multiple devices is passed.""" - dev1 = qml.device("default.qubit", wires=2) - dev2 = qml.device("default.qubit", wires=1) + dev1 = qml.device("default.qubit.legacy", wires=2) + dev2 = qml.device("default.qubit.legacy", wires=1) H = qml.Hamiltonian([0.2, 0.9], [qml.PauliZ(0), qml.PauliY(0)]) def ansatz(x, wires): diff --git a/tests/transforms/test_batch_input.py b/tests/transforms/test_batch_input.py index 26c12d4269b..cd632d7ab11 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 import pytest import pennylane as qml @@ -181,7 +181,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 @@ -220,7 +220,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 @@ -283,6 +283,7 @@ def circuit(inputs, weights): assert isinstance(res, tuple) assert len(res) == 5 + # pylint:disable=not-an-iterable assert all(shot_res.shape == (batch_size, 4) for shot_res in res) @@ -858,7 +859,7 @@ def test_unbatched_not_copied(): tape = qml.tape.QuantumScript(ops, meas) tape.trainable_params = [0, 2] - new_tapes = qml.batch_input(argnum=1)(tape)[0] + new_tapes = qml.batch_input(argnum=1)(tape)[0] # pylint:disable=not-callable assert len(new_tapes) == batch_size for new_tape in new_tapes: diff --git a/tests/transforms/test_batch_params.py b/tests/transforms/test_batch_params.py index 626c3f06984..da0232c9e8e 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 @@ -556,7 +558,7 @@ def test_jax(self, diff_method, tol, interface): jax.config.update("jax_enable_x64", True) dev = qml.device("default.qubit", wires=2) - @qml.batch_params(all_operations=True) + @qml.batch_params(all_operations=True) # pylint:disable=no-value-for-parameter @qml.qnode(dev, diff_method=diff_method, interface=interface) def circuit(x): qml.RY(x, wires=0) @@ -606,7 +608,7 @@ def test_jax_jit(self, diff_method, tol, interface): dev = qml.device("default.qubit", wires=2) @jax.jit - @qml.batch_params(all_operations=True) + @qml.batch_params(all_operations=True) # pylint:disable=no-value-for-parameter @qml.qnode(dev, diff_method=diff_method, interface=interface) def circuit(x): qml.RY(x, wires=0) @@ -800,7 +802,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 b01e457a5b9..c009b82e825 100644 --- a/tests/transforms/test_batch_transform.py +++ b/tests/transforms/test_batch_transform.py @@ -340,7 +340,7 @@ def test_parametrized_transform_device(self, mocker): b = 0.4 x = 0.543 - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) dev = self.my_transform(dev, a, b) @qml.qnode(dev, interface="autograd") @@ -371,7 +371,7 @@ def test_parametrized_transform_device_decorator(self, mocker): b = 0.4 x = 0.543 - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) dev = self.my_transform(a, b)(dev) # pylint: disable=no-value-for-parameter @qml.qnode(dev, interface="autograd") @@ -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): @@ -664,7 +664,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 56736052775..eb5ddea02ad 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]) @@ -295,6 +295,8 @@ def test_hamiltonian_dif_tensorflow(self): with AnnotatedQueue() as s_tape1: qml.PauliX(0) + for i in range(4): + qml.Identity(i) S1 = qml.s_prod(1.5, qml.prod(qml.PauliZ(0), qml.PauliZ(1))) qml.expval(S1) qml.expval(S1) @@ -406,7 +408,7 @@ def test_observables_on_same_wires(self): def test_sums(self, qscript, output): """Tests that the sum_expand transform returns the correct value""" 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)) @@ -416,7 +418,7 @@ def test_sums_no_grouping(self, qscript, output): """Tests that the sum_expand transform returns the correct value if we switch grouping off""" 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 +561,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..2b36fd01d14 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) @@ -1745,6 +1747,7 @@ def circuit_multi_block(x, z): assert len(recwarn) == 0 +@pytest.mark.xfail(reason="The new default.qubit does not enforce tape wires") def test_raises_circuit_that_uses_missing_wire(): """Test that an error in the original circuit is reraised properly and not caught. This avoids accidentally catching relevant errors, which can lead to a recursion error.""" diff --git a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py index 935def9795b..066007f0578 100644 --- a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py +++ b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py @@ -41,7 +41,7 @@ def qfunc(): assert len(ops) == 3 # Check that the solution is as expected. - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) assert np.allclose(qml.QNode(transformed_qfunc, dev)()[-1], 1) def test_repeated_qubit(self): @@ -53,7 +53,7 @@ def qfunc(): transformed_qfunc = merge_amplitude_embedding(qfunc) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qnode = qml.QNode(transformed_qfunc, dev) with pytest.raises(DeviceError, match="applied in the same qubit"): @@ -69,13 +69,13 @@ def qfunc(): return qml.state() - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) qnode = qml.QNode(qfunc, dev) assert qnode()[3] == 1.0 def test_broadcasting(self): """Test that merging preserves the batch dimension""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) @qml.transforms.merge_amplitude_embedding @@ -105,7 +105,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -123,7 +123,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -141,7 +141,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -162,7 +162,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) diff --git a/tests/transforms/test_qcut.py b/tests/transforms/test_qcut.py index 78dbc160ad6..162b9280165 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 @@ -3717,7 +3718,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) @@ -4631,7 +4632,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.experimental.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 d59b56022c2..f54af3f7b32 100644 --- a/tests/transforms/test_sign_expand.py +++ b/tests/transforms/test_sign_expand.py @@ -96,7 +96,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) @@ -108,7 +108,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) @@ -151,7 +151,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) @@ -163,7 +163,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..375d409baaf 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)] ) @@ -99,15 +95,11 @@ def circuit(x, y, add_RY=True): assert info["num_device_wires"] == 4 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.2" 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 diff --git a/tests/transforms/test_tape_expand.py b/tests/transforms/test_tape_expand.py index 258acb743c1..82f5ecdfb3a 100644 --- a/tests/transforms/test_tape_expand.py +++ b/tests/transforms/test_tape_expand.py @@ -64,7 +64,7 @@ def test_device_and_stopping_expansion(self): """Test that passing a device alongside a stopping condition ensures that all operations are expanded to match the devices default gate set""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) expand_fn = qml.transforms.create_expand_fn(device=dev, depth=10, stop_at=self.crit_0) with qml.queuing.AnnotatedQueue() as q: @@ -80,7 +80,7 @@ def test_device_and_stopping_expansion(self): def test_device_only_expansion(self): """Test that passing a device ensures that all operations are expanded to match the devices default gate set""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) expand_fn = qml.transforms.create_expand_fn(device=dev, depth=10) with qml.queuing.AnnotatedQueue() as q: @@ -432,8 +432,8 @@ def circuit(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - original_dev = qml.device("default.qubit", wires=3) - decomp_dev = qml.device("default.qubit", wires=3, custom_decomps={}) + original_dev = qml.device("default.qubit.legacy", wires=3) + decomp_dev = qml.device("default.qubit.legacy", wires=3, custom_decomps={}) original_qnode = qml.QNode(circuit, original_dev, expansion_strategy="device") decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") @@ -457,8 +457,8 @@ def circuit(): qml.BasicEntanglerLayers([[0.1, 0.2]], wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - original_dev = qml.device("default.qubit", wires=3) - decomp_dev = qml.device("default.qubit", wires=3, custom_decomps={}) + original_dev = qml.device("default.qubit.legacy", wires=3) + decomp_dev = qml.device("default.qubit.legacy", wires=3, custom_decomps={}) original_qnode = qml.QNode(circuit, original_dev, expansion_strategy="device") decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") @@ -474,7 +474,7 @@ def circuit(): ) ] - @pytest.mark.parametrize("device_name", ["default.qubit", "lightning.qubit"]) + @pytest.mark.parametrize("device_name", ["default.qubit.legacy", "lightning.qubit"]) def test_one_custom_decomp(self, device_name): """Test that specifying a single custom decomposition works as expected.""" @@ -509,7 +509,7 @@ def circuit(): custom_decomps = {"Hadamard": custom_hadamard, "CNOT": custom_cnot} decomp_dev = qml.device( - "default.qubit", wires=2, custom_decomps=custom_decomps, decomp_depth=0 + "default.qubit.legacy", wires=2, custom_decomps=custom_decomps, decomp_depth=0 ) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() @@ -529,8 +529,8 @@ def circuit(x): qml.Hadamard(wires=0) return qml.expval(qml.PauliZ(0)) - original_dev = qml.device("default.qubit", wires=3) - decomp_dev = qml.device("default.qubit", wires=3, custom_decomps={"Rot": custom_rot}) + original_dev = qml.device("default.qubit.legacy", wires=3) + decomp_dev = qml.device("default.qubit.legacy", wires=3, custom_decomps={"Rot": custom_rot}) original_qnode = qml.QNode(circuit, original_dev, expansion_strategy="device") decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") @@ -558,7 +558,7 @@ def circuit(): return qml.expval(qml.PauliZ(0)) custom_decomps = {"Hadamard": custom_hadamard, qml.CNOT: custom_cnot} - decomp_dev = qml.device("default.qubit", wires=2, custom_decomps=custom_decomps) + decomp_dev = qml.device("default.qubit.legacy", wires=2, custom_decomps=custom_decomps) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() decomp_ops = decomp_qnode.qtape.operations @@ -596,7 +596,7 @@ def circuit(): return qml.expval(qml.PauliZ(0)) custom_decomps = {"Hadamard": custom_hadamard, qml.CNOT: custom_cnot} - decomp_dev = qml.device("default.qubit", wires=2, custom_decomps=custom_decomps) + decomp_dev = qml.device("default.qubit.legacy", wires=2, custom_decomps=custom_decomps) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() decomp_ops = decomp_qnode.qtape.operations @@ -640,7 +640,7 @@ def circuit(): # BasicEntanglerLayers custom decomposition involves AngleEmbedding custom_decomps = {"BasicEntanglerLayers": custom_basic_entangler_layers, "RX": custom_rx} - decomp_dev = qml.device("default.qubit", wires=2, custom_decomps=custom_decomps) + decomp_dev = qml.device("default.qubit.legacy", wires=2, custom_decomps=custom_decomps) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() decomp_ops = decomp_qnode.qtape.operations @@ -677,7 +677,7 @@ def circuit(): # not be further decomposed even though the custom decomposition is specified. custom_decomps = {"BasicEntanglerLayers": custom_basic_entangler_layers, "RX": custom_rx} decomp_dev = qml.device( - "default.qubit", wires=2, custom_decomps=custom_decomps, decomp_depth=2 + "default.qubit.legacy", wires=2, custom_decomps=custom_decomps, decomp_depth=2 ) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() @@ -706,7 +706,7 @@ def circuit(): return qml.expval(qml.PauliZ("a")) custom_decomps = {qml.RX: custom_rx} - decomp_dev = qml.device("default.qubit", wires="a", custom_decomps=custom_decomps) + decomp_dev = qml.device("default.qubit.legacy", wires="a", custom_decomps=custom_decomps) decomp_qnode = qml.QNode(circuit, decomp_dev, expansion_strategy="device") _ = decomp_qnode() decomp_ops = decomp_qnode.qtape.operations @@ -732,7 +732,7 @@ def compute_decomposition(wire): return [qml.S(wire)] custom_decomps = {CustomOp: lambda wires: [qml.T(wires), qml.T(wires)]} - decomp_dev = qml.device("default.qubit", wires=2, custom_decomps=custom_decomps) + decomp_dev = qml.device("default.qubit.legacy", wires=2, custom_decomps=custom_decomps) @qml.qnode(decomp_dev, expansion_strategy="device") def circuit(): @@ -751,7 +751,7 @@ def circuit(): def test_custom_decomp_in_separate_context(self): """Test that the set_decomposition context manager works.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, expansion_strategy="device") def circuit(): From 55b1ac46b16cec4b7cdf8c601fdcb243a901017a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 10 Aug 2023 16:47:15 -0400 Subject: [PATCH 10/78] use the legacy short name instead of the constructor This reverts commit de4e5fa53cda43b1be6bf1409f9b29365c21d749. --- tests/conftest.py | 16 +- .../test_default_qubit_autograd.py | 63 ++- .../test_default_qubit_jax.py | 117 +++--- ..._qubit.py => test_default_qubit_legacy.py} | 119 +++--- ...test_default_qubit_legacy_broadcasting.py} | 69 ++-- .../test_default_qubit_tf.py | 109 +++--- .../test_default_qubit_torch.py | 77 ++-- tests/devices/test_lightning_qubit.py | 2 +- tests/test_debugging.py | 6 +- tests/test_device.py | 2 +- tests/test_operation.py | 2 +- tests/test_qnode.py | 164 ++++---- tests/test_return_types.py | 79 ++-- tests/test_return_types_qnode.py | 362 +++++++++--------- 14 files changed, 591 insertions(+), 596 deletions(-) rename tests/devices/{default_qubit_1 => }/test_default_qubit_autograd.py (91%) rename tests/devices/{default_qubit_1 => }/test_default_qubit_jax.py (93%) rename tests/devices/{default_qubit_1/test_default_qubit.py => test_default_qubit_legacy.py} (95%) rename tests/devices/{default_qubit_1/test_default_qubit_broadcasting.py => test_default_qubit_legacy_broadcasting.py} (96%) rename tests/devices/{default_qubit_1 => }/test_default_qubit_tf.py (96%) rename tests/devices/{default_qubit_1 => }/test_default_qubit_torch.py (96%) diff --git a/tests/conftest.py b/tests/conftest.py index 0e508325cb6..01f72658911 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -70,22 +70,28 @@ def n_subsystems_fixture(request): @pytest.fixture(scope="session") def qubit_device(n_subsystems): - return qml.device("default.qubit", wires=n_subsystems) + return qml.device("default.qubit.legacy", wires=n_subsystems) @pytest.fixture(scope="function", params=[(np.float32, np.complex64), (np.float64, np.complex128)]) def qubit_device_1_wire(request): - return qml.device("default.qubit", wires=1, r_dtype=request.param[0], c_dtype=request.param[1]) + return qml.device( + "default.qubit.legacy", wires=1, r_dtype=request.param[0], c_dtype=request.param[1] + ) @pytest.fixture(scope="function", params=[(np.float32, np.complex64), (np.float64, np.complex128)]) def qubit_device_2_wires(request): - return qml.device("default.qubit", wires=2, r_dtype=request.param[0], c_dtype=request.param[1]) + return qml.device( + "default.qubit.legacy", wires=2, r_dtype=request.param[0], c_dtype=request.param[1] + ) @pytest.fixture(scope="function", params=[(np.float32, np.complex64), (np.float64, np.complex128)]) def qubit_device_3_wires(request): - return qml.device("default.qubit", wires=3, r_dtype=request.param[0], c_dtype=request.param[1]) + return qml.device( + "default.qubit.legacy", wires=3, r_dtype=request.param[0], c_dtype=request.param[1] + ) # The following 3 fixtures are for default.qutrit devices to be used @@ -172,7 +178,7 @@ def mock_device(monkeypatch): m.setattr(dev, "short_name", "mock_device") m.setattr(dev, "capabilities", lambda cls: {"model": "qubit"}) m.setattr(dev, "operations", {"RX", "RY", "RZ", "CNOT", "SWAP"}) - yield qml.Device(wires=2) + yield qml.Device(wires=2) # pylint:disable=abstract-class-instantiated # pylint: disable=protected-access diff --git a/tests/devices/default_qubit_1/test_default_qubit_autograd.py b/tests/devices/test_default_qubit_autograd.py similarity index 91% rename from tests/devices/default_qubit_1/test_default_qubit_autograd.py rename to tests/devices/test_default_qubit_autograd.py index 180b8987fd6..f52c9cf0724 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_autograd.py +++ b/tests/devices/test_default_qubit_autograd.py @@ -18,7 +18,6 @@ import pennylane as qml from pennylane import numpy as np -from pennylane.devices import DefaultQubit from pennylane.devices.default_qubit_autograd import DefaultQubitAutograd from pennylane import DeviceError @@ -33,7 +32,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - DefaultQubitAutograd(wires=1, shots=1, analytic=True) + qml.device("default.qubit.autograd", wires=1, shots=1, analytic=True) @pytest.mark.autograd @@ -44,7 +43,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -67,7 +66,7 @@ def test_defines_correct_capabilities(self): def test_load_device(self): """Test that the plugin device loads correctly""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.autograd" @@ -78,7 +77,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit.""" p = np.array(0.543) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd") def circuit(x): @@ -95,7 +94,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple broadcasted circuit.""" p = np.array([0.543, 0.21, 1.5]) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd") def circuit(x): @@ -111,7 +110,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -135,7 +134,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -181,7 +180,7 @@ def test_real_dtype(self, r_dtype, measurement): real data type for a simple circuit""" p = 0.543 - dev = DefaultQubitAutograd(wires=3) + dev = qml.device("default.qubit.autograd", wires=3) dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="backprop") @@ -207,7 +206,7 @@ def test_real_dtype_broadcasted(self, r_dtype, measurement): real data type for a simple broadcasted circuit""" p = np.array([0.543, 0.21, 1.6]) - dev = DefaultQubitAutograd(wires=3) + dev = qml.device("default.qubit.autograd", wires=3) dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="backprop") @@ -228,7 +227,7 @@ def test_complex_dtype(self, c_dtype, measurement): complex data type for a simple circuit""" p = 0.543 - dev = DefaultQubitAutograd(wires=3) + dev = qml.device("default.qubit.autograd", wires=3) dev.C_DTYPE = c_dtype @qml.qnode(dev, diff_method="backprop") @@ -245,7 +244,7 @@ def test_complex_dtype_broadcasted(self, c_dtype): complex data type for a simple broadcasted circuit""" p = np.array([0.543, 0.21, 1.6]) - dev = DefaultQubitAutograd(wires=3) + dev = qml.device("default.qubit.autograd", wires=3) dev.C_DTYPE = c_dtype measurement = qml.state() @@ -271,7 +270,7 @@ def test_jacobian_variable_multiply(self, tol): z = 0.75110998 weights = np.array([x, y, z], requires_grad=True) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(p): @@ -307,7 +306,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): z = np.array([0.75110998, 0.12512, 9.12]) weights = np.array([x, y, z], requires_grad=True) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(p): @@ -342,7 +341,7 @@ def test_jacobian_repeated(self, tol): y = 0.2162158 z = 0.75110998 p = np.array([x, y, z], requires_grad=True) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -370,7 +369,7 @@ def test_jacobian_repeated_broadcasted(self, tol): y = np.array([0.2162158, 0.241, -0.51]) z = np.array([0.75110998, 0.12512, 9.12]) p = np.array([x, y, z], requires_grad=True) - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -408,8 +407,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - dev1 = DefaultQubit(wires=3) - dev2 = DefaultQubit(wires=3) + dev1 = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=3) def cost(x): return qml.math.stack(circuit(x)) @@ -431,7 +430,7 @@ def cost(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = DefaultQubitAutograd(wires=wires) + dev = qml.device("default.qubit.autograd", wires=wires) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a): @@ -452,7 +451,7 @@ def cost(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a): @@ -474,7 +473,7 @@ def cost(a): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -500,7 +499,7 @@ def cost(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -527,7 +526,7 @@ def cost(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -550,7 +549,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) @qml.qnode(dev, diff_method="backprop", interface="autograd") def circuit(a, b): @@ -577,7 +576,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) @qml.qnode(dev, interface="autograd", diff_method="backprop") def circuit(x): @@ -594,7 +593,7 @@ def circuit(x): def test_autograd_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the Autograd interface, using a variety of differentiation methods.""" - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) state = np.array(1j * np.array([1, -1]) / np.sqrt(2), requires_grad=False) @qml.qnode(dev, diff_method=diff_method, interface="autograd") @@ -645,7 +644,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface): """Tests that an error is raised if diff_method='backprop' but not using the Autograd interface""" - dev = DefaultQubitAutograd(wires=1) + dev = qml.device("default.qubit.autograd", wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -664,7 +663,7 @@ class TestHighLevelIntegration: def test_do_not_split_analytic_autograd(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the autograd device.""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="autograd") @@ -680,7 +679,7 @@ def circuit(): def test_do_not_split_analytic_autograd_broadcasted(self, mocker): """Tests that the Hamiltonian is not split for shots=None and broadcasting using the autograd device.""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="autograd") @@ -696,7 +695,7 @@ def circuit(): def test_template_integration(self): """Test that a PassthruQNode default.qubit.autograd works with templates.""" - dev = DefaultQubitAutograd(wires=2) + dev = qml.device("default.qubit.autograd", wires=2) @qml.qnode(dev, diff_method="backprop") def circuit(weights): @@ -719,7 +718,7 @@ def test_multirz_jacobian(self): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = DefaultQubitAutograd(wires=wires) + dev = qml.device("default.qubit.autograd", wires=wires) @qml.qnode(dev, diff_method="backprop") def circuit(param): @@ -765,7 +764,7 @@ def test_multirz_jacobian_broadcasted(self): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = DefaultQubitAutograd(wires=wires) + dev = qml.device("default.qubit.autograd", wires=wires) @qml.qnode(dev, diff_method="backprop") def circuit(param): diff --git a/tests/devices/default_qubit_1/test_default_qubit_jax.py b/tests/devices/test_default_qubit_jax.py similarity index 93% rename from tests/devices/default_qubit_1/test_default_qubit_jax.py rename to tests/devices/test_default_qubit_jax.py index 2e0689c9309..ea08c1a1ece 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_jax.py +++ b/tests/devices/test_default_qubit_jax.py @@ -39,7 +39,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - DefaultQubitJax(wires=1, shots=1, analytic=True) + qml.device("default.qubit.jax", wires=1, shots=1, analytic=True) # pylint: disable=too-many-public-methods @@ -51,7 +51,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -81,7 +81,7 @@ def test_defines_correct_capabilities_directly_from_class(self): def test_load_device(self): """Test that the plugin device loads correctly""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.jax" @@ -94,7 +94,7 @@ def test_load_device(self): def test_float_precision(self, jax_enable_x64, c_dtype, r_dtype): """Test that the plugin device uses the same float precision as the jax config.""" jax.config.update("jax_enable_x64", jax_enable_x64) - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) assert dev.state.dtype == c_dtype assert dev.state.real.dtype == r_dtype @@ -103,7 +103,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit.""" p = jnp.array(0.543) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -118,7 +118,7 @@ def test_qubit_circuit_with_jit(self, tol): result for a simple circuit under a jax.jit.""" p = jnp.array(0.543) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @jax.jit @qml.qnode(dev, interface="jax") @@ -141,7 +141,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple broadcasted circuit.""" p = jnp.array([0.543, 0.21, 1.5]) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -156,7 +156,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) state = dev.state expected = jnp.array([1, 0, 0, 0]) @@ -180,7 +180,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) state = dev.state expected = jnp.array([1, 0, 0, 0]) @@ -208,7 +208,7 @@ def circuit(): def test_correct_state_returned(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(): @@ -226,7 +226,7 @@ def circuit(): def test_correct_state_returned_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(): @@ -248,7 +248,7 @@ def circuit(): def test_probs_jax(self, tol): """Test that returning probs works with jax""" - dev = DefaultQubitJax(wires=1, shots=100) + dev = qml.device("default.qubit.jax", wires=1, shots=100) expected = jnp.array([0.0, 1.0]) @qml.qnode(dev, interface="jax", diff_method=None) @@ -261,7 +261,7 @@ def circuit(): def test_probs_jax_broadcasted(self, tol): """Test that returning probs works with jax""" - dev = DefaultQubitJax(wires=1, shots=100) + dev = qml.device("default.qubit.jax", wires=1, shots=100) expected = jnp.array([[0.0, 1.0]] * 3) @qml.qnode(dev, interface="jax", diff_method=None) @@ -275,7 +275,7 @@ def circuit(): def test_probs_jax_jit(self, tol): """Test that returning probs works with jax and jit""" - dev = DefaultQubitJax(wires=1, shots=100) + dev = qml.device("default.qubit.jax", wires=1, shots=100) expected = jnp.array([0.0, 1.0]) @qml.qnode(dev, interface="jax", diff_method=None) @@ -294,8 +294,7 @@ def circuit(z): def test_custom_shots_probs_jax_jit(self, tol): """Test that returning probs works with jax and jit when using custom shot vector""" - # pylint:disable=unsubscriptable-object - dev = DefaultQubitJax(wires=1, shots=(3, 2)) + dev = qml.device("default.qubit.jax", wires=1, shots=(3, 2)) expected = jnp.array([[0.0, 1.0], [0.0, 1.0]]) @jax.jit @@ -312,7 +311,7 @@ def circuit(): def test_custom_shots_probs_jax_jit_broadcasted(self, tol): """Test that returning probs works with jax and jit when using a custom shot vector and broadcasting""" - dev = DefaultQubitJax(wires=1, shots=(2, 2)) + dev = qml.device("default.qubit.jax", wires=1, shots=(2, 2)) expected = jnp.array([[[0.0, 1.0], [0.0, 1.0]]] * 5) @jax.jit @@ -330,7 +329,7 @@ def test_sampling_with_jit(self): @jax.jit def circuit(x, key): - dev = DefaultQubitJax(wires=1, shots=1000, prng_key=key) + dev = qml.device("default.qubit.jax", wires=1, shots=1000, prng_key=key) @qml.qnode(dev, interface="jax", diff_method=None) def inner_circuit(): @@ -356,7 +355,7 @@ def inner_circuit(): ) def test_qubit_state_vector_arg_jax_jit(self, state_vector, tol): """Test that Qubit state vector as argument works with a jax.jit""" - dev = DefaultQubitJax(wires=list(range(2))) + dev = qml.device("default.qubit.jax", wires=list(range(2))) @jax.jit @qml.qnode(dev, interface="jax") @@ -374,7 +373,7 @@ def circuit(x): ) def test_qubit_state_vector_arg_jax(self, state_vector, tol): """Test that Qubit state vector as argument works with jax""" - dev = DefaultQubitJax(wires=list(range(2))) + dev = qml.device("default.qubit.jax", wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -391,7 +390,7 @@ def circuit(x): ) def test_qubit_state_vector_jax_jit(self, state_vector, tol): """Test that Qubit state vector works with a jax.jit""" - dev = DefaultQubitJax(wires=list(range(2))) + dev = qml.device("default.qubit.jax", wires=list(range(2))) @jax.jit @qml.qnode(dev, interface="jax") @@ -410,7 +409,7 @@ def circuit(x): ) def test_qubit_state_vector_jax(self, state_vector, tol): """Test that Qubit state vector works with a jax""" - dev = DefaultQubitJax(wires=list(range(2))) + dev = qml.device("default.qubit.jax", wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -428,7 +427,7 @@ def circuit(x): ) def test_qubit_state_vector_jax_not_normed(self, state_vector): """Test that an error is raised when Qubit state vector is not normed works with a jax""" - dev = DefaultQubitJax(wires=list(range(2))) + dev = qml.device("default.qubit.jax", wires=list(range(2))) @qml.qnode(dev, interface="jax") def circuit(x): @@ -442,7 +441,7 @@ def circuit(x): def test_sampling_op_by_op(self): """Test that op-by-op sampling works as a new user would expect""" - dev = DefaultQubitJax(wires=1, shots=1000) + dev = qml.device("default.qubit.jax", wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -455,7 +454,7 @@ def circuit(): def test_sampling_analytic_mode(self): """Test that when sampling with shots=None an error is raised.""" - dev = DefaultQubitJax(wires=1, shots=None) + dev = qml.device("default.qubit.jax", wires=1, shots=None) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -470,7 +469,7 @@ def circuit(): def test_sampling_analytic_mode_with_counts(self): """Test that when sampling with counts and shots=None an error is raised.""" - dev = DefaultQubitJax(wires=1, shots=None) + dev = qml.device("default.qubit.jax", wires=1, shots=None) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -485,7 +484,7 @@ def circuit(): def test_gates_dont_crash(self): """Test for gates that weren't covered by other tests.""" - dev = DefaultQubitJax(wires=2, shots=1000) + dev = qml.device("default.qubit.jax", wires=2, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -501,7 +500,7 @@ def circuit(): def test_diagonal_doesnt_crash(self): """Test that diagonal gates can be used.""" - dev = DefaultQubitJax(wires=1, shots=1000) + dev = qml.device("default.qubit.jax", wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -512,7 +511,7 @@ def circuit(): def test_broadcasted_diagonal_doesnt_crash(self): """Test that diagonal gates can be used.""" - dev = DefaultQubitJax(wires=1, shots=1000) + dev = qml.device("default.qubit.jax", wires=1, shots=1000) @qml.qnode(dev, interface="jax", diff_method=None) def circuit(): @@ -525,7 +524,7 @@ def circuit(): def test_parametrized_evolution_state_vector(self, phi, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` the `_evolve_state_vector_under_parametrized_evolution` method is used.""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") @@ -548,7 +547,7 @@ def true_circuit(): def test_parametrized_evolution_matrix(self, phi, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires < device.num_wires/2`` the `_apply_operation` method is used.""" - dev = DefaultQubitJax(wires=3) + dev = qml.device("default.qubit.jax", wires=3) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -573,7 +572,7 @@ def test_parametrized_evolution_state_vector_return_intermediate(self, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` and ``return_intermediate=True``, the ``_evolve_state_vector_under_parametrized_evolution`` method is used.""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -600,7 +599,7 @@ def true_circuit(): def test_parametrized_evolution_matrix_complementary(self, mocker): """Test that when executing a ParametrizedEvolution with ``num_wires >= device.num_wires/2`` but with ``complementary=True``, the `_apply_operation` method is used.""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) H = ParametrizedHamiltonian([1], [qml.PauliX(0)]) spy = mocker.spy(dev, "_evolve_state_vector_under_parametrized_evolution") spy2 = mocker.spy(dev, "_apply_operation") @@ -638,7 +637,7 @@ def test_jacobian_variable_multiply(self, tol, jacobian_transform): z = 0.75110998 weights = jnp.array([x, y, z]) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax") def circuit(p): @@ -675,7 +674,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): z = jnp.array([0.75110998, 0.12512, 9.12]) weights = jnp.array([x, y, z]) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(p): @@ -713,7 +712,7 @@ def test_jacobian_repeated(self, tol, jacobian_transform): y = 0.2162158 z = 0.75110998 p = jnp.array([x, y, z]) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax") def circuit(x): @@ -738,7 +737,7 @@ def test_jacobian_repeated_broadcasted(self, tol): """Test that jacobian of a QNode with an attached default.qubit.jax device gives the correct result in the case of repeated broadcasted parameters""" p = jnp.array([[0.433, 92.1, -0.512], [0.218, 0.241, -0.51], [0.71, 0.152, 9.12]]) - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(x): @@ -767,7 +766,7 @@ def circuit(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = DefaultQubitJax(wires=wires) + dev = qml.device("default.qubit.jax", wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a): @@ -788,7 +787,7 @@ def cost(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a): @@ -812,7 +811,7 @@ def cost(a): def test_CRot_gradient(self, theta, tol): """Tests that the automatic gradient of a arbitrary controlled Euler-angle-parameterized gate is correct.""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) a, b, c = np.array([theta, theta**3, np.sqrt(2) * theta]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -839,7 +838,7 @@ def circuit(a, b, c): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -852,7 +851,7 @@ def circuit(a, b): b = jnp.array(0.12) def cost(a, b): - prob_wire_1 = circuit(a, b).squeeze() # pylint:disable=no-member + prob_wire_1 = circuit(a, b).squeeze() return prob_wire_1[1] - prob_wire_1[0] res = cost(a, b) @@ -865,7 +864,7 @@ def cost(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -879,7 +878,7 @@ def circuit(a, b): def cost(a, b): prob_wire_1 = circuit(a, b) - return prob_wire_1[:, 1] - prob_wire_1[:, 0] # pylint:disable=unsubscriptable-object + return prob_wire_1[:, 1] - prob_wire_1[:, 0] res = cost(a, b) expected = -jnp.cos(a) * jnp.cos(b) @@ -892,7 +891,7 @@ def cost(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -915,7 +914,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(a, b): @@ -941,7 +940,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, interface="jax", diff_method="backprop") def circuit(x): @@ -958,7 +957,7 @@ def circuit(x): def test_jax_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the Jax interface, using a variety of differentiation methods.""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) @qml.qnode(dev, diff_method=diff_method, interface="jax") def circuit(x, weights, w=None): @@ -1002,7 +1001,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface): """Tests that an error is raised if diff_method='backprop' but not using the Jax interface""" - dev = DefaultQubitJax(wires=1) + dev = qml.device("default.qubit.jax", wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -1021,7 +1020,7 @@ def test_no_jax_interface_applied(self): When the JAX interface is applied, we can only get the expectation value and the variance of a QNode. """ - dev = DefaultQubitJax(wires=1, shots=None) + dev = qml.device("default.qubit.jax", wires=1, shots=None) def circuit(): return qml.probs(wires=0) @@ -1036,7 +1035,7 @@ class TestHighLevelIntegration: def test_do_not_split_analytic_jax(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the jax device.""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -1052,7 +1051,7 @@ def circuit(): def test_direct_eval_hamiltonian_broadcasted_error_jax(self): """Tests that an error is raised when attempting to evaluate a Hamiltonian with broadcasting and shots=None directly via its sparse representation with Jax.""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) H = qml.Hamiltonian(jnp.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="jax") @@ -1065,7 +1064,7 @@ def circuit(): def test_template_integration(self): """Test that a PassthruQNode using default.qubit.jax works with templates.""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(weights): @@ -1090,7 +1089,7 @@ def test_multirz_jacobian(self, jacobian_transform): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = DefaultQubitJax(wires=wires) + dev = qml.device("default.qubit.jax", wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(param): @@ -1161,7 +1160,7 @@ def test_multirz_jacobian_broadcasted(self, jacobian_transform): """Test that the patched numpy functions are used for the MultiRZ operation and the jacobian can be computed.""" wires = 4 - dev = DefaultQubitJax(wires=wires) + dev = qml.device("default.qubit.jax", wires=wires) @qml.qnode(dev, diff_method="backprop", interface="jax") def circuit(param): @@ -1208,7 +1207,7 @@ class TestEstimateProb: ) def test_estimate_probability(self, wires, expected, monkeypatch): """Tests the estimate_probability method""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) samples = jnp.array([[0, 0], [1, 1], [1, 1], [0, 0]]) with monkeypatch.context() as m: @@ -1227,7 +1226,7 @@ def test_estimate_probability(self, wires, expected, monkeypatch): ) def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): """Tests the estimate_probability method with a bin size""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) samples = jnp.array([[1, 1], [1, 1], [1, 0], [0, 0]]) bin_size = 2 @@ -1247,7 +1246,7 @@ def test_estimate_probability_with_binsize(self, wires, expected, monkeypatch): ) def test_estimate_probability_with_broadcasting(self, wires, expected, monkeypatch): """Tests the estimate_probability method with parameter broadcasting""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) samples = jnp.array( [ [[1, 0], [1, 1], [1, 1], [1, 1]], @@ -1295,7 +1294,7 @@ def test_estimate_probability_with_binsize_with_broadcasting( self, wires, expected, monkeypatch ): """Tests the estimate_probability method with a bin size and parameter broadcasting""" - dev = DefaultQubitJax(wires=2) + dev = qml.device("default.qubit.jax", wires=2) bin_size = 2 samples = jnp.array( [ diff --git a/tests/devices/default_qubit_1/test_default_qubit.py b/tests/devices/test_default_qubit_legacy.py similarity index 95% rename from tests/devices/default_qubit_1/test_default_qubit.py rename to tests/devices/test_default_qubit_legacy.py index 214eee42e7d..f5f1b53dadd 100644 --- a/tests/devices/default_qubit_1/test_default_qubit.py +++ b/tests/devices/test_default_qubit_legacy.py @@ -15,7 +15,7 @@ Unit tests for the :mod:`pennylane.plugin.DefaultQubit` device. """ # pylint: disable=too-many-arguments,too-few-public-methods -# pylint: disable=protected-access,cell-var-from-loop,no-member +# pylint: disable=protected-access,cell-var-from-loop import cmath import math @@ -98,17 +98,17 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - DefaultQubit(wires=1, shots=1, analytic=True) + qml.device("default.qubit.legacy", wires=1, shots=1, analytic=True) def test_dtype_errors(): """Test that if an incorrect dtype is provided to the device then an error is raised.""" with pytest.raises(DeviceError, match="Real datatype must be a floating point type."): - DefaultQubit(wires=1, r_dtype=np.complex128) + qml.device("default.qubit.legacy", wires=1, r_dtype=np.complex128) with pytest.raises( DeviceError, match="Complex datatype must be a complex floating point type." ): - DefaultQubit(wires=1, c_dtype=np.float64) + qml.device("default.qubit.legacy", wires=1, c_dtype=np.float64) def test_custom_op_with_matrix(): @@ -125,7 +125,7 @@ def compute_matrix(self): # pylint:disable=arguments-differ qml.state() tape = qml.tape.QuantumScript.from_queue(q) - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) assert qml.math.allclose(dev.execute(tape), np.array([1, 0])) @@ -775,7 +775,7 @@ def test_expval_two_wires_with_parameters( def test_expval_estimate(self): """Test that the expectation value is not analytically calculated""" - dev = DefaultQubit(wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -902,7 +902,7 @@ def test_var_two_wires_with_parameters( def test_var_estimate(self): """Test that the variance is not analytically calculated""" - dev = DefaultQubit(wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -926,7 +926,7 @@ def test_sample_dimensions(self): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) dev.apply([qml.RX(1.5708, wires=[0]), qml.RX(1.5708, wires=[1])]) @@ -958,7 +958,7 @@ def test_sample_values(self, tol): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) dev.apply([qml.RX(1.5708, wires=[0])]) dev._wires_measured = {0} @@ -978,7 +978,7 @@ class TestDefaultQubitIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1016,7 +1016,7 @@ def circuit(x): res = circuit(p) assert np.isclose(res, expected, atol=tol, rtol=0) - assert res.dtype == r_dtype + assert res.dtype == r_dtype # pylint:disable=no-member def test_qubit_identity(self, qubit_device_1_wire, tol): """Test that the default qubit plugin provides correct result for the Identity expectation""" @@ -1035,7 +1035,7 @@ def test_nonzero_shots(self, tol): """Test that the default qubit plugin provides correct result for high shot number""" shots = 10**5 - dev = DefaultQubit(wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) p = 0.543 @@ -1178,7 +1178,7 @@ def test_multi_samples_return_correlated_results(self): the correct dimensions """ - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -1198,7 +1198,7 @@ def test_multi_samples_return_correlated_results_more_wires_than_size_of_observa the correct dimensions """ - dev = DefaultQubit(wires=num_wires, shots=1000) + dev = qml.device("default.qubit.legacy", wires=num_wires, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -1218,7 +1218,7 @@ class TestTensorExpval: def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1242,7 +1242,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1266,7 +1266,7 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1289,7 +1289,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() A = np.array( @@ -1327,7 +1327,7 @@ def test_hermitian(self, theta, phi, varphi, tol): def test_hermitian_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1376,7 +1376,7 @@ def test_hermitian_hermitian(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1400,7 +1400,7 @@ def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1429,7 +1429,7 @@ class TestTensorVar: def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1459,7 +1459,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1487,7 +1487,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A = np.array( [ @@ -1553,7 +1553,7 @@ class TestTensorSample: def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1595,7 +1595,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol_stochastic): def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.apply( [ @@ -1633,7 +1633,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol_stochastic): def test_hermitian(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) A = 0.1 * np.array( [ @@ -1748,7 +1748,7 @@ def test_state_dtype_after_op(self, r_dtype, c_dtype, op): examples. """ - dev = DefaultQubit(wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) n_wires = op.num_wires n_params = op.num_params @@ -1764,7 +1764,7 @@ def circuit(): return qml.state() res = circuit() - assert res.dtype == c_dtype + assert res.dtype == c_dtype # pylint:disable=no-member @pytest.mark.parametrize( "measurement", @@ -1779,7 +1779,7 @@ def test_measurement_real_dtype(self, r_dtype, c_dtype, measurement): """Test that the default qubit plugin provides correct result for a simple circuit""" p = 0.543 - dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1797,7 +1797,7 @@ def test_measurement_complex_dtype(self, r_dtype, c_dtype, measurement): """Test that the default qubit plugin provides correct result for a simple circuit""" p = 0.543 - dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1819,8 +1819,8 @@ def mock_analytic_counter(self, wires=None): @pytest.mark.parametrize("x", [[0.2, 0.5], [0.4, 0.9], [0.8, 0.3]]) def test_probability(self, x, tol): """Test that the probability function works for finite and infinite shots""" - dev = DefaultQubit(wires=2, shots=1000) - dev_analytic = DefaultQubit(wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) + dev_analytic = qml.device("default.qubit.legacy", wires=2, shots=None) def circuit(x): qml.RX(x[0], wires=0) @@ -1840,7 +1840,7 @@ def test_call_generate_samples(self, monkeypatch): """Test analytic_probability call when generating samples""" self.analytic_counter = False - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) monkeypatch.setattr(dev, "analytic_probability", self.mock_analytic_counter) # generate samples through `generate_samples` (using 'analytic_probability') @@ -1851,7 +1851,7 @@ def test_call_generate_samples(self, monkeypatch): def test_stateless_analytic_return(self): """Test that analytic_probability returns None if device is stateless""" - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) dev._state = None assert dev.analytic_probability() is None @@ -1862,7 +1862,7 @@ class TestWiresIntegration: def make_circuit_probs(self, wires): """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = DefaultQubit(wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) n_wires = len(wires) @qml.qnode(dev, diff_method="parameter-shift") @@ -1895,7 +1895,7 @@ def test_wires_probs(self, wires1, wires2, tol): def test_wires_not_found_exception(self): """Tests that an exception is raised when wires not present on the device are adressed.""" - dev = DefaultQubit(wires=["a", "b"]) + dev = qml.device("default.qubit.legacy", wires=["a", "b"]) with qml.queuing.AnnotatedQueue() as q: qml.RX(0.5, wires="c") @@ -1914,8 +1914,7 @@ def test_wires_not_found_exception(self): @pytest.mark.parametrize("dev_wires, wires_to_map", wires_to_try) def test_map_wires_caches(self, dev_wires, wires_to_map): """Test that multiple calls to map_wires will use caching.""" - # pylint:disable=no-value-for-parameter - dev = DefaultQubit(wires=dev_wires) + dev = qml.device("default.qubit.legacy", wires=dev_wires) original_hits = dev.map_wires.cache_info().hits original_misses = dev.map_wires.cache_info().misses @@ -1986,7 +1985,7 @@ class TestApplyOps: gates in DefaultQubit.""" state = np.arange(2**4, dtype=np.complex128).reshape((2, 2, 2, 2)) - dev = DefaultQubit(wires=4) + dev = qml.device("default.qubit.legacy", wires=4) single_qubit_ops = [ (qml.PauliX, dev._apply_x), @@ -2138,7 +2137,7 @@ def test_internal_apply_ops_case(self, monkeypatch): This test provides a new internal function that `default.qubit` uses to apply `PauliX` (rather than redefining the gate itself). """ - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # Create a dummy operation expected_test_output = np.ones(1) @@ -2157,7 +2156,7 @@ def test_internal_apply_ops_case(self, monkeypatch): def test_diagonal_operation_case(self, monkeypatch): """Tests the case when the operation to be applied is diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) par = 0.3 test_state = np.array([1, 0]) @@ -2170,7 +2169,6 @@ def test_diagonal_operation_case(self, monkeypatch): mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) with monkeypatch.context() as m: m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) - # pylint:disable=comparison-with-callable assert dev._apply_diagonal_unitary == mock_apply_diag dev._apply_operation(test_state, op) @@ -2184,7 +2182,7 @@ def test_diagonal_operation_case(self, monkeypatch): def test_apply_einsum_case(self, monkeypatch): """Tests the case when np.einsum is used to apply an operation in default.qubit.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_state = np.array([1, 0]) wires = 0 @@ -2222,7 +2220,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_tensordot_case(self, monkeypatch): """Tests the case when np.tensordot is used to apply an operation in default.qubit.""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) test_state = np.array([1, 0]) wires = [0, 1, 2] @@ -2261,7 +2259,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_unitary_tensordot_double_broadcasting_error(self): """Tests that an error is raised if attempting to use _apply_unitary with a broadcasted matrix and a broadcasted state simultaneously.""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) class BroadcastedToffoli(qml.operation.Operation): num_wires = 3 @@ -2282,7 +2280,7 @@ def compute_matrix(*params, **hyperparams): def test_identity_skipped(self, mocker): """Test that applying the identity operation does not perform any additional computations.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) starting_state = np.array([1, 0]) op = qml.Identity(0) @@ -2304,7 +2302,7 @@ class TestHamiltonianSupport: def test_do_not_split_analytic(self, mocker): """Tests that the Hamiltonian is not split for shots=None.""" - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="parameter-shift", interface=None) @@ -2319,7 +2317,7 @@ def circuit(): def test_split_finite_shots(self, mocker): """Tests that the Hamiltonian is split for finite shots.""" - dev = DefaultQubit(wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) spy = mocker.spy(dev, "expval") H = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @@ -2335,7 +2333,7 @@ def circuit(): def test_error_hamiltonian_expval_finite_shots(self): """Tests that the Hamiltonian is split for finite shots.""" - dev = DefaultQubit(wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) with pytest.raises(AssertionError, match="Hamiltonian must be used with shots=None"): @@ -2343,7 +2341,7 @@ def test_error_hamiltonian_expval_finite_shots(self): def test_error_hamiltonian_expval_wrong_wires(self): """Tests that expval fails if Hamiltonian uses non-device wires.""" - dev = DefaultQubit(wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) H = qml.Hamiltonian([0.1, 0.2, 0.3], [qml.PauliX(0), qml.PauliZ(1), qml.PauliY(2)]) with pytest.raises( @@ -2354,7 +2352,7 @@ def test_error_hamiltonian_expval_wrong_wires(self): def test_Hamiltonian_filtered_from_rotations(self, mocker): """Tests that the device does not attempt to get rotations for Hamiltonians.""" - dev = DefaultQubit(wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) H = qml.Hamiltonian([0.1, 0.2], [qml.PauliX(0), qml.PauliZ(1)]) spy = mocker.spy(qml.QubitDevice, "_get_diagonalizing_gates") @@ -2394,7 +2392,7 @@ def circuit(y, z, is_state_batched): def test_super_expval_not_called(self, is_state_batched, mocker): """Tests basic expval result, and ensures QubitDevice.expval is not called.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.QubitDevice, "expval") obs = qml.sum(qml.s_prod(0.1, qml.PauliX(0)), qml.s_prod(0.2, qml.PauliZ(0))) assert np.isclose(dev.expval(obs), 0.2) @@ -2405,7 +2403,7 @@ def test_trainable_autograd(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with autograd.""" if is_state_batched: pytest.skip(msg="Broadcasting, qml.jacobian and new return types do not work together") - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) qnode = qml.QNode(self.circuit, dev, interface="autograd") y, z = np.array([1.1, 2.2]) actual = qml.grad(qnode, argnum=[0, 1])(y, z, is_state_batched) @@ -2416,7 +2414,7 @@ def test_trainable_torch(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with torch.""" import torch - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) qnode = qml.QNode(self.circuit, dev, interface="torch") y, z = torch.tensor(1.1, requires_grad=True), torch.tensor(2.2, requires_grad=True) _qnode = partial(qnode, is_state_batched=is_state_batched) @@ -2428,7 +2426,7 @@ def test_trainable_tf(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with tf.""" import tensorflow as tf - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) qnode = qml.QNode(self.circuit, dev, interface="tensorflow") y, z = tf.Variable(1.1, dtype=tf.float64), tf.Variable(2.2, dtype=tf.float64) with tf.GradientTape() as tape: @@ -2441,7 +2439,7 @@ def test_trainable_jax(self, is_state_batched): """Tests that coeffs passed to a sum are trainable with jax.""" import jax - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) qnode = qml.QNode(self.circuit, dev, interface="jax") y, z = jax.numpy.array([1.1, 2.2]) actual = jax.jacobian(qnode, argnums=[0, 1])(y, z, is_state_batched) @@ -2454,7 +2452,7 @@ class TestGetBatchSize: @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) def test_batch_size_None(self, shape): """Test that a ``batch_size=None`` is reported correctly.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) tensor0 = np.ones(shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None tensor1 = np.arange(np.prod(shape)).reshape(shape) @@ -2464,7 +2462,7 @@ def test_batch_size_None(self, shape): @pytest.mark.parametrize("batch_size", [1, 3]) def test_batch_size_int(self, shape, batch_size): """Test that an integral ``batch_size`` is reported correctly.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) full_shape = (batch_size,) + shape tensor0 = np.ones(full_shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size @@ -2475,7 +2473,7 @@ def test_batch_size_int(self, shape, batch_size): def test_invalid_tensor(self): """Test that an error is raised if a tensor is provided that does not have a proper shape/ndim.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises(ValueError, match="could not broadcast"): dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) @@ -2495,4 +2493,5 @@ class TestDenseMatrixDecompositionThreshold: def test_threshold(self, op, n_wires, condition): wires = np.linspace(0, n_wires - 1, n_wires, dtype=int) op = op(wires=wires) + # pylint:disable=no-member assert DefaultQubit.stopping_condition.__get__(op)(op) == condition diff --git a/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py b/tests/devices/test_default_qubit_legacy_broadcasting.py similarity index 96% rename from tests/devices/default_qubit_1/test_default_qubit_broadcasting.py rename to tests/devices/test_default_qubit_legacy_broadcasting.py index 01108402691..a23c69d8dff 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_broadcasting.py +++ b/tests/devices/test_default_qubit_legacy_broadcasting.py @@ -595,7 +595,7 @@ def test_expval_two_wires_with_parameters_broadcasted( def test_expval_estimate_broadcasted(self): """Test that the expectation value is not analytically calculated""" - dev = DefaultQubit(wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -695,7 +695,7 @@ def test_var_two_wires_with_parameters_broadcasted( def test_var_estimate_broadcasted(self): """Test that the variance is not analytically calculated""" - dev = DefaultQubit(wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -720,7 +720,7 @@ def test_sample_dimensions_broadcasted(self): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) dev.apply([qml.RX(np.array([np.pi / 2, 0.0]), 0), qml.RX(np.array([np.pi / 2, 0.0]), 1)]) @@ -756,7 +756,7 @@ def test_sample_values_broadcasted(self, tol): # Explicitly resetting is necessary as the internal # state is set to None in __init__ and only properly # initialized during reset - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) dev.apply([qml.RX(np.ones(3), wires=[0])]) dev._wires_measured = {0} @@ -810,7 +810,7 @@ def test_nonzero_shots_broadcasted(self, tol): """Test that the default qubit plugin provides correct result for high shot number""" shots = 10**5 - dev = DefaultQubit(wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) p = np.array([0.543, np.pi / 2, 0.0, 1.0]) @@ -916,7 +916,7 @@ def test_multi_samples_return_correlated_results_broadcasted(self): correctly for correlated observables. """ - dev = DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -937,7 +937,7 @@ def test_multi_samples_correlated_results_more_wires_than_observable_broadcasted correctly for correlated observables on larger devices than the observables """ - dev = DefaultQubit(wires=num_wires, shots=1000) + dev = qml.device("default.qubit.legacy", wires=num_wires, shots=1000) @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -960,7 +960,7 @@ class TestTensorExpvalBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -984,7 +984,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1008,7 +1008,7 @@ def test_pauliz_identity_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1031,7 +1031,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) dev.reset() A = np.array( @@ -1069,7 +1069,7 @@ def test_hermitian_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1118,7 +1118,7 @@ def test_hermitian_hermitian_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1142,7 +1142,7 @@ def test_hermitian_identity_expectation_broadcasted(self, theta, phi, varphi, to def test_hermitian_two_wires_identity_expectation_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A = np.array( [[1.02789352, 1.61296440 - 0.3498192j], [1.61296440 + 0.3498192j, 1.23920938 + 0j]] @@ -1173,7 +1173,7 @@ class TestTensorVarBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1203,7 +1203,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1231,7 +1231,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol): def test_hermitian_broadcasted(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) A = np.array( [ @@ -1299,7 +1299,7 @@ class TestTensorSampleBroadcasted: def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1341,7 +1341,7 @@ def test_paulix_pauliy_broadcasted(self, theta, phi, varphi, tol_stochastic): def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.apply( [ @@ -1379,7 +1379,7 @@ def test_pauliz_hadamard_broadcasted(self, theta, phi, varphi, tol_stochastic): def test_hermitian_broadcasted(self, theta, phi, varphi, tol_stochastic): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubit(wires=3, shots=int(1e6)) + dev = qml.device("default.qubit.legacy", wires=3, shots=int(1e6)) A = 0.1 * np.array( [ @@ -1494,7 +1494,7 @@ def test_state_dtype_after_op_broadcasted(self, r_dtype, c_dtype, op): examples. """ - dev = DefaultQubit(wires=4, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=4, r_dtype=r_dtype, c_dtype=c_dtype) n_wires = op.num_wires n_params = op.num_params @@ -1526,7 +1526,7 @@ def test_measurement_real_dtype_broadcasted(self, r_dtype, c_dtype, measurement) """Test that the default qubit plugin provides correct result for a simple circuit""" p = np.array([0.543, 0.622, 1.3]) - dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1541,7 +1541,7 @@ def test_measurement_complex_dtype_broadcasted(self, r_dtype, c_dtype): p = np.array([0.543, 0.622, 1.3]) m = qml.state() - dev = DefaultQubit(wires=3, r_dtype=r_dtype, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=3, r_dtype=r_dtype, c_dtype=c_dtype) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -1562,8 +1562,8 @@ def mock_analytic_counter(self, wires=None): def test_probability_broadcasted(self, tol): """Test that the probability function works for finite and infinite shots""" - dev = DefaultQubit(wires=2, shots=1000) - dev_analytic = DefaultQubit(wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) + dev_analytic = qml.device("default.qubit.legacy", wires=2, shots=None) x = np.array([[0.2, 0.5, 0.4], [0.9, 0.8, 0.3]]) @@ -1586,7 +1586,7 @@ class TestWiresIntegrationBroadcasted: def make_circuit_probs(self, wires): """Factory for a qnode returning probabilities using arbitrary wire labels.""" - dev = DefaultQubit(wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) n_wires = len(wires) @qml.qnode(dev, diff_method="parameter-shift") @@ -1623,7 +1623,7 @@ class TestApplyOpsBroadcasted: gates in DefaultQubit.""" broadcasted_state = np.arange(2**4 * 3, dtype=np.complex128).reshape((3, 2, 2, 2, 2)) - dev = DefaultQubit(wires=4) + dev = qml.device("default.qubit.legacy", wires=4) single_qubit_ops = [ (qml.PauliX, dev._apply_x), @@ -1750,7 +1750,7 @@ def test_internal_apply_ops_case_broadcasted(self, monkeypatch): This test provides a new internal function that `default.qubit` uses to apply `PauliX` (rather than redefining the gate itself). """ - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) # Create a dummy operation @@ -1769,7 +1769,7 @@ def test_internal_apply_ops_case_broadcasted(self, monkeypatch): def test_diagonal_operation_case_broadcasted(self, monkeypatch): """Tests the case when the operation to be applied is diagonal in the computational basis and the _apply_diagonal_unitary method is used.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) par = 0.3 test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) @@ -1782,7 +1782,6 @@ def test_diagonal_operation_case_broadcasted(self, monkeypatch): mock_apply_diag = lambda state, matrix, wires: history.append((state, matrix, wires)) with monkeypatch.context() as m: m.setattr(dev, "_apply_diagonal_unitary", mock_apply_diag) - # pylint:disable=comparison-with-callable assert dev._apply_diagonal_unitary == mock_apply_diag dev._apply_operation(test_state, op) @@ -1796,7 +1795,7 @@ def test_diagonal_operation_case_broadcasted(self, monkeypatch): def test_apply_einsum_case_broadcasted(self, monkeypatch): """Tests the case when np.einsum is used to apply an operation in default.qubit.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) wires = 0 @@ -1835,7 +1834,7 @@ def compute_matrix(*params, **hyperparams): def test_apply_tensordot_case_broadcasted(self, monkeypatch): """Tests the case when np.tensordot is used to apply an operation in default.qubit.""" - dev = DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) test_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) wires = [0, 1, 2] @@ -1874,7 +1873,7 @@ def compute_matrix(*params, **hyperparams): def test_identity_skipped_broadcasted(self, mocker): """Test that applying the identity operation does not perform any additional computations.""" - dev = DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) starting_state = np.array([[1, 0], [INVSQ2, INVSQ2], [0, 1]]) op = qml.Identity(0) @@ -1896,7 +1895,7 @@ class TestHamiltonianSupportBroadcasted: def test_do_not_split_analytic_broadcasted(self, mocker): """Tests that the Hamiltonian is not split for shots=None.""" - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) Ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="parameter-shift", interface=None) @@ -1912,7 +1911,7 @@ def circuit(): def test_split_finite_shots_broadcasted(self, mocker): """Tests that the Hamiltonian is split for finite shots.""" - dev = DefaultQubit(wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) spy = mocker.spy(dev, "expval") ham = qml.Hamiltonian(np.array([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) diff --git a/tests/devices/default_qubit_1/test_default_qubit_tf.py b/tests/devices/test_default_qubit_tf.py similarity index 96% rename from tests/devices/default_qubit_1/test_default_qubit_tf.py rename to tests/devices/test_default_qubit_tf.py index 7a54129c54c..1b76d407d4e 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_tf.py +++ b/tests/devices/test_default_qubit_tf.py @@ -51,7 +51,6 @@ import pennylane as qml from pennylane import numpy as pnp from pennylane import DeviceError -from pennylane.devices import DefaultQubit tf = pytest.importorskip("tensorflow", minversion="2.0") from pennylane.devices.default_qubit_tf import ( # pylint: disable=wrong-import-position @@ -156,7 +155,7 @@ def test_analytic_deprecation(): DeviceError, match=msg, ): - DefaultQubitTF(wires=1, shots=1, analytic=True) + qml.device("default.qubit.tf", wires=1, shots=1, analytic=True) ##################################################### @@ -564,7 +563,7 @@ def test_apply_ops_above_8_wires_using_special(self): def test_do_not_split_analytic_tf(self, mocker): """Tests that the Hamiltonian is not split for shots=None using the tf device.""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="tf") @@ -931,7 +930,7 @@ def test_three_qubit_no_parameters_broadcasted(self, broadcasted_init_state, op, def test_direct_eval_hamiltonian_broadcasted_error_tf(self): """Tests that an error is raised when attempting to evaluate a Hamiltonian with broadcasting and shots=None directly via its sparse representation with TF.""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) ham = qml.Hamiltonian(tf.Variable([0.1, 0.2]), [qml.PauliX(0), qml.PauliZ(1)]) @qml.qnode(dev, diff_method="backprop", interface="tf") @@ -1059,7 +1058,7 @@ def test_multi_mode_hermitian_expectation(self, theta, phi, varphi, tol): def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) dev.reset() obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1083,7 +1082,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_identity(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and Identity works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) dev.reset() obs = qml.PauliZ(0) @ qml.Identity(1) @ qml.PauliZ(2) @@ -1107,7 +1106,7 @@ def test_pauliz_identity(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1130,7 +1129,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) dev.reset() _A = np.array( @@ -1168,7 +1167,7 @@ def test_hermitian(self, theta, phi, varphi, tol): def test_hermitian_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving two Hermitian matrices works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) A1 = np.array([[1, 2], [2, 4]]) @@ -1217,7 +1216,7 @@ def test_hermitian_hermitian(self, theta, phi, varphi, tol): def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix and the identity works correctly""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) obs = qml.Hermitian(A, wires=[0]) @ qml.Identity(wires=[1]) @@ -1237,7 +1236,7 @@ def test_hermitian_identity_expectation(self, theta, phi, varphi, tol): def test_hermitian_two_wires_identity_expectation(self, theta, phi, varphi, tol): """Test that a tensor product involving an Hermitian matrix for two wires and the identity works correctly""" - dev = DefaultQubitTF(wires=3, shots=None) + dev = qml.device("default.qubit.tf", wires=3, shots=None) Identity = np.array([[1, 0], [0, 1]]) ham = np.kron(np.kron(Identity, Identity), A) obs = qml.Hermitian(ham, wires=[2, 1, 0]) @@ -1299,7 +1298,7 @@ def test_var_hermitian(self, theta, phi, varphi, tol): def test_paulix_pauliy(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliX and PauliY works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) obs = qml.PauliX(0) @ qml.PauliY(2) @@ -1329,7 +1328,7 @@ def test_paulix_pauliy(self, theta, phi, varphi, tol): def test_pauliz_hadamard(self, theta, phi, varphi, tol): """Test that a tensor product involving PauliZ and PauliY and hadamard works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) obs = qml.PauliZ(0) @ qml.Hadamard(1) @ qml.PauliY(2) dev.reset() @@ -1357,7 +1356,7 @@ def test_pauliz_hadamard(self, theta, phi, varphi, tol): def test_hermitian(self, theta, phi, varphi, tol): """Test that a tensor product involving qml.Hermitian works correctly""" - dev = DefaultQubitTF(wires=3) + dev = qml.device("default.qubit.tf", wires=3) _A = np.array( [ @@ -1430,7 +1429,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self): """Test that the device defines the right capabilities""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1453,7 +1452,7 @@ def test_defines_correct_capabilities(self): def test_load_tensornet_tf_device(self): """Test that the tensor network plugin loads correctly""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.tf" @@ -1464,7 +1463,7 @@ def test_qubit_circuit(self, tol): result for a simple circuit using the old QNode.""" p = tf.Variable(0.543) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf") def circuit(x): @@ -1481,7 +1480,7 @@ def test_qubit_circuit_broadcasted(self, tol): result for a simple circuit with broadcasting using the old QNode.""" p = tf.Variable([0.543, 0.21, 2.41]) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf") def circuit(x): @@ -1497,7 +1496,7 @@ def test_correct_state(self, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -1521,7 +1520,7 @@ def test_correct_state_broadcasted(self, tol): """Test that the device state is correct after applying a broadcasted quantum function on the device""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) state = dev.state expected = np.array([1, 0, 0, 0]) @@ -1551,7 +1550,7 @@ def circuit(): def test_one_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the one-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) state = init_state(1) @qml.qnode(dev, interface="tf") @@ -1572,7 +1571,7 @@ def circuit(params): def test_two_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the two-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) state = init_state(2) @qml.qnode(dev, interface="tf") @@ -1593,7 +1592,7 @@ def circuit(params): def test_four_qubit_param_gates(self, theta, op, func, init_state, tol): """Test the integration of the four-qubit single parameter rotations by passing a TF data structure as a parameter""" - dev = DefaultQubitTF(wires=4) + dev = qml.device("default.qubit.tf", wires=4) state = init_state(4) @qml.qnode(dev, interface="tf") @@ -1612,7 +1611,7 @@ def circuit(params): def test_controlled_rotation_integration(self, init_state, tol): """Test the integration of the two-qubit controlled rotation by passing a TF data structure as a parameter""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) a = 1.7 b = 1.3432 c = -0.654 @@ -1643,7 +1642,7 @@ def test_jacobian_variable_multiply(self, tol): y = tf.Variable(0.2162158) z = tf.Variable(0.75110998) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(p): @@ -1687,7 +1686,7 @@ def test_jacobian_variable_multiply_broadcasted(self, tol): y = tf.Variable([0.2162158, 0.241, -0.51]) z = tf.Variable([0.75110998, 0.12512, 9.12]) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(p): @@ -1733,7 +1732,7 @@ def test_jacobian_repeated(self, tol): y = 0.2162158 z = 0.75110998 p = tf.Variable([x, y, z]) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(x): @@ -1761,7 +1760,7 @@ def test_jacobian_repeated_broadcasted(self, tol): y = tf.Variable([0.218, 0.241, -0.51]) z = tf.Variable([0.71, 0.152, 9.12]) p = tf.Variable([x, y, z]) - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, interface="tf", diff_method="backprop") def circuit(x): @@ -1796,8 +1795,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)) - dev1 = DefaultQubit(wires=3) - dev2 = DefaultQubit(wires=3) + dev1 = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=3) def cost(x): return qml.math.stack(circuit(x)) @@ -1819,7 +1818,7 @@ def cost(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, wires, tol): """Test that the device state can be differentiated""" - dev = DefaultQubitTF(wires=wires) + dev = qml.device("default.qubit.tf", wires=wires) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a): @@ -1838,7 +1837,7 @@ def circuit(a): def test_state_differentiability_broadcasted(self, tol): """Test that the broadcasted device state can be differentiated""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a): @@ -1858,7 +1857,7 @@ def circuit(a): def test_prob_differentiability(self, tol): """Test that the device probability can be differentiated""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1885,7 +1884,7 @@ def circuit(a, b): def test_prob_differentiability_broadcasted(self, tol): """Test that the broadcasted device probability can be differentiated""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1913,8 +1912,7 @@ def circuit(a, b): def test_backprop_gradient(self, tol): """Tests that the gradient of the qnode is correct""" - # pylint:disable=no-member - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1940,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]) @@ -1947,8 +1946,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, tol): """Tests that the gradient of the broadcasted qnode is correct""" - # pylint:disable=no-member - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) @qml.qnode(dev, diff_method="backprop", interface="tf") def circuit(a, b): @@ -1974,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]) @@ -1984,7 +1983,7 @@ def circuit(a, b): def test_hessian_at_zero(self, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) shift = tf.constant(shift) x = tf.Variable(x) @@ -2012,7 +2011,7 @@ def circuit(x): def test_tf_interface_gradient(self, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the TensorFlow interface, using a variety of differentiation methods.""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) @qml.qnode(dev, diff_method=diff_method, interface="tf") def circuit(x, weights, w): @@ -2068,7 +2067,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, interface, tol): """Tests that an error is raised if diff_method='backprop' but not using the TF interface""" - dev = DefaultQubitTF(wires=1) + dev = qml.device("default.qubit.tf", wires=1) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -2082,7 +2081,7 @@ def circuit(x, w=None): def test_hermitian_backprop(self, tol): """Test that backprop with qml.Hermitian works correctly""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) K = tf.linalg.diag([1, 2, 3, 4]) @@ -2104,7 +2103,7 @@ class TestSamples: def test_sample_observables(self): """Test that the device allows for sampling from observables.""" shots = 100 - dev = DefaultQubitTF(wires=2, shots=shots) + dev = qml.device("default.qubit.tf", wires=2, shots=shots) @qml.qnode(dev, diff_method="best", interface="tf") def circuit(a): @@ -2120,7 +2119,7 @@ def circuit(a): def test_estimating_marginal_probability(self, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTF(wires=2, shots=1000) + dev = qml.device("default.qubit.tf", wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2136,7 +2135,7 @@ def circuit(): def test_estimating_full_probability(self, tol): """Test that the probability of all wires is accurately estimated.""" - dev = DefaultQubitTF(wires=2, shots=1000) + dev = qml.device("default.qubit.tf", wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2154,7 +2153,7 @@ def circuit(): def test_estimating_expectation_values(self, tol): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" - dev = DefaultQubitTF(wires=3, shots=1000) + dev = qml.device("default.qubit.tf", wires=3, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(a, b): @@ -2182,7 +2181,7 @@ class TestSamplesBroadcasted: def test_sample_observables_broadcasted(self): """Test that the device allows for broadcasted sampling from observables.""" shots = 100 - dev = DefaultQubitTF(wires=2, shots=shots) + dev = qml.device("default.qubit.tf", wires=2, shots=shots) @qml.qnode(dev, diff_method="best", interface="tf") def circuit(a): @@ -2199,7 +2198,7 @@ def circuit(a): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_marginal_probability_broadcasted(self, batch_size, tol): """Test that the broadcasted probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTF(wires=2, shots=1000) + dev = qml.device("default.qubit.tf", wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2218,7 +2217,7 @@ def circuit(): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_full_probability_broadcasted(self, batch_size, tol): """Test that the broadcasted probability of all wires is accurately estimated.""" - dev = DefaultQubitTF(wires=2, shots=1000) + dev = qml.device("default.qubit.tf", wires=2, shots=1000) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(): @@ -2241,7 +2240,7 @@ def test_estimating_expectation_values_broadcasted(self, a, tol): """Test that estimating broadcasted expectation values using a finite number of shots produces a numeric tensor""" batch_size = len(a) - dev = DefaultQubitTF(wires=3, shots=None) + dev = qml.device("default.qubit.tf", wires=3, shots=None) @qml.qnode(dev, diff_method=None, interface="tf") def circuit(a, b): @@ -2264,7 +2263,7 @@ def test_asarray_ragged_dtype_conversion(monkeypatch): the dtype argument was provided.""" from tensorflow.python.framework.errors_impl import InvalidArgumentError - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) def mock_func(arr, dtype): raise InvalidArgumentError( @@ -2283,7 +2282,7 @@ class TestGetBatchSize: @pytest.mark.parametrize("shape", [(4, 4), (1, 8), (4,)]) def test_batch_size_None(self, shape): """Test that a ``batch_size=None`` is reported correctly.""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) tensor0 = np.ones(shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) is None @@ -2291,7 +2290,7 @@ def test_batch_size_None(self, shape): @pytest.mark.parametrize("batch_size", [1, 3]) def test_batch_size_int(self, shape, batch_size): """Test that an integral ``batch_size`` is reported correctly.""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) full_shape = (batch_size,) + shape tensor0 = np.ones(full_shape, dtype=complex) assert dev._get_batch_size(tensor0, shape, qml.math.prod(shape)) == batch_size @@ -2299,14 +2298,14 @@ def test_batch_size_int(self, shape, batch_size): def test_invalid_tensor(self): """Test that an error is raised if a tensor is provided that does not have a proper shape/ndim.""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) with pytest.raises(ValueError, match="Can't convert non-rectangular Python"): dev._get_batch_size([qml.math.ones((2, 3)), qml.math.ones((2, 2))], (2, 2, 2), 8) @pytest.mark.parametrize("jit_compile", [True, False]) def test_no_error_abstract_tensor(self, jit_compile): """Test that no error is raised if an abstract tensor is provided""" - dev = DefaultQubitTF(wires=2) + dev = qml.device("default.qubit.tf", wires=2) signature = (tf.TensorSpec(shape=None, dtype=tf.float32),) @tf.function(jit_compile=jit_compile, input_signature=signature) diff --git a/tests/devices/default_qubit_1/test_default_qubit_torch.py b/tests/devices/test_default_qubit_torch.py similarity index 96% rename from tests/devices/default_qubit_1/test_default_qubit_torch.py rename to tests/devices/test_default_qubit_torch.py index e1d1174c58a..8a1529fd87b 100644 --- a/tests/devices/default_qubit_1/test_default_qubit_torch.py +++ b/tests/devices/test_default_qubit_torch.py @@ -61,7 +61,6 @@ import pennylane as qml from pennylane import DeviceError from pennylane import numpy as pnp -from pennylane.devices import DefaultQubit torch = pytest.importorskip("torch", minversion="1.8.1") from pennylane.devices.default_qubit_torch import ( # pylint: disable=wrong-import-position @@ -201,7 +200,7 @@ def test_analytic_deprecation(): msg += "Please use shots=None instead of analytic=True." with pytest.raises(DeviceError, match=msg): - DefaultQubitTorch(wires=1, shots=1, analytic=True) + qml.device("default.qubit.torch", wires=1, shots=1, analytic=True) ##################################################### @@ -212,7 +211,7 @@ def test_analytic_deprecation(): def test_conj_helper_method(): """Unittests the _conj helper method.""" - dev = DefaultQubitTorch(wires=1) + dev = qml.device("default.qubit.torch", wires=1) x = qml.numpy.array(1.0 + 1j) conj_x = dev._conj(x) @@ -1577,7 +1576,7 @@ class TestQNodeIntegration: def test_defines_correct_capabilities(self, torch_device): """Test that the device defines the right capabilities""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) cap = dev.capabilities() capabilities = { "model": "qubit", @@ -1600,7 +1599,7 @@ def test_defines_correct_capabilities(self, torch_device): def test_load_torch_device(self, torch_device): """Test that the torch device plugin loads correctly""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) assert dev.num_wires == 2 assert dev.shots is None assert dev.short_name == "default.qubit.torch" @@ -1612,7 +1611,7 @@ def test_qubit_circuit(self, torch_device, tol): result for a simple circuit using the old QNode.""" p = torch.tensor(0.543, dtype=torch.float64, device=torch_device) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch") def circuit(x): @@ -1629,7 +1628,7 @@ def test_qubit_circuit_broadcasted(self, torch_device, tol): result for a simple circuit using the old QNode.""" p = torch.tensor([0.543, 0.21, 2.41], dtype=torch.float64, device=torch_device) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch") def circuit(x): @@ -1644,7 +1643,7 @@ def circuit(x): def test_correct_state(self, torch_device, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) state = dev.state expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) @@ -1671,7 +1670,7 @@ def circuit(): def test_correct_state_broadcasted(self, torch_device, tol): """Test that the device state is correct after applying a quantum function on the device""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) state = dev.state expected = torch.tensor([1, 0, 0, 0], dtype=torch.complex128, device=torch_device) @@ -1705,7 +1704,7 @@ def circuit(): def test_one_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the one-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) state = init_state(1, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1725,7 +1724,7 @@ def circuit(params): def test_two_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the two-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) state = init_state(2, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1747,7 +1746,7 @@ def circuit(params): def test_four_qubit_param_gates(self, torch_device, theta, op, func, init_state, tol): """Test the integration of the four-qubit single parameter rotations by passing a Torch data structure as a parameter""" - dev = DefaultQubitTorch(wires=4, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=4, torch_device=torch_device) state = init_state(4, torch_device=torch_device) @qml.qnode(dev, interface="torch") @@ -1766,7 +1765,7 @@ def circuit(params): def test_controlled_rotation_integration(self, torch_device, init_state, tol): """Test the integration of the two-qubit controlled rotation by passing a Torch data structure as a parameter""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) a = torch.tensor(1.7, device=torch_device) b = torch.tensor(1.3432, device=torch_device) @@ -1799,7 +1798,7 @@ def test_jacobian_variable_multiply(self, torch_device, tol): y = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) z = torch.tensor(0.43316321, dtype=torch.float64, requires_grad=True, device=torch_device) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(p): @@ -1844,7 +1843,7 @@ def test_jacobian_variable_multiply_broadcasted(self, torch_device, tol): device=torch_device, ) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(p): @@ -1887,7 +1886,7 @@ def test_jacobian_repeated(self, torch_device, tol): y = torch.tensor(0.2162158, dtype=torch.float64, requires_grad=True, device=torch_device) z = torch.tensor(0.75110998, dtype=torch.float64, requires_grad=True, device=torch_device) p = torch.tensor([x, y, z], requires_grad=True, device=torch_device) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(x): @@ -1922,7 +1921,7 @@ def test_jacobian_repeated_broadcasted(self, torch_device, tol): device=torch_device, requires_grad=True, ) - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(x): @@ -1962,8 +1961,8 @@ def circuit(x): qml.CNOT(wires=[i, i + 1]) return qml.expval(qml.PauliZ(0)) # , qml.var(qml.PauliZ(1)) - dev1 = DefaultQubitTorch(wires=3, torch_device=torch_device) - dev2 = DefaultQubit(wires=3) + dev1 = qml.device("default.qubit.torch", wires=3, torch_device=torch_device) + dev2 = qml.device("default.qubit.legacy", wires=3) circuit1 = qml.QNode(circuit, dev1, diff_method="backprop", interface="torch") circuit2 = qml.QNode(circuit, dev2, diff_method="parameter-shift") @@ -1980,7 +1979,7 @@ def circuit(x): @pytest.mark.parametrize("wires", [[0], ["abc"]]) def test_state_differentiability(self, torch_device, wires, tol): """Test that the device state can be differentiated""" - dev = DefaultQubitTorch(wires=wires, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=wires, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a): @@ -1999,7 +1998,7 @@ def circuit(a): def test_state_differentiability_broadcasted(self, torch_device, tol): """Test that the device state can be differentiated""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a): @@ -2019,7 +2018,7 @@ def cost(a): def test_prob_differentiability(self, torch_device, tol): """Test that the device probability can be differentiated""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2045,7 +2044,7 @@ def circuit(a, b): def test_prob_differentiability_broadcasted(self, torch_device, tol): """Test that the device probability can be differentiated""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2076,7 +2075,7 @@ def cost(a, b): def test_backprop_gradient(self, torch_device, tol): """Tests that the gradient of the qnode is correct""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2100,7 +2099,7 @@ def circuit(a, b): def test_backprop_gradient_broadcasted(self, torch_device, tol): """Tests that the gradient of the qnode is correct""" - dev = DefaultQubitTorch(wires=2, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, torch_device=torch_device) @qml.qnode(dev, diff_method="backprop", interface="torch") def circuit(a, b): @@ -2127,7 +2126,7 @@ def circuit(a, b): def test_hessian_at_zero(self, torch_device, x, shift): """Tests that the Hessian at vanishing state vector amplitudes is correct.""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) x = torch.tensor(x, requires_grad=True) @@ -2148,7 +2147,7 @@ def circuit(x): def test_torch_interface_gradient(self, torch_device, operation, diff_method, tol): """Tests that the gradient of an arbitrary U3 gate is correct using the PyTorch interface, using a variety of differentiation methods.""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) input_state = torch.tensor(1j * np.array([1, -1]) / math.sqrt(2), device=torch_device) @@ -2208,7 +2207,7 @@ def cost(params): def test_error_backprop_wrong_interface(self, torch_device, interface): """Tests that an error is raised if diff_method='backprop' but not using the torch interface""" - dev = DefaultQubitTorch(wires=1, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, torch_device=torch_device) def circuit(x, w=None): qml.RZ(x, wires=w) @@ -2230,7 +2229,7 @@ class TestSamples: def test_sample_observables(self, torch_device): """Test that the device allows for sampling from observables.""" shots = 100 - dev = DefaultQubitTorch(wires=2, shots=shots, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a): @@ -2248,7 +2247,7 @@ def circuit(a): def test_estimating_marginal_probability(self, torch_device, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2264,7 +2263,7 @@ def circuit(): def test_estimating_full_probability(self, torch_device, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2282,7 +2281,7 @@ def circuit(): def test_estimating_expectation_values(self, torch_device): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" - dev = DefaultQubitTorch(wires=3, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a, b): @@ -2314,7 +2313,7 @@ def test_sample_observables_broadcasted(self, torch_device, a): """Test that the device allows for sampling from observables.""" batch_size = len(a) shots = 100 - dev = DefaultQubitTorch(wires=2, shots=shots, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=shots, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a): @@ -2333,7 +2332,7 @@ def circuit(a): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_marginal_probability_broadcasted(self, torch_device, batch_size, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2352,7 +2351,7 @@ def circuit(): @pytest.mark.parametrize("batch_size", [2, 3]) def test_estimating_full_probability_broadcasted(self, torch_device, batch_size, tol): """Test that the probability of a subset of wires is accurately estimated.""" - dev = DefaultQubitTorch(wires=2, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(): @@ -2377,7 +2376,7 @@ def test_estimating_expectation_values_broadcasted(self, torch_device, a): """Test that estimating expectation values using a finite number of shots produces a numeric tensor""" batch_size = len(a) - dev = DefaultQubitTorch(wires=3, shots=1000, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=3, shots=1000, torch_device=torch_device) @qml.qnode(dev, diff_method=None, interface="torch") def circuit(a, b): @@ -2403,7 +2402,7 @@ def test_sampling_analytic_mode(self, torch_device): """Test that when sampling with shots=None, dev uses 1000 shots and raises an error. """ - dev = DefaultQubitTorch(wires=1, shots=None, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(): @@ -2417,7 +2416,7 @@ def circuit(): def test_sampling_analytic_mode_with_counts(self, torch_device): """Test that when sampling with counts and shots=None an error is raised.""" - dev = DefaultQubitTorch(wires=1, shots=None, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=1, shots=None, torch_device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") def circuit(): @@ -2474,7 +2473,7 @@ class TestCtrlOperator: ) def test_ctrl_r_operators(self, torch_device, ops, tol): """Test qml.ctrl using R-gate targets""" - dev = DefaultQubitTorch(wires=2, shots=None, torch_device=torch_device) + dev = qml.device("default.qubit.torch", wires=2, shots=None, torch_device=torch_device) par = torch.tensor([0.12345, 0.2468], dtype=torch.float64, device=torch_device) @qml.qnode(dev, interface="torch", diff_method="backprop") diff --git a/tests/devices/test_lightning_qubit.py b/tests/devices/test_lightning_qubit.py index bae30e7791b..e225077ecc0 100644 --- a/tests/devices/test_lightning_qubit.py +++ b/tests/devices/test_lightning_qubit.py @@ -24,7 +24,7 @@ def test_integration(): wires = 2 layers = 2 dev_l = qml.device("lightning.qubit", wires=wires) - dev_d = qml.device("default.qubit", wires=wires) + dev_d = qml.device("default.qubit.legacy", wires=wires) def circuit(weights): qml.templates.StronglyEntanglingLayers(weights, wires=range(wires)) diff --git a/tests/test_debugging.py b/tests/test_debugging.py index ae825a65622..55a6daaf005 100644 --- a/tests/test_debugging.py +++ b/tests/test_debugging.py @@ -24,9 +24,9 @@ class TestSnapshot: # pylint: disable=protected-access @pytest.mark.parametrize("method", [None, "backprop", "parameter-shift", "adjoint"]) - def test_default_qubit1(self, method): + def test_default_qubit_legacy(self, method): """Test that multiple snapshots are returned correctly on the state-vector simulator.""" - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, diff_method=method) def circuit(): @@ -57,7 +57,7 @@ def circuit(): def test_default_qubit2(self): """Test that multiple snapshots are returned correctly on the new state-vector simulator.""" - dev = qml.devices.experimental.DefaultQubit2() + dev = qml.device("default.qubit") # TODO: add additional QNode test once the new device supports it diff --git a/tests/test_device.py b/tests/test_device.py index f393034934e..285461f3eb9 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -975,7 +975,7 @@ def test_hot_refresh_entrypoints(self, monkeypatch): def test_shot_vector_property(self): """Tests shot vector initialization.""" - dev = qml.devices.DefaultQubit(wires=1, shots=[1, 3, 3, 4, 4, 4, 3]) + dev = qml.device("default.qubit.legacy", wires=1, shots=[1, 3, 3, 4, 4, 4, 3]) shot_vector = dev.shot_vector assert len(shot_vector) == 4 assert shot_vector[0].shots == 1 diff --git a/tests/test_operation.py b/tests/test_operation.py index 44391bf6559..c807ea02eb4 100644 --- a/tests/test_operation.py +++ b/tests/test_operation.py @@ -1035,7 +1035,7 @@ def test_all_wires_defined_but_init_with_one(self): """Test that an exception is raised if the class is defined with ALL wires, but then instantiated with only one""" - dev1 = qml.devices.DefaultQubit(wires=2) + dev1 = qml.device("default.qubit.legacy", wires=2) class DummyOp(qml.operation.Operation): r"""Dummy custom operator""" diff --git a/tests/test_qnode.py b/tests/test_qnode.py index c39f8370e37..acaf3c006d7 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -44,7 +44,7 @@ class TestValidation: def test_invalid_interface(self): """Test that an exception is raised for an invalid interface""" - dev = qml.devices.DefaultQubit(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" @@ -54,7 +54,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" @qnode(dev) @@ -73,7 +73,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, interface="autograd", diff_method="best") def circuit(x): @@ -96,7 +96,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -125,7 +125,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -137,7 +137,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" monkeypatch.setitem(dev._capabilities, "passthru_interface", test_interface) @@ -155,7 +155,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) diff_method, _, new_dev = QNode._validate_backprop_method(dev, accepted_name) @@ -166,7 +166,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -183,7 +183,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) test_interface = "something" orig_capabilities = dev.capabilities().copy() @@ -197,7 +197,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) @@ -210,7 +210,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.devices.DefaultQubit(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 @@ -243,7 +243,7 @@ def capabilities(cls): return capabilities monkeypatch.setattr(qml.devices.DefaultQubit, "capabilities", capabilities) - dev = qml.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, match="does not support the parameter-shift rule" @@ -255,7 +255,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.devices.DefaultQubit(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) @@ -271,7 +271,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.devices.DefaultQubit(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) @@ -283,7 +283,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.devices.DefaultQubit(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) @@ -296,7 +296,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.devices.DefaultQubit(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) @@ -314,7 +314,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.devices.DefaultQubit(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) @@ -330,7 +330,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.devices.DefaultQubit(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) @@ -342,7 +342,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.devices.DefaultQubit(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) @@ -355,7 +355,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.devices.DefaultQubit(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) @@ -373,7 +373,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.devices.DefaultQubit(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) @@ -438,7 +438,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.devices.DefaultQubit(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) @@ -452,7 +452,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, match="Differentiation method hello not recognized" @@ -461,7 +461,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with pytest.raises( qml.QuantumFunctionError, @@ -481,7 +481,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.devices.DefaultQubit(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." @@ -493,7 +493,7 @@ def test_adjoint_finite_shots(self): on QNode construction when the device has finite shots """ - dev = qml.devices.DefaultQubit(wires=1, shots=1) + dev = qml.device("default.qubit.legacy", wires=1, shots=1) @qnode(dev, diff_method="adjoint") def circ(): @@ -508,7 +508,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.devices.DefaultQubit(wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) @qnode(dev, diff_method="backprop") def circuit(param): @@ -524,7 +524,7 @@ def circuit(param): def test_qnode_print(self): """Test that printing a QNode object yields the right information.""" - dev = qml.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def func(x): qml.RX(x, wires=0) @@ -548,7 +548,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, diff_method=None) def circuit(x): @@ -570,7 +570,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with warnings.catch_warnings(record=True) as w: @@ -586,7 +586,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with warnings.catch_warnings(record=True) as w: @@ -606,7 +606,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(params): @@ -628,7 +628,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev, interface="autograd") def circuit(params): @@ -643,14 +643,14 @@ 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.devices.DefaultQubit(wires=1)) + _ = qml.QNode(lambda f: f, qml.device("default.qubit.legacy", wires=1)) assert len(record) == 0 def test_giving_mode_kwarg_raises_warning(self): """Test that providing a value for mode raises a warning.""" with pytest.warns(UserWarning, match="The `mode` keyword argument is deprecated"): - _ = qml.QNode(lambda f: f, qml.devices.DefaultQubit(wires=1), mode="best") + _ = qml.QNode(lambda f: f, qml.device("default.qubit.legacy", wires=1), mode="best") def test_giving_mode_kwarg_raises_warning_old_return(self): """Test that providing a value for mode raises a custom warning with disable_return.""" @@ -658,7 +658,7 @@ def test_giving_mode_kwarg_raises_warning_old_return(self): with pytest.warns( UserWarning, match="In the new return system, you should set the `grad_on_execution`" ): - _ = qml.QNode(lambda f: f, qml.devices.DefaultQubit(wires=1), mode="best") + _ = qml.QNode(lambda f: f, qml.device("default.qubit.legacy", wires=1), mode="best") qml.enable_return() @@ -667,7 +667,7 @@ class TestTapeConstruction: def test_basic_tape_construction(self, tol): """Test that a quantum tape is properly constructed""" - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -700,7 +700,7 @@ def func(x, y): def test_jacobian(self): """Test the jacobian computation""" - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -724,7 +724,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func0(x, y): qml.RX(x, wires=0) @@ -768,7 +768,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def func(x, y): qml.RX(x, wires=0) @@ -788,7 +788,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) contents = [] @@ -819,13 +819,13 @@ def circuit(x): qml.RX(x, wires=0) return qml.expval(qml.PauliZ(0)) - dev = qml.devices.DefaultQubit(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.devices.DefaultQubit(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) @@ -835,7 +835,7 @@ def test_jit_counts_raises_error(self): jitting raises an error.""" import jax - dev = qml.devices.DefaultQubit(wires=2, shots=5) + dev = qml.device("default.qubit.legacy", wires=2, shots=5) def circuit1(param): qml.Hadamard(0) @@ -869,7 +869,7 @@ def circuit2(param): def test_decorator(tol): """Test that the decorator correctly creates a QNode.""" - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev) def func(x, y): @@ -915,7 +915,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface="autograd") for _ in range(2): @@ -939,7 +939,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -968,7 +968,7 @@ def func(): qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(0)) - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) qn = QNode(func, dev, interface=interface) for _ in range(2): qn() @@ -991,7 +991,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) cache = {} @@ -1012,7 +1012,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) cache = {} @@ -1047,7 +1047,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.devices.DefaultQubit(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) @@ -1077,7 +1077,7 @@ def test_defer_meas_if_mcm_unsupported(self, first_par, sec_par, return_type): """Tests that the transform using the deferred measurement principle is applied if the device doesn't support mid-circuit measurements natively.""" - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def cry_qnode(x, y): @@ -1105,7 +1105,7 @@ def conditional_ry_qnode(x, y): def test_sampling_with_mcm(self, basis_state): """Tests that a QNode with qml.sample and mid-circuit measurements returns the expected results.""" - dev = qml.devices.DefaultQubit(wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) first_par = np.pi @@ -1135,7 +1135,7 @@ def test_conditional_ops_tensorflow(self, interface): """Test conditional operations with TensorFlow.""" import tensorflow as tf - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1178,7 +1178,7 @@ def test_conditional_ops_torch(self, interface): """Test conditional operations with Torch.""" import torch - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1217,7 +1217,7 @@ def test_conditional_ops_jax(self, jax_interface): import jax jnp = jax.numpy - dev = qml.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=jax_interface, diff_method="parameter-shift") def cry_qnode(x): @@ -1249,7 +1249,7 @@ def conditional_ry_qnode(x): def test_already_measured_error_operation(self): """Test that attempting to apply an operation on a wires that has been measured raises an error.""" - dev = qml.devices.DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def circuit(): @@ -1262,7 +1262,7 @@ def circuit(): def test_qnode_does_not_support_nested_queuing(self): """Test that operators in QNodes are not queued to surrounding contexts.""" - dev = qml.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(): @@ -1282,7 +1282,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.devices.DefaultQubit(wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) @qnode(dev) def circuit(a): @@ -1298,7 +1298,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.devices.DefaultQubit(wires=1, shots=None) + dev = qml.device("default.qubit.legacy", wires=1, shots=None) @qnode(dev) def circuit(): @@ -1324,7 +1324,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.devices.DefaultQubit(wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) def circuit(a, shots=0): qml.RX(a, wires=shots) @@ -1348,7 +1348,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.devices.DefaultQubit(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) @@ -1363,7 +1363,7 @@ def ansatz0(a, shots): assert len(circuit(0.8, 1)) == 10 assert circuit.qtape.operations[0].wires.labels == (1,) - dev = qml.devices.DefaultQubit(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" @@ -1381,7 +1381,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.devices.DefaultQubit(wires=1, shots=3) + dev = qml.device("default.qubit.legacy", wires=1, shots=3) @qnode(dev) def circuit(a): @@ -1395,7 +1395,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.devices.DefaultQubit(wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache={}) def circuit(x): @@ -1410,7 +1410,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.devices.DefaultQubit(wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache={}) def circuit(x): @@ -1424,7 +1424,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.devices.DefaultQubit(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) @@ -1439,7 +1439,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev, cache={}) def circuit(x): @@ -1454,7 +1454,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.devices.DefaultQubit(wires=1, shots=5) + dev = qml.device("default.qubit.legacy", wires=1, shots=5) @qml.qnode(dev, cache=True) def circuit(x): @@ -1477,7 +1477,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.devices.DefaultQubit(wires=2, shots=5) + dev = qml.device("default.qubit.legacy", wires=2, shots=5) def func(x, y): qml.RX(x, wires=0) @@ -1515,7 +1515,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def null_postprocessing(results): return results[0] @@ -1548,7 +1548,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( @@ -1573,7 +1573,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] @@ -1620,7 +1620,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 @@ -1836,7 +1836,7 @@ class TestTapeExpansion: ) def test_device_expansion(self, diff_method, mode, mocker): """Test expansion of an unsupported operation on the device""" - dev = qml.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1869,7 +1869,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class UnsupportedOp(qml.operation.Operation): @@ -1914,7 +1914,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.devices.DefaultQubit(wires=1) + dev = qml.device("default.qubit.legacy", wires=1) # pylint: disable=too-few-public-methods class PhaseShift(qml.PhaseShift): @@ -1959,7 +1959,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.devices.DefaultQubit(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]) @@ -1978,7 +1978,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.devices.DefaultQubit(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]) @@ -2003,7 +2003,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.devices.DefaultQubit(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]) @@ -2024,7 +2024,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.devices.DefaultQubit(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") @@ -2050,7 +2050,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.devices.DefaultQubit(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 a2e1c8adb89..a0c98572997 100644 --- a/tests/test_return_types.py +++ b/tests/test_return_types.py @@ -14,7 +14,6 @@ """ Unit tests for the new return types. """ -from functools import partial import warnings import numpy as np @@ -25,7 +24,7 @@ test_wires = [2, 3, 4] -devices = [qml.devices.DefaultQubit, partial(qml.device, "default.mixed")] +devices = ["default.qubit.legacy", "default.mixed"] @pytest.mark.parametrize("interface, shots", [["autograd", None], ["auto", 100]]) @@ -35,7 +34,7 @@ class TestSingleReturnExecute: @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires, interface, shots): """Return state with default.qubit.""" - dev = qml.devices.DefaultQubit(wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -84,7 +83,7 @@ def circuit(x): @pytest.mark.parametrize("d_wires", test_wires) def test_density_matrix(self, d_wires, device, interface, shots): """Return density matrix.""" - dev = device(wires=4, shots=shots) + dev = qml.device(device, wires=4, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -108,7 +107,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_expval(self, device, interface, shots): """Return a single expval.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -126,7 +125,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_var(self, device, interface, shots): """Return a single var.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -144,7 +143,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_vn_entropy(self, device, interface, shots): """Return a single vn entropy.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -168,7 +167,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_mutual_info(self, device, interface, shots): """Return a single mutual information.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -202,7 +201,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, op, wires, device, interface, shots): """Return a single prob.""" - dev = device(wires=3, shots=shots) + dev = qml.device(device, wires=3, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -226,7 +225,7 @@ def test_sample(self, measurement, interface, shots): if shots is None: pytest.skip("Sample requires finite shots.") - dev = qml.devices.DefaultQubit(wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -247,7 +246,7 @@ def test_counts(self, measurement, interface, shots): if shots is None: pytest.skip("Counts requires finite shots.") - dev = qml.devices.DefaultQubit(wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -275,7 +274,7 @@ class TestMultipleReturns: @pytest.mark.parametrize("device", devices) def test_multiple_expval(self, device, shots): """Return multiple expvals.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -299,7 +298,7 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_multiple_var(self, device, shots): """Return multiple vars.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -337,7 +336,7 @@ def circuit(x): @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 = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -371,7 +370,7 @@ def circuit(x): def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device, shots): """Return multiple different measurements.""" - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -419,7 +418,7 @@ def circuit(x): @pytest.mark.parametrize("wires", wires) def test_list_multiple_expval(self, wires, device, shots): """Return a comprehension list of multiple expvals.""" - dev = device(wires=wires, shots=shots) + dev = qml.device(device, wires=wires, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -445,7 +444,7 @@ def test_expval_sample(self, measurement, shots, device): if shots is None: pytest.skip("Sample requires finite shots.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -472,7 +471,7 @@ def test_expval_counts(self, measurement, shots, device): if shots is None: pytest.skip("Counts requires finite shots.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -528,7 +527,7 @@ class TestShotVector: @pytest.mark.parametrize("measurement", single_scalar_output_measurements) def test_scalar(self, shot_vector, measurement, device): """Test a single scalar-valued measurement.""" - dev = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -549,7 +548,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, shot_vector, op, wires, device): """Test a single probability measurement.""" - dev = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -572,7 +571,7 @@ def circuit(x): @pytest.mark.xfail def test_density_matrix(self, shot_vector, wires, device): """Test a density matrix measurement.""" - dev = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -598,7 +597,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -625,7 +624,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -652,7 +651,7 @@ class TestSameMeasurementShotVector: def test_scalar(self, shot_vector, device): """Test multiple scalar-valued measurements.""" - dev = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -684,7 +683,7 @@ def circuit(x): @pytest.mark.parametrize("op2,wires2", reversed(probs_data2)) def test_probs(self, shot_vector, op1, wires1, op2, wires2, device): """Test multiple probability measurements.""" - dev = device(wires=4, shots=shot_vector) + dev = qml.device(device, wires=4, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -712,7 +711,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -737,7 +736,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -828,7 +827,7 @@ class TestMixMeasurementsShotVector: @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 = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -861,7 +860,7 @@ def circuit(x): def test_scalar_sample_with_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and sample measurements where sample takes an observable.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -896,7 +895,7 @@ def circuit(x): @pytest.mark.xfail def test_scalar_sample_no_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and computational basis sample measurements.""" - dev = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -929,7 +928,7 @@ def circuit(x): def test_scalar_counts_with_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and counts measurements where counts takes an observable.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -970,7 +969,7 @@ def circuit(x): @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 = device(wires=3, shots=shot_vector) + 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) ] @@ -1004,7 +1003,7 @@ def circuit(x): @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) def test_probs_sample(self, shot_vector, sample_obs, device): """Test probs and sample measurements.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -1052,7 +1051,7 @@ def circuit(x): @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) def test_probs_counts(self, shot_vector, sample_obs, device): """Test probs and counts measurements.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -1102,7 +1101,7 @@ def circuit(x): 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 = device(wires=6, shots=shot_vector) + 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) ] @@ -1155,7 +1154,7 @@ def circuit(x): 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 = device(wires=5, shots=shot_vector) + 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) ] @@ -1224,7 +1223,7 @@ def return_type(self): DummyMeasurement(obs=qml.PauliZ(0)) tape = qml.tape.QuantumScript.from_queue(q) - dev = qml.devices.DefaultQubit(wires=3) + dev = qml.device("default.qubit.legacy", wires=3) with pytest.raises( qml.QuantumFunctionError, match="Unsupported return type specified for observable" ): @@ -1234,7 +1233,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.devices.DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires=0) @@ -1251,7 +1250,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.devices.DefaultQubit(wires=["a", 1]) + dev = qml.device("default.qubit.legacy", wires=["a", 1]) with qml.queuing.AnnotatedQueue() as q: qml.PauliX(wires="a") @@ -1267,7 +1266,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.devices.DefaultQubit(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_qnode.py b/tests/test_return_types_qnode.py index 716eb00fb6d..3e7a2de8394 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -14,19 +14,13 @@ """ Unit tests for the new return types with QNode. """ -from functools import partial import numpy as np import pytest import pennylane as qml -from pennylane.devices import DefaultQubit, DefaultMixed -from pennylane.devices.default_qubit_torch import DefaultQubitTorch -from pennylane.devices.default_qubit_tf import DefaultQubitTF -from pennylane.devices.default_qubit_jax import DefaultQubitJax -from pennylane.devices.default_qutrit import DefaultQutrit test_wires = [2, 3, 4] -devices = [DefaultQubit, partial(qml.device, "lightning.qubit"), DefaultMixed, DefaultQutrit] +devices = ["default.qubit.legacy", "lightning.qubit", "default.mixed", "default.qutrit"] def qubit_ansatz(x): @@ -46,7 +40,7 @@ class TestIntegrationSingleReturn: @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires): """Return state with default.qubit.""" - dev = DefaultQubit(wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) def circuit(x): qubit_ansatz(x) @@ -61,7 +55,7 @@ def circuit(x): @pytest.mark.parametrize("wires", test_wires) def test_state_mixed(self, wires): """Return state with default.mixed.""" - dev = DefaultMixed(wires=wires) + dev = qml.device("default.mixed", wires=wires) def circuit(x): qubit_ansatz(x) @@ -77,8 +71,8 @@ def circuit(x): @pytest.mark.parametrize("d_wires", test_wires) def test_density_matrix(self, d_wires, device): """Return density matrix with default.qubit.""" - dev = device(wires=4) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + dev = qml.device(device, wires=4) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) @@ -87,20 +81,20 @@ def circuit(x): qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) - dim = 3 if device == DefaultQutrit else 2 + dim = 3 if device == "default.qutrit" else 2 assert res.shape == (dim**d_wires, dim**d_wires) assert isinstance(res, np.ndarray) @pytest.mark.parametrize("device", devices) def test_expval(self, device): """Return a single expval.""" - dev = device(wires=2) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + dev = qml.device(device, wires=2) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) return qml.expval( - qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) + qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) ) qnode = qml.QNode(circuit, dev, diff_method=None) @@ -112,12 +106,14 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_var(self, device): """Return a single var.""" - dev = device(wires=2) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + dev = qml.device(device, wires=2) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) - return qml.var(qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3)) + return qml.var( + qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) + ) qnode = qml.QNode(circuit, dev, diff_method=None) res = qnode(0.5) @@ -128,10 +124,10 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_vn_entropy(self, device): """Return a single vn entropy.""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("DefaultQutrit does not support VnEntropy.") - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qubit_ansatz(x) @@ -147,7 +143,7 @@ def circuit(x): @pytest.mark.filterwarnings("ignore:Requested Von Neumann entropy with finite shots") def test_vn_entropy_shot_vec_error(self): """Test an error is raised when using shot vectors with vn_entropy.""" - dev = DefaultQubit(wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -162,10 +158,10 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_mutual_info(self, device): """Return a single mutual information.""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("DefaultQutrit does not support MutualInfo.") - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qubit_ansatz(x) @@ -181,7 +177,7 @@ def circuit(x): @pytest.mark.filterwarnings("ignore:Requested mutual information with finite shots") def test_mutual_info_shot_vec_error(self): """Test an error is raised when using shot vectors with mutual_info.""" - dev = DefaultQubit(wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -205,11 +201,11 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, op, wires, device): """Return a single prob.""" - if device == DefaultQutrit or isinstance(device, partial): + if device in ("lightning.qubit", "default.qutrit"): pytest.skip( "Skip Lightning (wire reordering unsupported) and Qutrit (unsuported observables)." ) - dev = device(wires=3) + dev = qml.device(device, wires=3) def circuit(x): qubit_ansatz(x) @@ -234,7 +230,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data_qutrit) def test_probs_qutrit(self, op, wires): """Return a single prob.""" - dev = DefaultQutrit(wires=3) + dev = qml.device("default.qutrit", wires=3) def circuit(x): qutrit_ansatz(x) @@ -261,14 +257,14 @@ def circuit(x): ) def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" - if device == DefaultQutrit: + if device == "default.qutrit": if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = device(wires=2, shots=shots) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + dev = qml.device(device, wires=2, shots=shots) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) @@ -282,7 +278,7 @@ def circuit(x): if measurement.wires.tolist() != [0, 1]: assert res.shape == (shots,) else: - assert res.shape == (shots, 2) if device != DefaultQutrit else (shots, 3) + assert res.shape == (shots, 2) if device != "default.qutrit" else (shots, 3) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize( @@ -296,14 +292,14 @@ def circuit(x): ) def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" - if device == DefaultQutrit: + if device == "default.qutrit": if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = device(wires=2, shots=shots) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + dev = qml.device(device, wires=2, shots=shots) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) @@ -316,7 +312,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = [DefaultQubitTF, DefaultMixed] +devices = ["default.qubit.tf", "default.mixed"] @pytest.mark.tf @@ -328,7 +324,7 @@ def test_state_default(self, wires): """Return state with default.qubit.""" import tensorflow as tf - dev = DefaultQubitTF(wires=wires) + dev = qml.device("default.qubit.tf", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -346,7 +342,7 @@ def test_state_mixed(self, wires): """Return state with default.mixed.""" import tensorflow as tf - dev = DefaultMixed(wires=wires) + dev = qml.device("default.mixed", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -367,7 +363,7 @@ def test_density_matrix(self, d_wires, device): """Return density matrix.""" import tensorflow as tf - dev = device(wires=3) + dev = qml.device(device, wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -385,7 +381,7 @@ def test_expval(self, device): """Return a single expval.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -403,7 +399,7 @@ def test_var(self, device): """Return a single var.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -421,7 +417,7 @@ def test_vn_entropy(self, device): """Return a single vn entropy.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -439,7 +435,7 @@ def test_mutual_info(self, device): """Return a single mutual information.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -466,7 +462,7 @@ def test_probs(self, op, wires, device): """Return a single prob.""" import tensorflow as tf - dev = device(wires=3) + dev = qml.device(device, wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -490,10 +486,10 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import tensorflow as tf - if device in [DefaultMixed, DefaultQubit]: + if device in ["default.mixed", "default.qubit.legacy"]: pytest.skip("Sample need to be rewritten for Tf.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -518,7 +514,7 @@ def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" import tensorflow as tf - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -532,7 +528,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = [DefaultQubitTorch, DefaultMixed] +devices = ["default.qubit.torch", "default.mixed"] @pytest.mark.torch @@ -544,7 +540,7 @@ def test_state_default(self, wires): """Return state with default.qubit.""" import torch - dev = DefaultQubitTorch(wires=wires) + dev = qml.device("default.qubit.torch", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -562,7 +558,7 @@ def test_state_mixed(self, wires): """Return state with default.mixed.""" import torch - dev = DefaultMixed(wires=wires) + dev = qml.device("default.mixed", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -581,7 +577,7 @@ def test_density_matrix(self, d_wires, device): """Return density matrix.""" import torch - dev = device(wires=4) + dev = qml.device(device, wires=4) def circuit(x): qml.Hadamard(wires=[0]) @@ -599,7 +595,7 @@ def test_expval(self, device): """Return a single expval.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -617,7 +613,7 @@ def test_var(self, device): """Return a single var.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -635,7 +631,7 @@ def test_vn_entropy(self, device): """Return a single vn entropy.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -653,7 +649,7 @@ def test_mutual_info(self, device): """Return a single mutual information.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -680,7 +676,7 @@ def test_probs(self, op, wires, device): """Return a single prob.""" import torch - dev = device(wires=3) + dev = qml.device(device, wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -704,10 +700,10 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import torch - if device in [DefaultMixed, DefaultQubit]: + if device in ["default.mixed", "default.qubit.legacy"]: pytest.skip("Sample need to be rewritten for Torch.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -730,10 +726,10 @@ def test_counts(self, measurement, device, shots=100): """Test the counts measurement.""" import torch - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Counts need to be rewritten for Torch and default mixed.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -747,7 +743,7 @@ def circuit(x): assert sum(res.values()) == shots -devices = [DefaultQubitJax, DefaultMixed] +devices = ["default.qubit.jax", "default.mixed"] @pytest.mark.jax @@ -762,7 +758,7 @@ def test_state_default(self, wires): config.update("jax_enable_x64", True) import jax - dev = DefaultQubitJax(wires=wires) + dev = qml.device("default.qubit.jax", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -783,7 +779,7 @@ def test_state_mixed(self, wires): config.update("jax_enable_x64", True) import jax - dev = DefaultMixed(wires=wires) + dev = qml.device("default.mixed", wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -805,7 +801,7 @@ def test_density_matrix(self, d_wires, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=4) + dev = qml.device(device, wires=4) def circuit(x): qml.Hadamard(wires=[0]) @@ -826,7 +822,7 @@ def test_expval(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -847,7 +843,7 @@ def test_var(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -868,7 +864,7 @@ def test_vn_entropy(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -889,7 +885,7 @@ def test_mutual_info(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -919,7 +915,7 @@ def test_probs(self, op, wires, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=3) + dev = qml.device(device, wires=3) def circuit(x): qml.Hadamard(wires=[0]) @@ -946,10 +942,10 @@ def test_sample(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Sample need to be rewritten for each interface in default mixed.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -977,7 +973,7 @@ def test_counts(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -993,7 +989,7 @@ def circuit(x): multi_return_wires = [([0], [1]), ([1], [0]), ([0], [0]), ([1], [1])] -devices = [DefaultQubit, partial(qml.device, "lightning.qubit"), DefaultMixed, DefaultQutrit] +devices = ["default.qubit.legacy", "lightning.qubit", "default.mixed", "default.qutrit"] class TestIntegrationMultipleReturns: @@ -1004,15 +1000,15 @@ class TestIntegrationMultipleReturns: @pytest.mark.parametrize("device", devices) def test_multiple_expval(self, device): """Return multiple expvals.""" - dev = device(wires=2) + dev = qml.device(device, wires=2) obs1 = ( qml.Projector([0], wires=0) - if device != DefaultQutrit + if device != "default.qutrit" else qml.THermitian(np.eye(3), wires=0) ) - obs2 = qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + obs2 = qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) @@ -1033,15 +1029,15 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_multiple_var(self, device): """Return multiple vars.""" - dev = device(wires=2) + dev = qml.device(device, wires=2) obs1 = ( qml.Projector([0], wires=0) - if device != DefaultQutrit + if device != "default.qutrit" else qml.THermitian(np.eye(3), wires=0) ) - obs2 = qml.PauliZ(wires=1) if device != DefaultQutrit else qml.GellMann(1, 3) - func = qutrit_ansatz if device == DefaultQutrit else qubit_ansatz + obs2 = qml.PauliZ(wires=1) if device != "default.qutrit" else qml.GellMann(1, 3) + func = qutrit_ansatz if device == "default.qutrit" else qubit_ansatz def circuit(x): func(x) @@ -1076,10 +1072,10 @@ def circuit(x): @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data) def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("Separate test for DefaultQutrit.") - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qubit_ansatz(x) @@ -1117,7 +1113,7 @@ def circuit(x): @pytest.mark.parametrize("op1,wires1,op2,wires2", multi_probs_data_qutrit) def test_multiple_prob_qutrit(self, op1, op2, wires1, wires2): """Return multiple probs.""" - dev = DefaultQutrit(wires=2) + dev = qml.device("default.qutrit", wires=2) def circuit(x): qutrit_ansatz(x) @@ -1147,10 +1143,10 @@ def circuit(x): @pytest.mark.parametrize("wires3, wires4", multi_return_wires) def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("Different test for DefaultQutrit.") - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qubit_ansatz(x) @@ -1192,7 +1188,7 @@ def test_mix_meas_qutrit(self, op1, wires1, op2, wires2, wires3, wires4): """Return multiple different measurements.""" pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") - dev = DefaultQutrit(wires=2) + dev = qml.device("default.qutrit", wires=2) def circuit(x): qutrit_ansatz(x) @@ -1234,15 +1230,15 @@ def circuit(x): ) def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" - if device == DefaultQutrit: + if device == "default.qutrit": if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = device(wires=2, shots=shots) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) + dev = qml.device(device, wires=2, shots=shots) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1266,15 +1262,15 @@ def circuit(x): ) def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" - if device == DefaultQutrit: + if device == "default.qutrit": if isinstance(measurement.obs, qml.PauliZ): pytest.skip("DefaultQutrit doesn't support qubit observables.") elif isinstance(measurement.obs, qml.GellMann): pytest.skip("DefaultQubit doesn't support qutrit observables.") - dev = device(wires=2, shots=shots) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) + dev = qml.device(device, wires=2, shots=shots) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1297,9 +1293,9 @@ def circuit(x): @pytest.mark.parametrize("wires", wires) def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" - dev = device(wires=wires) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ(0) if device != DefaultQutrit else qml.GellMann(0, 3) + dev = qml.device(device, wires=wires) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ(0) if device != "default.qutrit" else qml.GellMann(0, 3) def circuit(x): func(x) @@ -1320,15 +1316,15 @@ def circuit(x): @pytest.mark.parametrize("shot_vector", shot_vectors) def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" - # pylint:disable=unexpected-keyword-arg - dev = device(wires=wires, shots=shot_vector) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ if device != DefaultQutrit else qml.GellMann + dev = qml.device(device, wires=wires, shots=shot_vector) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ if device != "default.qutrit" else qml.GellMann def circuit(x): func(x) + # pylint:disable=unexpected-keyword-arg return [ - qml.expval(obs(wires=i) if device != DefaultQutrit else obs(wires=i, index=3)) + qml.expval(obs(wires=i) if device != "default.qutrit" else obs(wires=i, index=3)) for i in range(0, wires) ] @@ -1354,12 +1350,12 @@ def circuit(x): @pytest.mark.parametrize("device", devices) def test_array_multiple(self, device): """Return PennyLane array of multiple measurements""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") - dev = device(wires=2) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) + dev = qml.device(device, wires=2) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1370,20 +1366,20 @@ def circuit(x): assert isinstance(res, qml.numpy.ndarray) assert res[0].shape == () - assert res[1].shape == (4,) if device != DefaultQutrit else (9,) + assert res[1].shape == (4,) if device != "default.qutrit" else (9,) @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize("comp_basis_sampling", [qml.sample(), qml.counts()]) def test_sample_counts_no_obs(self, device, comp_basis_sampling): """Measuring qml.sample()/qml.counts() works with other measurements even with the same wire being measured.""" - if device == DefaultQutrit: + if device == "default.qutrit": pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") shot_num = 1000 num_wires = 2 - dev = device(wires=num_wires, shots=shot_num) - func = qubit_ansatz if device != DefaultQutrit else qutrit_ansatz - obs = qml.PauliZ(1) if device != DefaultQutrit else qml.GellMann(1, 3) + dev = qml.device(device, wires=num_wires, shots=shot_num) + func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz + obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) def circuit(x): func(x) @@ -1405,7 +1401,7 @@ def circuit(x): assert res[2].shape == (2,) -devices = [DefaultQubitTF, DefaultMixed] +devices = ["default.qubit.tf", "default.mixed"] @pytest.mark.tf @@ -1419,7 +1415,7 @@ def test_multiple_expval(self, device): """Return multiple expvals.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1443,7 +1439,7 @@ def test_multiple_var(self, device): """Return multiple vars.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1481,7 +1477,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1514,7 +1510,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1556,10 +1552,10 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import tensorflow as tf - if device in [DefaultMixed, DefaultQubit]: + if device in ["default.mixed", "default.qubit.legacy"]: pytest.skip("Sample must be reworked with interfaces.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1583,9 +1579,9 @@ def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" import tensorflow as tf - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Mixed as array must be reworked for shots.") def circuit(x): @@ -1612,7 +1608,7 @@ def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" import tensorflow as tf - dev = device(wires=wires) + dev = qml.device(device, wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -1636,13 +1632,13 @@ def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" import tensorflow as tf - if device == DefaultMixed and shot_vector: + if device == "default.mixed" and shot_vector: pytest.skip("No support for shot vector and Tensorflow because use of .T in statistics") - if device == DefaultQubitTF and shot_vector: + if device == "default.qubit.tf" and shot_vector: pytest.skip("No support for shot vector and mixed device with Tensorflow.") - dev = device(wires=wires, shots=shot_vector) + dev = qml.device(device, wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -1669,7 +1665,7 @@ def circuit(x): assert t.shape == () -devices = [DefaultQubitTorch, DefaultMixed] +devices = ["default.qubit.torch", "default.mixed"] @pytest.mark.torch @@ -1683,7 +1679,7 @@ def test_multiple_expval(self, device): """Return multiple expvals.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1707,7 +1703,7 @@ def test_multiple_var(self, device): """Return multiple vars.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1745,7 +1741,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): """Return multiple probs.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1778,7 +1774,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): """Return multiple different measurements.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1820,10 +1816,10 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import torch - if device in [DefaultMixed, DefaultQubit]: + if device in ["default.mixed", "default.qubit.legacy"]: pytest.skip("Sample need to be rewritten for interfaces.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1847,10 +1843,10 @@ def test_expval_counts(self, measurement, device, shots=100): """Test the expval and counts measurements together.""" import torch - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Counts need to be rewritten for interfaces.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -1876,7 +1872,7 @@ def test_list_one_expval(self, wires, device): """Return a comprehension list of one expvals.""" import torch - dev = device(wires=wires) + dev = qml.device(device, wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -1901,10 +1897,10 @@ def test_list_multiple_expval(self, wires, device, shot_vector): """Return a comprehension list of multiple expvals.""" import torch - if device == DefaultMixed and shot_vector: + if device == "default.mixed" and shot_vector: pytest.skip("No support for shot vector and mixed device with Torch.") - dev = device(wires=wires, shots=shot_vector) + dev = qml.device(device, wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -1931,7 +1927,7 @@ def circuit(x): assert t.shape == () -devices = [DefaultQubitJax, DefaultMixed] +devices = ["default.qubit.jax", "default.mixed"] @pytest.mark.jax @@ -1948,7 +1944,7 @@ def test_multiple_expval(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -1975,7 +1971,7 @@ def test_multiple_var(self, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2016,7 +2012,7 @@ def test_multiple_prob(self, op1, op2, wires1, wires2, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2052,7 +2048,7 @@ def test_mix_meas(self, op1, wires1, op2, wires2, wires3, wires4, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) def circuit(x): qml.Hadamard(wires=[0]) @@ -2097,10 +2093,10 @@ def test_expval_sample(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Sample need to be rewritten for interfaces.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -2127,10 +2123,10 @@ def test_expval_counts(self, measurement, device, shots=100): config.update("jax_enable_x64", True) import jax - if device == DefaultMixed: + if device == "default.mixed": pytest.skip("Counts need to be rewritten for interfaces and mixed device.") - dev = device(wires=2, shots=shots) + dev = qml.device(device, wires=2, shots=shots) def circuit(x): qml.Hadamard(wires=[0]) @@ -2159,7 +2155,7 @@ def test_list_one_expval(self, wires, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=wires) + dev = qml.device(device, wires=wires) def circuit(x): qml.Hadamard(wires=[0]) @@ -2186,10 +2182,10 @@ def test_list_multiple_expval(self, wires, device, shot_vector): config.update("jax_enable_x64", True) import jax - if device == DefaultMixed and shot_vector: + if device == "default.mixed" and shot_vector: pytest.skip("No support for shot vector and mixed device with Jax") - dev = device(wires=wires, shots=shot_vector) + dev = qml.device(device, wires=wires, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2241,7 +2237,7 @@ def circuit(x): shot_vectors = [[10, 1000], [1, 10, 10, 1000], [1, (10, 2), 1000]] -devices = [DefaultQubit, DefaultMixed] +devices = ["default.qubit.legacy", "default.mixed"] @pytest.mark.parametrize("device", devices) @@ -2252,7 +2248,7 @@ class TestIntegrationShotVectors: @pytest.mark.parametrize("measurement", single_scalar_output_measurements) def test_scalar(self, shot_vector, measurement, device): """Test a single scalar-valued measurement.""" - dev = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2272,7 +2268,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, shot_vector, op, wires, device): """Test a single probability measurement.""" - dev = DefaultQubit(wires=2, shots=shot_vector) + dev = qml.device("default.qubit.legacy", wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2296,7 +2292,7 @@ def circuit(x): @pytest.mark.xfail def test_density_matrix(self, shot_vector, wires, device): """Test a density matrix measurement.""" - dev = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2317,7 +2313,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2343,7 +2339,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2369,7 +2365,7 @@ class TestIntegrationSameMeasurementShotVector: def test_scalar(self, shot_vector, device): """Test multiple scalar-valued measurements.""" - dev = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2399,7 +2395,7 @@ def circuit(x): @pytest.mark.parametrize("op2,wires2", reversed(probs_data2)) def test_probs(self, shot_vector, op1, wires1, op2, wires2, device): """Test multiple probability measurements.""" - dev = device(wires=4, shots=shot_vector) + dev = qml.device(device, wires=4, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2425,7 +2421,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2448,7 +2444,7 @@ def circuit(x): @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 = device(wires=2, shots=shot_vector) + dev = qml.device(device, wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2538,7 +2534,7 @@ class TestIntegrationMultipleMeasurementsShotVector: @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 = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2569,7 +2565,7 @@ def circuit(x): def test_scalar_sample_with_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and sample measurements where sample takes an observable.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -2602,7 +2598,7 @@ def circuit(x): @pytest.mark.xfail def test_scalar_sample_no_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and computational basis sample measurements.""" - dev = device(wires=3, shots=shot_vector) + dev = qml.device(device, wires=3, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2633,7 +2629,7 @@ def circuit(x): def test_scalar_counts_with_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and counts measurements where counts takes an observable.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -2673,7 +2669,7 @@ def circuit(x): @pytest.mark.xfail def test_scalar_counts_no_obs(self, shot_vector, meas1, meas2, device): """Test scalar-valued and computational basis counts measurements.""" - dev = device(wires=3, shots=shot_vector) + 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) @@ -2706,7 +2702,7 @@ def circuit(x): @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) def test_probs_sample(self, shot_vector, sample_obs, device): """Test probs and sample measurements.""" - dev = device(wires=3, shots=shot_vector) + 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) @@ -2753,7 +2749,7 @@ def circuit(x): @pytest.mark.parametrize("sample_obs", [qml.PauliZ, None]) def test_probs_counts(self, shot_vector, sample_obs, device): """Test probs and counts measurements.""" - dev = device(wires=3, shots=shot_vector) + 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) ] @@ -2801,7 +2797,7 @@ def circuit(x): 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 = device(wires=6, shots=shot_vector) + 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) ] @@ -2852,7 +2848,7 @@ def circuit(x): 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 = device(wires=5, shots=shot_vector) + 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) ] @@ -2910,7 +2906,7 @@ class TestIntegrationJacobianBackpropMultipleReturns: @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_expval_autograd(self, interface, device): """Return Jacobian of multiple expvals.""" - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2937,7 +2933,7 @@ def test_multiple_expval_torch(self, interface, device): """Return Jacobian of multiple expvals.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2964,7 +2960,7 @@ def test_multiple_expval_tf(self, interface, device): """Return Jacobian of multiple expvals.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -2991,7 +2987,7 @@ def test_multiple_meas_tf_autograph(self, interface): """Return Jacobian of multiple measurements with Tf Autograph.""" import tensorflow as tf - dev = DefaultQubit(wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @tf.function @qml.qnode(dev, interface=interface) @@ -3025,7 +3021,7 @@ def test_multiple_expval_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3054,7 +3050,7 @@ def test_multiple_expval_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3077,7 +3073,7 @@ def circuit(a): @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_probs_autograd(self, interface, device): """Return Jacobian of multiple probs.""" - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3104,7 +3100,7 @@ def test_multiple_probs_torch(self, interface, device): """Return Jacobian of multiple probs.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3131,7 +3127,7 @@ def test_multiple_probs_tf(self, interface, device): """Return Jacobian of multiple probs.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3162,7 +3158,7 @@ def test_multiple_probs_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3192,7 +3188,7 @@ def test_multiple_probs_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3216,7 +3212,7 @@ def circuit(a): @pytest.mark.parametrize("interface", ["auto", "autograd"]) def test_multiple_meas_autograd(self, interface, device): """Return Jacobian of multiple measurements.""" - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3243,7 +3239,7 @@ def test_multiple_meas_torch(self, interface, device): """Return Jacobian of multiple measurements.""" import torch - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3275,7 +3271,7 @@ def test_multiple_meas_tf(self, interface, device): """Return Jacobian of multiple measurements.""" import tensorflow as tf - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3310,7 +3306,7 @@ def test_multiple_meas_jax(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): @@ -3345,7 +3341,7 @@ def test_multiple_meas_jax_jit(self, interface, device): config.update("jax_enable_x64", True) import jax - dev = device(wires=2) + dev = qml.device(device, wires=2) @qml.qnode(dev, interface=interface) def circuit(a): From 4e71b6822dc40b181a37a77a86396f1632feea77 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 11 Aug 2023 16:56:10 -0400 Subject: [PATCH 11/78] don't import DQ2 at top level --- pennylane/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane/__init__.py b/pennylane/__init__.py index 8d5c51bb3cd..09da5112115 100644 --- a/pennylane/__init__.py +++ b/pennylane/__init__.py @@ -122,7 +122,6 @@ import pennylane.qinfo # pylint:disable=wrong-import-order from pennylane.interfaces import execute # pylint:disable=wrong-import-order import pennylane.logging # pylint:disable=wrong-import-order -from pennylane.devices.experimental import DefaultQubit2 import pennylane.data From 90400bd89793318c529cede6e245c1d3e99093be Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Sun, 13 Aug 2023 11:24:31 -0400 Subject: [PATCH 12/78] fix qinfo module tests --- pennylane/qinfo/transforms.py | 55 +++++++++++++++++++----------- tests/qinfo/test_fidelity.py | 2 ++ tests/qinfo/test_fisher.py | 6 ++-- tests/qinfo/test_reduced_dm.py | 2 +- tests/qinfo/test_trace_distance.py | 1 + 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/pennylane/qinfo/transforms.py b/pennylane/qinfo/transforms.py index b57d3ffc460..2d415ad6e1f 100644 --- a/pennylane/qinfo/transforms.py +++ b/pennylane/qinfo/transforms.py @@ -21,6 +21,10 @@ from pennylane.transforms import adjoint_metric_tensor, batch_transform, metric_tensor +def _get_qnode_wires(qnode): + return qnode.device.wires if isinstance(qnode.device, qml.Device) else qnode.tape.wires + + def reduced_dm(qnode, wires): """Compute the reduced density matrix from a :class:`~.QNode` returning :func:`~pennylane.state`. @@ -51,8 +55,6 @@ def circuit(x): .. seealso:: :func:`pennylane.density_matrix` and :func:`pennylane.math.reduce_dm` """ - wire_map = {w: i for i, w in enumerate(qnode.device.wires)} - indices = [wire_map[w] for w in wires] def wrapper(*args, **kwargs): qnode.construct(args, kwargs) @@ -68,7 +70,11 @@ def wrapper(*args, **kwargs): # TODO: optimize given the wires by creating a tape with relevant operations state_built = qnode(*args, **kwargs) - density_matrix = dm_func(state_built, indices=indices, c_dtype=qnode.device.C_DTYPE) + wire_map = {w: i for i, w in enumerate(_get_qnode_wires(qnode))} + indices = [wire_map[w] for w in wires] + density_matrix = dm_func( + state_built, indices=indices, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") + ) return density_matrix return wrapper @@ -123,8 +129,6 @@ def circuit(x): .. seealso:: :func:`pennylane.math.purity` """ - wire_map = {w: i for i, w in enumerate(qnode.device.wires)} - indices = [wire_map[w] for w in wires] def wrapper(*args, **kwargs): # Construct tape @@ -145,7 +149,11 @@ def wrapper(*args, **kwargs): if not dm_measurement: state_built = qml.math.dm_from_state_vector(state_built) - return qml.math.purity(state_built, indices, c_dtype=qnode.device.C_DTYPE) + wire_map = {w: i for i, w in enumerate(_get_qnode_wires(qnode))} + indices = [wire_map[w] for w in wires] + return qml.math.purity( + state_built, indices, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") + ) return wrapper @@ -188,15 +196,14 @@ def circuit(x): .. seealso:: :func:`pennylane.math.vn_entropy` and :func:`pennylane.vn_entropy` """ - wire_map = {w: i for i, w in enumerate(qnode.device.wires)} - indices = [wire_map[w] for w in wires] - - density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode.device.wires) def wrapper(*args, **kwargs): # If pure state directly return 0. - if len(wires) == len(qnode.device.wires): - qnode.construct(args, kwargs) + qnode.construct(args, kwargs) + qnode_wires = _get_qnode_wires(qnode) + wire_map = {w: i for i, w in enumerate(qnode_wires)} + indices = [wire_map[w] for w in wires] + if len(wires) == len(qnode_wires): measurements = qnode.tape.measurements if len(measurements) != 1 or not isinstance(measurements[0], StateMP): raise ValueError("The qfunc return type needs to be a state.") @@ -212,12 +219,18 @@ def wrapper(*args, **kwargs): density_matrix = qnode(*args, **kwargs) entropy = qml.math.vn_entropy( - density_matrix, indices, base, c_dtype=qnode.device.C_DTYPE + density_matrix, + indices, + base, + c_dtype=getattr(qnode.device, "C_DTYPE", "complex128"), ) return entropy + density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode_wires) density_matrix = density_matrix_qnode(*args, **kwargs) - entropy = qml.math.vn_entropy(density_matrix, indices, base, c_dtype=qnode.device.C_DTYPE) + entropy = qml.math.vn_entropy( + density_matrix, indices, base, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") + ) return entropy return wrapper @@ -271,13 +284,17 @@ def circuit(x): .. seealso:: :func:`~.qinfo.vn_entropy`, :func:`pennylane.math.mutual_info` and :func:`pennylane.mutual_info` """ - wire_map = {w: i for i, w in enumerate(qnode.device.wires)} - indices0 = [wire_map[w] for w in wires0] - indices1 = [wire_map[w] for w in wires1] - - density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode.device.wires) def wrapper(*args, **kwargs): + qnode_wires = ( + qnode.device.wires + if isinstance(qnode.device, qml.Device) + else qml.tape.make_qscript(qnode.func)(*args, **kwargs).wires + ) + wire_map = {w: i for i, w in enumerate(qnode_wires)} + indices0 = [wire_map[w] for w in wires0] + indices1 = [wire_map[w] for w in wires1] + density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode_wires) density_matrix = density_matrix_qnode(*args, **kwargs) entropy = qml.math.mutual_info(density_matrix, indices0, indices1, base=base) return entropy diff --git a/tests/qinfo/test_fidelity.py b/tests/qinfo/test_fidelity.py index 4d4604b33cb..a9146344f79 100644 --- a/tests/qinfo/test_fidelity.py +++ b/tests/qinfo/test_fidelity.py @@ -101,6 +101,7 @@ def circuit0(x): @qml.qnode(dev) def circuit1(): + qml.Identity(0) return qml.state() fid = qml.qinfo.fidelity(circuit0, circuit1, wires0=[0], wires1=[0])((np.pi)) @@ -113,6 +114,7 @@ def test_fidelity_qnodes_state_rx(self, device): @qml.qnode(dev) def circuit0(): + qml.Identity(0) return qml.state() @qml.qnode(dev) diff --git a/tests/qinfo/test_fisher.py b/tests/qinfo/test_fisher.py index b8ea2f4c361..e384e5dce34 100644 --- a/tests/qinfo/test_fisher.py +++ b/tests/qinfo/test_fisher.py @@ -147,8 +147,8 @@ def test_quantum_fisher_info(self): n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) - dev_hard = qml.device("default.qubit", wires=n_wires + 1, shots=1000) + dev = qml.device("default.qubit.legacy", wires=n_wires) + dev_hard = qml.device("default.qubit.legacy", wires=n_wires + 1, shots=1000) def qfunc(params): qml.RX(params[0], wires=0) @@ -160,7 +160,7 @@ def qfunc(params): circ_hard = qml.QNode(qfunc, dev_hard) QFIM_hard = quantum_fisher(circ_hard)(params) - QFIM1_hard = 4.0 * qml.metric_tensor(circ_hard)(params) + QFIM1_hard = 4.0 * qml.metric_tensor(circ_hard)(params) # pylint:disable=not-callable circ = qml.QNode(qfunc, dev) QFIM = quantum_fisher(circ)(params) diff --git a/tests/qinfo/test_reduced_dm.py b/tests/qinfo/test_reduced_dm.py index da76fd5a256..3427bf1e066 100644 --- a/tests/qinfo/test_reduced_dm.py +++ b/tests/qinfo/test_reduced_dm.py @@ -158,7 +158,7 @@ def circuit(x): def test_density_matrix_c_dtype(self, wires, c_dtype): """Test different complex dtype.""" - dev = qml.device("default.qubit", wires=2, c_dtype=c_dtype) + dev = qml.device("default.qubit.legacy", wires=2, c_dtype=c_dtype) @qml.qnode(dev, diff_method=None) def circuit(x): diff --git a/tests/qinfo/test_trace_distance.py b/tests/qinfo/test_trace_distance.py index 892000a9737..280b774f000 100644 --- a/tests/qinfo/test_trace_distance.py +++ b/tests/qinfo/test_trace_distance.py @@ -71,6 +71,7 @@ def circuit0(x): @qml.qnode(dev) def circuit1(): + qml.Identity(0) return qml.state() td = qml.qinfo.trace_distance(circuit0, circuit1, wires0=[0], wires1=[0])(np.pi, None) From e7d54d3fc3bd690d499f139f85a289f27e4a2956 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 14 Aug 2023 12:34:33 -0400 Subject: [PATCH 13/78] Revert "add is_state_batched to mp.process_state; probs supports jitting" This reverts commit 840f30adf5aaa2d4e2a63fd6d4a942cbeeada6a3. --- pennylane/devices/qubit/measure.py | 4 +--- pennylane/devices/qubit/sampling.py | 4 +--- pennylane/devices/tests/test_measurements.py | 4 ++-- pennylane/measurements/expval.py | 12 +++--------- pennylane/measurements/measurements.py | 10 +++------- pennylane/measurements/mutual_info.py | 4 +--- pennylane/measurements/probs.py | 13 +++++++++---- pennylane/measurements/purity.py | 4 +--- pennylane/measurements/state.py | 4 +--- pennylane/measurements/var.py | 12 +++--------- pennylane/measurements/vn_entropy.py | 4 +--- 11 files changed, 26 insertions(+), 49 deletions(-) diff --git a/pennylane/devices/qubit/measure.py b/pennylane/devices/qubit/measure.py index fc35d861661..e30a0c809b0 100644 --- a/pennylane/devices/qubit/measure.py +++ b/pennylane/devices/qubit/measure.py @@ -49,9 +49,7 @@ def state_diagonalizing_gates( flattened_state = ( math.reshape(state, (state.shape[0], -1)) if is_state_batched else math.flatten(state) ) - return measurementprocess.process_state( - flattened_state, wires, is_state_batched=is_state_batched - ) + return measurementprocess.process_state(flattened_state, wires) def csr_dot_products( diff --git a/pennylane/devices/qubit/sampling.py b/pennylane/devices/qubit/sampling.py index 14ab26d42ba..2bb170ec5ad 100644 --- a/pennylane/devices/qubit/sampling.py +++ b/pennylane/devices/qubit/sampling.py @@ -340,9 +340,7 @@ def sample_state( num_wires = len(wires_to_sample) basis_states = np.arange(2**num_wires) - probs = qml.probs(wires=wires_to_sample).process_state( - state, state_wires, is_state_batched=is_state_batched - ) + probs = qml.probs(wires=wires_to_sample).process_state(state, state_wires) if is_state_batched: # rng.choice doesn't support broadcasting diff --git a/pennylane/devices/tests/test_measurements.py b/pennylane/devices/tests/test_measurements.py index 69c8debb121..203305c0f96 100644 --- a/pennylane/devices/tests/test_measurements.py +++ b/pennylane/devices/tests/test_measurements.py @@ -1680,7 +1680,7 @@ def test_custom_state_measurement(self, device): class MyMeasurement(StateMeasurement): """Dummy state measurement.""" - def process_state(self, state, wire_order, is_state_batched=False): + def process_state(self, state, wire_order): return 1 @qml.qnode(dev) @@ -1701,7 +1701,7 @@ def test_sample_measurement_with_shots(self, device): class MyMeasurement(StateMeasurement): """Dummy state measurement.""" - def process_state(self, state, wire_order, is_state_batched=False): + def process_state(self, state, wire_order): return 1 @qml.qnode(dev) diff --git a/pennylane/measurements/expval.py b/pennylane/measurements/expval.py index 267797d9c56..e696546ff56 100644 --- a/pennylane/measurements/expval.py +++ b/pennylane/measurements/expval.py @@ -121,21 +121,15 @@ def process_samples( # TODO: do we need to squeeze here? Maybe remove with new return types return qml.math.squeeze(qml.math.mean(samples, axis=axis)) - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): if isinstance(self.obs, Projector): # branch specifically to handle the projector observable idx = int("".join(str(i) for i in self.obs.parameters[0]), 2) - probs = qml.probs(wires=self.wires).process_state( - state=state, wire_order=wire_order, is_state_batched=is_state_batched - ) + probs = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) return probs[idx] eigvals = qml.math.asarray(self.obs.eigvals(), dtype="float64") # we use ``self.wires`` instead of ``self.obs`` because the observable was # already applied to the state - prob = qml.probs(wires=self.wires).process_state( - state=state, wire_order=wire_order, is_state_batched=is_state_batched - ) + prob = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) # In case of broadcasting, `prob` has two axes and this is a matrix-vector product return qml.math.dot(prob, eigvals) diff --git a/pennylane/measurements/measurements.py b/pennylane/measurements/measurements.py index 977c5dcaf7d..50551158e2d 100644 --- a/pennylane/measurements/measurements.py +++ b/pennylane/measurements/measurements.py @@ -570,17 +570,16 @@ class StateMeasurement(MeasurementProcess): * state (Sequence[complex]): quantum state * wire_order (Wires): wires determining the subspace that ``state`` acts on; a matrix of dimension :math:`2^n` acts on a subspace of :math:`n` wires - * is_state_batched (Optional[bool]): whether the state is batched or not **Example:** Let's create a measurement that returns the diagonal of the reduced density matrix. >>> class MyMeasurement(StateMeasurement): - ... def process_state(self, state, wire_order, is_state_batched=False): + ... def process_state(self, state, wire_order): ... # use the already defined `qml.density_matrix` measurement to compute the ... # reduced density matrix from the given state - ... density_matrix = qml.density_matrix(wires=self.wires).process_state(state, wire_order, is_state_batched=is_state_batched) + ... density_matrix = qml.density_matrix(wires=self.wires).process_state(state, wire_order) ... return qml.math.diagonal(qml.math.real(density_matrix)) We can now execute it in a QNode: @@ -596,16 +595,13 @@ class StateMeasurement(MeasurementProcess): """ @abstractmethod - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): """Process the given quantum state. Args: state (Sequence[complex]): quantum state wire_order (Wires): wires determining the subspace that ``state`` acts on; a matrix of dimension :math:`2^n` acts on a subspace of :math:`n` wires - is_state_batched (Optional[bool]): whether the state is batched or not """ diff --git a/pennylane/measurements/mutual_info.py b/pennylane/measurements/mutual_info.py index 9cc8d697f1c..991d56a7554 100644 --- a/pennylane/measurements/mutual_info.py +++ b/pennylane/measurements/mutual_info.py @@ -145,9 +145,7 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): state = qml.math.dm_from_state_vector(state) return qml.math.mutual_info( state, diff --git a/pennylane/measurements/probs.py b/pennylane/measurements/probs.py index d039cf7b896..0fa8c9a32e7 100644 --- a/pennylane/measurements/probs.py +++ b/pennylane/measurements/probs.py @@ -194,13 +194,18 @@ def process_samples( prob = self._count_samples(indices, batch_size, dim) return qml.math.squeeze(prob) if bin_size is None else prob - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): num_wires = len(wire_order) dim = 2**num_wires # Compute batch_size - batch_size = qml.math.size(state) // dim if is_state_batched else None + expected_shape = [2] * num_wires + expected_size = dim + size = qml.math.size(state) + batch_size = ( + size // expected_size + if qml.math.ndim(state) > len(expected_shape) or size > expected_size + else None + ) flat_state = qml.math.reshape( state, (batch_size, dim) if batch_size is not None else (dim,) ) diff --git a/pennylane/measurements/purity.py b/pennylane/measurements/purity.py index fea6cf010af..7bf411007e8 100644 --- a/pennylane/measurements/purity.py +++ b/pennylane/measurements/purity.py @@ -98,9 +98,7 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): wire_map = dict(zip(wire_order, list(range(len(wire_order))))) indices = [wire_map[w] for w in self.wires] state = qml.math.dm_from_state_vector(state) diff --git a/pennylane/measurements/state.py b/pennylane/measurements/state.py index 7116dab7a67..22e89d2aae2 100644 --- a/pennylane/measurements/state.py +++ b/pennylane/measurements/state.py @@ -183,9 +183,7 @@ def shape(self, device, shots): return (dim,) if num_shot_elements == 1 else tuple((dim,) for _ in range(num_shot_elements)) # pylint: disable=redefined-outer-name - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): if self.wires: # qml.density_matrix wire_map = dict(zip(wire_order, range(len(wire_order)))) diff --git a/pennylane/measurements/var.py b/pennylane/measurements/var.py index 59a1e5df262..60fd35da323 100644 --- a/pennylane/measurements/var.py +++ b/pennylane/measurements/var.py @@ -124,25 +124,19 @@ def process_samples( # TODO: do we need to squeeze here? Maybe remove with new return types return qml.math.squeeze(qml.math.var(samples, axis=axis)) - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): if isinstance(self.obs, Projector): # branch specifically to handle the projector observable idx = int("".join(str(i) for i in self.obs.parameters[0]), 2) # we use ``self.wires`` instead of ``self.obs`` because the observable was # already applied to the state - probs = qml.probs(wires=self.wires).process_state( - state=state, wire_order=wire_order, is_state_batched=is_state_batched - ) + probs = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) return probs[idx] - probs[idx] ** 2 eigvals = qml.math.asarray(self.obs.eigvals(), dtype=float) # we use ``wires`` instead of ``op`` because the observable was # already applied to the state - prob = qml.probs(wires=self.wires).process_state( - state=state, wire_order=wire_order, is_state_batched=is_state_batched - ) + prob = qml.probs(wires=self.wires).process_state(state=state, wire_order=wire_order) # In case of broadcasting, `prob` has two axes and these are a matrix-vector products return qml.math.dot(prob, (eigvals**2)) - qml.math.dot(prob, eigvals) ** 2 diff --git a/pennylane/measurements/vn_entropy.py b/pennylane/measurements/vn_entropy.py index 9ce76a6621a..67228cadfb1 100644 --- a/pennylane/measurements/vn_entropy.py +++ b/pennylane/measurements/vn_entropy.py @@ -122,9 +122,7 @@ def shape(self, device, shots): num_shot_elements = sum(s.copies for s in shots.shot_vector) return tuple(() for _ in range(num_shot_elements)) - def process_state( - self, state: Sequence[complex], wire_order: Wires, is_state_batched: bool = False - ): + def process_state(self, state: Sequence[complex], wire_order: Wires): state = qml.math.dm_from_state_vector(state) return qml.math.vn_entropy( state, indices=self.wires, c_dtype=state.dtype, base=self.log_base From 6c7f69efe8cd4f84b151af84b423b50d2d23b02e Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 14 Aug 2023 12:39:24 -0400 Subject: [PATCH 14/78] put back adjoint metric tensor change with new fix --- .../transforms/test_adjoint_metric_tensor.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/transforms/test_adjoint_metric_tensor.py b/tests/transforms/test_adjoint_metric_tensor.py index 605a8251e06..f4c37be342f 100644 --- a/tests/transforms/test_adjoint_metric_tensor.py +++ b/tests/transforms/test_adjoint_metric_tensor.py @@ -204,7 +204,7 @@ def fubini_ansatz10(weights, wires=None): def autodiff_metric_tensor(ansatz, num_wires): """Compute the metric tensor by full state vector differentiation via autograd.""" - dev = qml.device("default.qubit.legacy", wires=num_wires) + dev = qml.device("default.qubit", wires=num_wires) @qml.qnode(dev) def qnode(*params): @@ -383,7 +383,7 @@ def test_correct_output_qnode_autograd(self, ansatz, params, interface): """Test that the output is correct when using Autograd and calling the adjoint metric tensor on a QNode.""" expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) - dev = qml.device("default.qubit.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -412,7 +412,7 @@ def test_correct_output_qnode_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.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface="jax") def circuit(*params): @@ -468,7 +468,7 @@ def test_correct_output_qnode_tf(self, ansatz, params, interface): expected = autodiff_metric_tensor(ansatz, self.num_wires)(*params) t_params = tuple(tf.Variable(p, dtype=tf.float64) for p in params) - dev = qml.device("default.qubit.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface=interface) def circuit(*params): @@ -492,7 +492,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.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) dev2 = qml.device("default.qubit.autograd", wires=self.num_wires) @qml.qnode(dev) @@ -536,7 +536,7 @@ def test_autograd(self, ansatz, params): calling the adjoint metric tensor on a QNode.""" exp_fn = autodiff_metric_tensor(ansatz, self.num_wires) expected = qml.jacobian(exp_fn)(*params) - dev = qml.device("default.qubit.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface="autograd") def circuit(*params): @@ -563,7 +563,7 @@ def test_correct_output_qnode_jax(self, ansatz, params): expected = qml.jacobian(autodiff_metric_tensor(ansatz, self.num_wires))(*params) j_params = tuple(jax.numpy.array(p) for p in params) - dev = qml.device("default.qubit.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface="jax") def circuit(*params): @@ -591,7 +591,7 @@ def test_correct_output_qnode_torch(self, ansatz, params): expected = qml.jacobian(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.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface="torch") def circuit(*params): @@ -616,7 +616,7 @@ def test_correct_output_qnode_tf(self, ansatz, params): expected = qml.jacobian(autodiff_metric_tensor(ansatz, self.num_wires))(*params) t_params = tuple(tf.Variable(p, dtype=tf.float64) for p in params) - dev = qml.device("default.qubit.legacy", wires=self.num_wires) + dev = qml.device("default.qubit", wires=self.num_wires) @qml.qnode(dev, interface="tf") def circuit(*params): @@ -646,7 +646,7 @@ def ansatz(x, y): qml.RX(x, wires=0) qml.RY(y, wires=1) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) with pytest.raises(qml.QuantumFunctionError, match="The passed object is not a "): qml.adjoint_metric_tensor(ansatz, device=dev) @@ -657,7 +657,7 @@ def test_error_finite_shots(self): qml.RX(0.2, wires=0) qml.RY(1.9, wires=1) tape = qml.tape.QuantumScript.from_queue(q, shots=1) - dev = qml.device("default.qubit.legacy", wires=2, shots=1) + dev = qml.device("default.qubit", wires=2, shots=1) with pytest.raises(ValueError, match="The adjoint method for the metric tensor"): qml.adjoint_metric_tensor(tape, device=dev) @@ -665,8 +665,8 @@ def test_error_finite_shots(self): def test_warning_multiple_devices(self): """Test that a warning is issued if an ExpvalCost with multiple devices is passed.""" - dev1 = qml.device("default.qubit.legacy", wires=2) - dev2 = qml.device("default.qubit.legacy", wires=1) + dev1 = qml.device("default.qubit", wires=2) + dev2 = qml.device("default.qubit", wires=1) H = qml.Hamiltonian([0.2, 0.9], [qml.PauliZ(0), qml.PauliY(0)]) def ansatz(x, wires): From b508abbd8e160443d7aabab10bdff501190e9718 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 14 Aug 2023 16:50:22 -0400 Subject: [PATCH 15/78] use legacy device for legacy interface tests --- tests/interfaces/test_autograd.py | 68 +++++++++--------- tests/interfaces/test_autograd_qnode.py | 70 +++++++++---------- .../test_autograd_qnode_shot_vector.py | 6 +- tests/interfaces/test_jax.py | 50 ++++++------- tests/interfaces/test_jax_jit.py | 52 +++++++------- tests/interfaces/test_jax_jit_qnode.py | 22 +++--- tests/interfaces/test_jax_qnode.py | 24 +++---- .../interfaces/test_jax_qnode_shot_vector.py | 14 ++-- tests/interfaces/test_tensorflow.py | 48 ++++++------- ..._tensorflow_autograph_qnode_shot_vector.py | 6 +- tests/interfaces/test_tensorflow_qnode.py | 56 +++++++-------- .../test_tensorflow_qnode_shot_vector.py | 6 +- tests/interfaces/test_torch.py | 62 ++++++++-------- tests/interfaces/test_torch_qnode.py | 52 +++++++------- .../test_transform_program_integration.py | 4 +- 15 files changed, 270 insertions(+), 270 deletions(-) diff --git a/tests/interfaces/test_autograd.py b/tests/interfaces/test_autograd.py index 6f32aec02bb..e93e7ce8037 100644 --- a/tests/interfaces/test_autograd.py +++ b/tests/interfaces/test_autograd.py @@ -41,7 +41,7 @@ def test_import_error(self, mocker): except KeyError: pass - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) with qml.queuing.AnnotatedQueue() as q: qml.expval(qml.PauliY(1)) @@ -60,7 +60,7 @@ def test_jacobian_options(self, mocker): a = np.array([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -86,7 +86,7 @@ def test_incorrect_grad_on_execution(self): is used with grad_on_execution=True""" a = np.array([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -106,7 +106,7 @@ def test_unknown_interface(self): """Test that an error is raised if the interface is unknown""" a = np.array([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -122,7 +122,7 @@ def cost(a, device): def test_grad_on_execution(self, mocker): """Test that grad on execution uses the `device.execute_and_gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(dev, "execute_and_gradients") def cost(a): @@ -148,7 +148,7 @@ def cost(a): def test_no_gradients_on_execution(self, mocker): """Test that no grad on execution uses the `device.batch_execute` and `device.gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy_execute = mocker.spy(qml.devices.DefaultQubit, "batch_execute") spy_gradients = mocker.spy(qml.devices.DefaultQubit, "gradients") @@ -184,7 +184,7 @@ class TestBatchTransformExecution: def test_no_batch_transform(self, mocker): """Test that batch transforms can be disabled and enabled""" - dev = qml.device("default.qubit", wires=2, shots=100000) + dev = qml.device("default.qubit.legacy", wires=2, shots=100000) H = qml.PauliZ(0) @ qml.PauliZ(1) - qml.PauliX(0) x = 0.6 @@ -214,7 +214,7 @@ def test_no_batch_transform(self, mocker): def test_batch_transform_dynamic_shots(self): """Tests that the batch transform considers the number of shots for the execution, not those statically on the device.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) H = 2.0 * qml.PauliZ(0) qscript = qml.tape.QuantumScript(measurements=[qml.expval(H)]) res = qml.execute([qscript], dev, interface=None, override_shots=10) @@ -226,7 +226,7 @@ class TestCaching: def test_cache_maxsize(self, mocker): """Test the cachesize property of the cache""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cachesize): @@ -248,7 +248,7 @@ def cost(a, cachesize): def test_custom_cache(self, mocker): """Test the use of a custom cache object""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cache): @@ -270,7 +270,7 @@ def cost(a, cache): def test_caching_param_shift(self, tol): """Test that, when using parameter-shift transform, caching reduces the number of evaluations to their optimum.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, cache): with qml.queuing.AnnotatedQueue() as q: @@ -315,7 +315,7 @@ def test_caching_param_shift_hessian(self, num_params, tol): """Test that, when using parameter-shift transform, caching reduces the number of evaluations to their optimum when computing Hessians.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = np.arange(1, num_params + 1) / 10 N = len(params) @@ -378,7 +378,7 @@ def cost(x, cache): def test_caching_adjoint_no_grad_on_execution(self): """Test that caching reduces the number of adjoint evaluations when the grads is not on execution.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = np.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -418,7 +418,7 @@ def test_single_backward_pass_batch(self): """Tests that the backward pass is one single batch, not a bunch of batches, when parameter shift is requested for multiple tapes.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def f(x): tape1 = qml.tape.QuantumScript([qml.RX(x, 0)], [qml.probs(wires=0)]) @@ -440,7 +440,7 @@ def test_single_backward_pass_split_hamiltonian(self): """Tests that the backward pass is one single batch, not a bunch of batches, when parameter shift derivatives are requested for a a tape that the device split into batches.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) H = qml.Hamiltonian([1, 1], [qml.PauliY(0), qml.PauliZ(0)], grouping_type="qwc") @@ -480,7 +480,7 @@ class TestAutogradExecuteIntegration: def test_execution(self, execute_kwargs): """Test execution""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, b): with qml.queuing.AnnotatedQueue() as q1: @@ -508,7 +508,7 @@ def cost(a, b): def test_scalar_jacobian(self, execute_kwargs, tol): """Test scalar jacobian calculation""" a = np.array(0.1, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def cost(a): with qml.queuing.AnnotatedQueue() as q: @@ -548,7 +548,7 @@ def cost(a, b, device): tape = qml.tape.QuantumScript.from_queue(q) return autograd.numpy.hstack(qml.execute([tape], device, **execute_kwargs)[0]) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost(a, b, device=dev) expected = [np.cos(a), -np.cos(a) * np.sin(b)] @@ -570,7 +570,7 @@ def test_tape_no_parameters(self, execute_kwargs, tol): if execute_kwargs["gradient_fn"] == "device": pytest.skip("Adjoint differentiation does not yet support probabilities") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def cost(params): with qml.queuing.AnnotatedQueue() as q1: @@ -614,7 +614,7 @@ def cost(params): @pytest.mark.filterwarnings("ignore:Attempted to compute the gradient") def test_tapes_with_different_return_size(self, execute_kwargs): """Test that tapes wit different can be executed and differentiated.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def cost(params): with qml.queuing.AnnotatedQueue() as q1: @@ -652,7 +652,7 @@ def test_reusing_quantum_tape(self, execute_kwargs, tol): a = np.array(0.1, requires_grad=True) b = np.array(0.2, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -705,7 +705,7 @@ def cost(a, b, c, device): tape = qml.tape.QuantumScript.from_queue(q) return qml.execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = qml.jacobian(cost)(a, b, c, device=dev) # Only two arguments are trainable @@ -728,7 +728,7 @@ def cost(a, b, device): tape = qml.tape.QuantumScript.from_queue(q) return autograd.numpy.hstack(qml.execute([tape], device, **execute_kwargs)[0]) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost(a, b, device=dev) assert res.shape == (2,) @@ -758,7 +758,7 @@ def cost(a, U, device): tape = qml.tape.QuantumScript.from_queue(q) return qml.execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost(a, U, device=dev) assert isinstance(res, np.ndarray) assert np.allclose(res, -np.cos(a), atol=tol, rtol=0) @@ -794,7 +794,7 @@ def cost_fn(a, p, device): a = np.array(0.1, requires_grad=False) p = np.array([0.1, 0.2, 0.3], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) res = cost_fn(a, p, device=dev) expected = np.cos(a) * np.cos(p[1]) * np.sin(p[0]) + np.sin(a) * ( np.cos(p[2]) * np.sin(p[1]) + np.cos(p[0]) * np.cos(p[1]) * np.sin(p[2]) @@ -833,7 +833,7 @@ def cost(x, y, device): tape = qml.tape.QuantumScript.from_queue(q) return autograd.numpy.hstack(qml.execute([tape], device, **execute_kwargs)[0]) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = np.array(0.543, requires_grad=True) y = np.array(-0.654, requires_grad=True) @@ -894,7 +894,7 @@ def cost(x, y, device): tape = qml.tape.QuantumScript.from_queue(q) return autograd.numpy.hstack(qml.execute([tape], device, **execute_kwargs)[0]) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = np.array(0.543, requires_grad=True) y = np.array(-0.654, requires_grad=True) @@ -936,7 +936,7 @@ def cost(device): return qml.execute([tape], device, **execute_kwargs)[0] shots = 10 - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) res = cost(device=dev) assert isinstance(res, tuple) assert len(res) == 2 @@ -1100,7 +1100,7 @@ class TestOverridingShots: def test_changing_shots(self, mocker, tol): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = np.array([0.543, -0.654], requires_grad=True) with qml.queuing.AnnotatedQueue() as q: @@ -1130,7 +1130,7 @@ def test_changing_shots(self, mocker, tol): def test_overriding_shots_with_same_value(self, mocker): """Overriding shots with the same value as the device will have no effect""" - dev = qml.device("default.qubit", wires=2, shots=123) + dev = qml.device("default.qubit.legacy", wires=2, shots=123) a, b = np.array([0.543, -0.654], requires_grad=True) with qml.queuing.AnnotatedQueue() as q: @@ -1161,7 +1161,7 @@ def test_overriding_shots_with_same_value(self, mocker): def test_overriding_device_with_shot_vector(self): """Overriding a device that has a batch of shots set results in original shots being returned after execution""" - dev = qml.device("default.qubit", wires=2, shots=[10, (1, 3), 5]) + dev = qml.device("default.qubit.legacy", wires=2, shots=[10, (1, 3), 5]) assert dev.shots == 18 assert dev._shot_vector == [(10, 1), (1, 3), (5, 1)] @@ -1192,7 +1192,7 @@ def test_gradient_integration(self): """Test that temporarily setting the shots works for gradient computations""" # TODO: Update here when shot vectors are supported - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = np.array([0.543, -0.654], requires_grad=True) def cost_fn(a, b, shots): @@ -1285,7 +1285,7 @@ def test_multiple_hamiltonians_not_trainable(self, cost_fn, execute_kwargs, tol) coeffs1 = np.array([0.1, 0.2, 0.3], requires_grad=False) coeffs2 = np.array([0.7], requires_grad=False) weights = np.array([0.4, 0.5], requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost_fn(weights, coeffs1, coeffs2, dev=dev) expected = self.cost_fn_expected(weights, coeffs1, coeffs2) @@ -1301,7 +1301,7 @@ def test_multiple_hamiltonians_trainable(self, cost_fn, execute_kwargs, tol): 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", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost_fn(weights, coeffs1, coeffs2, dev=dev) expected = self.cost_fn_expected(weights, coeffs1, coeffs2) diff --git a/tests/interfaces/test_autograd_qnode.py b/tests/interfaces/test_autograd_qnode.py index a2d3be61d14..365a5a0898b 100644 --- a/tests/interfaces/test_autograd_qnode.py +++ b/tests/interfaces/test_autograd_qnode.py @@ -22,30 +22,30 @@ from pennylane import qnode qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "backprop", True], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "spsa", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "spsa", False], + ["default.qubit.legacy", "hadamard", False], ] interface_qubit_device_and_diff_method = [ - ["autograd", "default.qubit", "finite-diff", False], - ["autograd", "default.qubit", "parameter-shift", False], - ["autograd", "default.qubit", "backprop", True], - ["autograd", "default.qubit", "adjoint", True], - ["autograd", "default.qubit", "adjoint", False], - ["autograd", "default.qubit", "spsa", False], - ["autograd", "default.qubit", "hadamard", False], - ["auto", "default.qubit", "finite-diff", False], - ["auto", "default.qubit", "parameter-shift", False], - ["auto", "default.qubit", "backprop", True], - ["auto", "default.qubit", "adjoint", True], - ["auto", "default.qubit", "adjoint", False], - ["auto", "default.qubit", "spsa", False], - ["auto", "default.qubit", "hadamard", False], + ["autograd", "default.qubit.legacy", "finite-diff", False], + ["autograd", "default.qubit.legacy", "parameter-shift", False], + ["autograd", "default.qubit.legacy", "backprop", True], + ["autograd", "default.qubit.legacy", "adjoint", True], + ["autograd", "default.qubit.legacy", "adjoint", False], + ["autograd", "default.qubit.legacy", "spsa", False], + ["autograd", "default.qubit.legacy", "hadamard", False], + ["auto", "default.qubit.legacy", "finite-diff", False], + ["auto", "default.qubit.legacy", "parameter-shift", False], + ["auto", "default.qubit.legacy", "backprop", True], + ["auto", "default.qubit.legacy", "adjoint", True], + ["auto", "default.qubit.legacy", "adjoint", False], + ["auto", "default.qubit.legacy", "spsa", False], + ["auto", "default.qubit.legacy", "hadamard", False], ] pytestmark = pytest.mark.autograd @@ -71,7 +71,7 @@ def test_nondiff_param_unwrapping( if diff_method != "parameter-shift": pytest.skip("Test only supports parameter-shift") - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, interface=interface, diff_method=diff_method) def circuit(x, y): @@ -299,7 +299,7 @@ def test_jacobian_options(self, interface, dev_name, diff_method, grad_on_execut a = np.array([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qnode(dev, interface=interface, diff_method=diff_method, **kwargs) def circuit(a): @@ -327,7 +327,7 @@ def test_changing_trainability( a = np.array(0.1, requires_grad=True) b = np.array(0.2, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev, interface=interface, diff_method=diff_method) def circuit(a, b): @@ -551,7 +551,7 @@ class TestShotsIntegration: def test_changing_shots(self, mocker, tol): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = np.array([0.543, -0.654], requires_grad=True) @qnode(dev, diff_method=qml.gradients.param_shift) @@ -583,7 +583,7 @@ def circuit(a, b): def test_gradient_integration(self): """Test that temporarily setting the shots works for gradient computations""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = np.array([0.543, -0.654], requires_grad=True) @qnode(dev, diff_method=qml.gradients.param_shift) @@ -606,7 +606,7 @@ def cost_fn(a, b): def test_update_diff_method(self, mocker): """Test that temporarily setting the shots updates the diff method""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) a, b = np.array([0.543, -0.654], requires_grad=True) spy = mocker.spy(qml, "execute") @@ -928,7 +928,7 @@ def circuit1(a, b, c): qml.CNOT(wires=[1, 2]) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(2)) - dev2 = qml.device("default.qubit", wires=num_wires) + dev2 = qml.device("default.qubit.legacy", wires=num_wires) @qnode(dev2, interface=interface, diff_method=diff_method) def circuit2(data, weights): @@ -1552,7 +1552,7 @@ def circuit(n, a): def test_adjoint_reuse_device_state(mocker): """Tests that the autograd interface reuses the device state for adjoint differentiation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, diff_method="adjoint") def circ(x): @@ -1754,7 +1754,7 @@ class TestSample: def test_backprop_error(self): """Test that sampling in backpropagation grad_on_execution raises an error""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev, diff_method="backprop") def circuit(): @@ -1768,7 +1768,7 @@ def test_sample_dimension(self): """Test that the sample function outputs samples of the right size""" n_sample = 10 - dev = qml.device("default.qubit", wires=2, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_sample) @qnode(dev) def circuit(): @@ -1791,7 +1791,7 @@ def test_sample_combination(self): n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev, diff_method="parameter-shift") def circuit(): @@ -1813,7 +1813,7 @@ def test_single_wire_sample(self): """Test the return type and shape of sampling a single wire""" n_sample = 10 - dev = qml.device("default.qubit", wires=1, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_sample) @qnode(dev) def circuit(): @@ -1831,7 +1831,7 @@ def test_multi_wire_sample_regular_shape(self): where a rectangular array is expected""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev) def circuit(): @@ -2370,7 +2370,7 @@ def cost(x): assert hess.shape == (3, 2, 2) -@pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) +@pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_no_ops(dev_name): """Test that the return value of the QNode matches in the interface even if there are no ops""" diff --git a/tests/interfaces/test_autograd_qnode_shot_vector.py b/tests/interfaces/test_autograd_qnode_shot_vector.py index 06893e389f8..7ad7a4984fc 100644 --- a/tests/interfaces/test_autograd_qnode_shot_vector.py +++ b/tests/interfaces/test_autograd_qnode_shot_vector.py @@ -26,9 +26,9 @@ shots_and_num_copies_hess = [(((5, 1), 10), 2), ((10, (5, 1)), 2)] qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", {"h": 0.05}], - ["default.qubit", "parameter-shift", {}], - ["default.qubit", "spsa", {"h": 0.05, "num_directions": 20}], + ["default.qubit.legacy", "finite-diff", {"h": 0.05}], + ["default.qubit.legacy", "parameter-shift", {}], + ["default.qubit.legacy", "spsa", {"h": 0.05, "num_directions": 20}], ] TOLS = { diff --git a/tests/interfaces/test_jax.py b/tests/interfaces/test_jax.py index b726d810fd5..9f519b733fe 100644 --- a/tests/interfaces/test_jax.py +++ b/tests/interfaces/test_jax.py @@ -35,7 +35,7 @@ def test_jacobian_options(self, mocker): a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -61,7 +61,7 @@ def test_incorrect_grad_on_execution(self): is used with grad_on_execution=True""" a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -86,7 +86,7 @@ def test_unknown_interface(self): """Test that an error is raised if the interface is unknown""" a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -107,7 +107,7 @@ def cost(a, device): def test_grad_on_execution(self, mocker): """Test that grad_on_execution uses the `device.execute_and_gradients` pathway""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) spy = mocker.spy(dev, "execute_and_gradients") def cost(params): @@ -150,7 +150,7 @@ def cost(params): def test_no_grad_on_execution(self, mocker): """Test that no grad on execution uses the `device.batch_execute` and `device.gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy_execute = mocker.spy(qml.devices.DefaultQubit, "batch_execute") spy_gradients = mocker.spy(qml.devices.DefaultQubit, "gradients") @@ -185,7 +185,7 @@ class TestCaching: def test_cache_maxsize(self, mocker): """Test the cachesize property of the cache""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cachesize): @@ -212,7 +212,7 @@ def cost(a, cachesize): def test_custom_cache(self, mocker): """Test the use of a custom cache object""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cache): @@ -238,7 +238,7 @@ def cost(a, cache): def test_custom_cache_multiple(self, mocker): """Test the use of a custom cache object with multiple tapes""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") a = jax.numpy.array(0.1) @@ -274,7 +274,7 @@ def cost(a, b, cache): def test_caching_param_shift(self, tol): """Test that, when using parameter-shift transform, caching produces the optimum number of evaluations.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, cache): with qml.queuing.AnnotatedQueue() as q: @@ -319,7 +319,7 @@ def cost(a, cache): def test_caching_adjoint_backward(self): """Test that caching produces the optimum number of adjoint evaluations when no grad on execution.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -375,7 +375,7 @@ class TestJaxExecuteIntegration: def test_execution(self, execute_kwargs): """Test execution""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, b): with qml.queuing.AnnotatedQueue() as q1: @@ -404,7 +404,7 @@ def cost(a, b): def test_scalar_jacobian(self, execute_kwargs, tol): """Test scalar jacobian calculation""" a = jax.numpy.array(0.1) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def cost(a): with qml.queuing.AnnotatedQueue() as q: @@ -436,7 +436,7 @@ def test_reusing_quantum_tape(self, execute_kwargs, tol): a = jax.numpy.array(0.1) b = jax.numpy.array(0.2) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -477,7 +477,7 @@ def cost(a, b): def test_grad_with_different_grad_on_execution(self, execute_kwargs): """Test jax grad for adjoint diff method with different execution kwargs.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) expected_results = jax.numpy.array([-0.3875172, -0.18884787, -0.38355705]) @@ -513,14 +513,14 @@ def cost(a, b, c, device): return execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = jax.grad(cost, argnums=(0, 1, 2))(a, b, c, device=dev) assert len(res) == 3 def test_classical_processing_multiple_tapes(self, execute_kwargs): """Test classical processing within the quantum tape for multiple tapes""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.3, 0.2]) def cost_fn(x): @@ -546,7 +546,7 @@ def cost_fn(x): def test_multiple_tapes_output(self, execute_kwargs): """Test the output types for the execution of multiple quantum tapes""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.3, 0.2]) def cost_fn(x): @@ -588,7 +588,7 @@ def cost(a, U, device): tape.trainable_params = [0] return execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost(a, U, device=dev) assert np.allclose(res, -np.cos(a), atol=tol, rtol=0) @@ -622,7 +622,7 @@ def cost_fn(a, p, device): a = jax.numpy.array(0.1) p = jax.numpy.array([0.1, 0.2, 0.3]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) res = cost_fn(a, p, device=dev) expected = np.cos(a) * np.cos(p[1]) * np.sin(p[0]) + np.sin(a) * ( np.cos(p[2]) * np.sin(p[1]) + np.cos(p[0]) * np.cos(p[1]) * np.sin(p[2]) @@ -646,7 +646,7 @@ def cost_fn(a, p, device): def test_independent_expval(self, execute_kwargs): """Tests computing an expectation value that is independent of trainable parameters.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -672,7 +672,7 @@ class TestVectorValued: def test_multiple_expvals(self, execute_kwargs): """Tests computing multiple expectation values in a tape.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -701,7 +701,7 @@ def cost(a, cache): def test_multiple_expvals_single_par(self, execute_kwargs): """Tests computing multiple expectation values in a tape with a single trainable parameter.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1]) def cost(a, cache): @@ -727,7 +727,7 @@ def cost(a, cache): def test_multi_tape_fwd(self, execute_kwargs): """Test the forward evaluation of a cost function that uses the output of multiple tapes that be vector-valued.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.3, 0.2]) def cost_fn(x): @@ -773,7 +773,7 @@ def cost(x, y, device, interface, ek): tape2 = qml.tape.QuantumScript.from_queue(q2) return qml.execute([tape1, tape2], device, **ek, interface=interface) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = jax.numpy.array(0.543) y = jax.numpy.array(-0.654) @@ -830,7 +830,7 @@ def cost(x, y, device, interface, ek): tape2 = qml.tape.QuantumScript.from_queue(q2) return qml.execute([tape1, tape2], device, **ek, interface=interface) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = jax.numpy.array(0.543) y = jax.numpy.array(-0.654) diff --git a/tests/interfaces/test_jax_jit.py b/tests/interfaces/test_jax_jit.py index a9f9e494757..5e375f8e912 100644 --- a/tests/interfaces/test_jax_jit.py +++ b/tests/interfaces/test_jax_jit.py @@ -36,7 +36,7 @@ def test_jacobian_options(self, mocker): a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -63,7 +63,7 @@ def test_incorrect_gradients_on_execution(self): is used with grad_on_execution=True""" a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -89,7 +89,7 @@ def test_unknown_interface(self): """Test that an error is raised if the interface is unknown""" a = jax.numpy.array([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, device): with qml.queuing.AnnotatedQueue() as q: @@ -111,7 +111,7 @@ def cost(a, device): def test_grad_on_execution(self, mocker): """Test that grad on execution uses the `device.execute_and_gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(dev, "execute_and_gradients") def cost(a): @@ -141,7 +141,7 @@ def cost(a): def test_no_gradients_on_execution(self, mocker): """Test that no grad on execution uses the `device.batch_execute` and `device.gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy_execute = mocker.spy(qml.devices.DefaultQubit, "batch_execute") spy_gradients = mocker.spy(qml.devices.DefaultQubit, "gradients") @@ -177,7 +177,7 @@ class TestCaching: def test_cache_maxsize(self, mocker): """Test the cachesize property of the cache""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cachesize): @@ -205,7 +205,7 @@ def cost(a, cachesize): def test_custom_cache(self, mocker): """Test the use of a custom cache object""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cache): @@ -232,7 +232,7 @@ def cost(a, cache): def test_custom_cache_multiple(self, mocker): """Test the use of a custom cache object with multiple tapes""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") a = jax.numpy.array(0.1) @@ -270,7 +270,7 @@ def cost(a, b, cache): def test_caching_param_shift(self, tol): """Test that, when using parameter-shift transform, caching produces the optimum number of evaluations.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, cache): with qml.queuing.AnnotatedQueue() as q: @@ -316,7 +316,7 @@ def cost(a, cache): def test_caching_adjoint_backward(self): """Test that caching produces the optimum number of adjoint evaluations when mode=backward""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -373,7 +373,7 @@ class TestJaxExecuteIntegration: def test_execution(self, execute_kwargs): """Test execution""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, b): with qml.queuing.AnnotatedQueue() as q1: @@ -403,7 +403,7 @@ def cost(a, b): def test_scalar_jacobian(self, execute_kwargs, tol): """Test scalar jacobian calculation""" a = jax.numpy.array(0.1) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def cost(a): with qml.queuing.AnnotatedQueue() as q: @@ -436,7 +436,7 @@ def test_reusing_quantum_tape(self, execute_kwargs, tol): a = jax.numpy.array(0.1) b = jax.numpy.array(0.2) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -478,7 +478,7 @@ def cost(a, b): def test_grad_with_backward_mode(self, execute_kwargs): """Test jax grad for adjoint diff method in backward mode""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) expected_results = jax.numpy.array([-0.3875172, -0.18884787, -0.38355705]) @@ -517,14 +517,14 @@ def cost(a, b, c, device): return execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = jax.jit(jax.grad(cost, argnums=(0, 1, 2)), static_argnums=3)(a, b, c, device=dev) assert len(res) == 3 def test_classical_processing_multiple_tapes(self, execute_kwargs): """Test classical processing within the quantum tape for multiple tapes""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.3, 0.2]) def cost_fn(x): @@ -552,7 +552,7 @@ def cost_fn(x): def test_multiple_tapes_output(self, execute_kwargs): """Test the output types for the execution of multiple quantum tapes""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.3, 0.2]) def cost_fn(x): @@ -596,7 +596,7 @@ def cost(a, U, device): tape.trainable_params = [0] return execute([tape], device, **execute_kwargs)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = jax.jit(cost, static_argnums=2)(a, U, device=dev) assert np.allclose(res, -np.cos(a), atol=tol, rtol=0) @@ -627,7 +627,7 @@ def cost_fn(a, p, device): a = jax.numpy.array(0.1) p = jax.numpy.array([0.1, 0.2, 0.3]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) res = jax.jit(cost_fn, static_argnums=2)(a, p, device=dev) expected = np.cos(a) * np.cos(p[1]) * np.sin(p[0]) + np.sin(a) * ( np.cos(p[2]) * np.sin(p[1]) + np.cos(p[0]) * np.cos(p[1]) * np.sin(p[2]) @@ -651,7 +651,7 @@ def cost_fn(a, p, device): def test_independent_expval(self, execute_kwargs): """Tests computing an expectation value that is independent of trainable parameters.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -687,7 +687,7 @@ def test_shapes(self, execute_kwargs, ret_type, shape, expected_type): if adjoint: pytest.skip("The adjoint diff method doesn't support probabilities.") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -715,7 +715,7 @@ def cost(a, cache): def test_independent_expval(self, execute_kwargs): """Tests computing an expectation value that is independent of trainable parameters.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -747,7 +747,7 @@ def cost(a, cache): def test_vector_valued_qnode(self, execute_kwargs, ret, out_dim, expected_type): """Tests the shape of vector-valued QNode results.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) grad_meth = ( execute_kwargs["gradient_kwargs"]["method"] @@ -786,7 +786,7 @@ def cost(a, cache): def test_qnode_sample(self, execute_kwargs): """Tests computing multiple expectation values in a tape.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) params = jax.numpy.array([0.1, 0.2, 0.3]) grad_meth = ( @@ -814,7 +814,7 @@ def cost(a, cache): def test_multiple_expvals_grad(self, execute_kwargs): """Tests computing multiple expectation values in a tape.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jax.numpy.array([0.1, 0.2, 0.3]) def cost(a, cache): @@ -861,7 +861,7 @@ def cost(x, y, device, interface, ek): return qml.execute([tape1, tape2], device, **ek, interface=interface)[0] - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = jax.numpy.array(0.543) y = jax.numpy.array(-0.654) diff --git a/tests/interfaces/test_jax_jit_qnode.py b/tests/interfaces/test_jax_jit_qnode.py index 6e600a63aa9..7f0fd26a9da 100644 --- a/tests/interfaces/test_jax_jit_qnode.py +++ b/tests/interfaces/test_jax_jit_qnode.py @@ -20,13 +20,13 @@ from pennylane import qnode qubit_device_and_diff_method = [ - ["default.qubit", "backprop", True], - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "spsa", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "spsa", False], + ["default.qubit.legacy", "hadamard", False], ] interface_and_qubit_device_and_diff_method = [ ["auto"] + inner_list for inner_list in qubit_device_and_diff_method @@ -809,7 +809,7 @@ def circuit(x): def test_changing_shots(self, interface, mocker, tol): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = jax.numpy.array([0.543, -0.654]) @qnode(dev, diff_method=qml.gradients.param_shift, interface=interface) @@ -840,7 +840,7 @@ def circuit(a, b): def test_gradient_integration(self, interface): """Test that temporarily setting the shots works for gradient computations""" - dev = qml.device("default.qubit", wires=2, shots=1) + dev = qml.device("default.qubit.legacy", wires=2, shots=1) a, b = jax.numpy.array([0.543, -0.654]) @qnode(dev, diff_method=qml.gradients.param_shift, interface=interface) @@ -860,7 +860,7 @@ def cost_fn(a, b): def test_update_diff_method(self, mocker, interface): """Test that temporarily setting the shots updates the diff method""" # pylint: disable=unused-argument - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) a, b = jax.numpy.array([0.543, -0.654]) spy = mocker.spy(qml, "execute") @@ -1481,7 +1481,7 @@ def circuit(n, a): @pytest.mark.parametrize("interface", ["auto", "jax-jit"]) def test_adjoint_reuse_device_state(mocker, interface): """Tests that the jax interface reuses the device state for adjoint differentiation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, interface=interface, diff_method="adjoint") def circ(x): diff --git a/tests/interfaces/test_jax_qnode.py b/tests/interfaces/test_jax_qnode.py index b52deaac9ec..5a641db0959 100644 --- a/tests/interfaces/test_jax_qnode.py +++ b/tests/interfaces/test_jax_qnode.py @@ -21,13 +21,13 @@ from pennylane.tape import QuantumScript qubit_device_and_diff_method = [ - ["default.qubit", "backprop", True], - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "spsa", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "spsa", False], + ["default.qubit.legacy", "hadamard", False], ] interface_and_qubit_device_and_diff_method = [ @@ -767,7 +767,7 @@ def circuit(x): def test_changing_shots(self, interface, mocker, tol): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = jax.numpy.array([0.543, -0.654]) @qnode(dev, diff_method=qml.gradients.param_shift, interface=interface) @@ -798,7 +798,7 @@ def circuit(a, b): def test_gradient_integration(self, interface): """Test that temporarily setting the shots works for gradient computations""" - dev = qml.device("default.qubit", wires=2, shots=1) + dev = qml.device("default.qubit.legacy", wires=2, shots=1) a, b = jax.numpy.array([0.543, -0.654]) @qnode(dev, diff_method=qml.gradients.param_shift, interface=interface) @@ -817,7 +817,7 @@ def cost_fn(a, b): def test_update_diff_method(self, mocker, interface): """Test that temporarily setting the shots updates the diff method""" # pylint: disable=unused-argument - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) a, b = jax.numpy.array([0.543, -0.654]) spy = mocker.spy(qml, "execute") @@ -1417,7 +1417,7 @@ def circuit(n, a): @pytest.mark.parametrize("interface", ["auto", "jax", "jax-python"]) def test_adjoint_reuse_device_state(mocker, interface): """Tests that the jax interface reuses the device state for adjoint differentiation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qnode(dev, interface=interface, diff_method="adjoint") def circ(x): @@ -2512,7 +2512,7 @@ def circuit(x): assert hess[1].shape == (2, 2, 2) -@pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) +@pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_no_ops(dev_name): """Test that the return value of the QNode matches in the interface even if there are no ops""" diff --git a/tests/interfaces/test_jax_qnode_shot_vector.py b/tests/interfaces/test_jax_qnode_shot_vector.py index 23b80f617db..2e8f7781db5 100644 --- a/tests/interfaces/test_jax_qnode_shot_vector.py +++ b/tests/interfaces/test_jax_qnode_shot_vector.py @@ -29,9 +29,9 @@ all_shots = [(1, 20, 100), (1, (20, 1), 100), (1, (5, 4), 100)] qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", {"h": 10e-2}], - ["default.qubit", "parameter-shift", {}], - ["default.qubit", "spsa", {"h": 10e-2, "num_directions": 20}], + ["default.qubit.legacy", "finite-diff", {"h": 10e-2}], + ["default.qubit.legacy", "parameter-shift", {}], + ["default.qubit.legacy", "spsa", {"h": 10e-2, "num_directions": 20}], ] interface_and_qubit_device_and_diff_method = [ @@ -773,7 +773,7 @@ class TestReturnShotVectorsDevice: def test_jac_adjoint_fwd_error(self, shots): """Test that an error is raised for adjoint forward.""" - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) with pytest.warns( UserWarning, match="Requested adjoint differentiation to be computed with finite shots." @@ -796,7 +796,7 @@ def circuit(a): def test_jac_adjoint_bwd_error(self, shots): """Test that an error is raised for adjoint backward.""" - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) with pytest.warns( UserWarning, match="Requested adjoint differentiation to be computed with finite shots." @@ -818,8 +818,8 @@ def circuit(a): qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", {"h": 10e-2}], - ["default.qubit", "parameter-shift", {}], + ["default.qubit.legacy", "finite-diff", {"h": 10e-2}], + ["default.qubit.legacy", "parameter-shift", {}], ] shots_large = [(1000000, 900000, 800000), (1000000, (900000, 2))] diff --git a/tests/interfaces/test_tensorflow.py b/tests/interfaces/test_tensorflow.py index f3559d88029..019fa4f27ef 100644 --- a/tests/interfaces/test_tensorflow.py +++ b/tests/interfaces/test_tensorflow.py @@ -34,7 +34,7 @@ def test_jacobian_options(self, mocker): a = tf.Variable([0.1, 0.2], dtype=tf.float64) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -61,7 +61,7 @@ def test_incorrect_grad_on_execution(self): is used with grad_on_execution""" a = tf.Variable([0.1, 0.2]) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with tf.GradientTape(): with qml.queuing.AnnotatedQueue() as q: @@ -77,7 +77,7 @@ def test_incorrect_grad_on_execution(self): def test_grad_on_execution(self, mocker): """Test that grad on execution uses the `device.execute_and_gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = tf.Variable([0.1, 0.2]) spy = mocker.spy(dev, "execute_and_gradients") @@ -102,7 +102,7 @@ def test_grad_on_execution(self, mocker): def test_no_grad_execution(self, mocker): """Test that no grad on execution uses the `device.batch_execute` and `device.gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy_execute = mocker.spy(qml.devices.DefaultQubit, "batch_execute") spy_gradients = mocker.spy(qml.devices.DefaultQubit, "gradients") a = tf.Variable([0.1, 0.2]) @@ -136,7 +136,7 @@ class TestCaching: def test_cache_maxsize(self, mocker): """Test the cachesize property of the cache""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") a = tf.Variable([0.1, 0.2]) @@ -158,7 +158,7 @@ def test_cache_maxsize(self, mocker): def test_custom_cache(self, mocker): """Test the use of a custom cache object""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") a = tf.Variable([0.1, 0.2]) custom_cache = {} @@ -188,7 +188,7 @@ def test_custom_cache(self, mocker): def test_caching_param_shift(self): """Test that, when using parameter-shift transform, caching reduces the number of evaluations to their optimum.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = tf.Variable([0.1, 0.2], dtype=tf.float64) def cost(a, cache): @@ -228,7 +228,7 @@ def test_caching_param_shift_hessian(self, num_params, tol): """Test that, when using parameter-shift transform, caching reduces the number of evaluations to their optimum when computing Hessians.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = tf.Variable(np.arange(1, num_params + 1) / 10, dtype=tf.float64) N = params.shape[0] @@ -324,7 +324,7 @@ class TestTensorFlowExecuteIntegration: def test_execution(self, execute_kwargs): """Test execution""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = tf.Variable(0.1) b = tf.Variable(0.2) @@ -352,7 +352,7 @@ def test_execution(self, execute_kwargs): def test_scalar_jacobian(self, execute_kwargs, tol): """Test scalar jacobian calculation""" a = tf.Variable(0.1, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -381,7 +381,7 @@ def test_jacobian(self, execute_kwargs, tol): """Test jacobian calculation""" a = tf.Variable(0.1, dtype=tf.float64) b = tf.Variable(0.2, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -407,7 +407,7 @@ def test_jacobian(self, execute_kwargs, tol): def test_tape_no_parameters(self, execute_kwargs, tol): """Test that a tape with no parameters is correctly ignored during the gradient computation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) params = tf.Variable([0.1, 0.2], dtype=tf.float64) x, y = 1.0 * params @@ -443,7 +443,7 @@ def test_reusing_quantum_tape(self, execute_kwargs, tol): a = tf.Variable(0.1, dtype=tf.float64) b = tf.Variable(0.2, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -486,7 +486,7 @@ def test_reusing_pre_constructed_quantum_tape(self, execute_kwargs, tol): a = tf.Variable(0.1, dtype=tf.float64) b = tf.Variable(0.2, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -528,7 +528,7 @@ def test_classical_processing(self, execute_kwargs): b = tf.constant(0.2, dtype=tf.float64) c = tf.Variable(0.3, dtype=tf.float64) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -550,7 +550,7 @@ def test_classical_processing(self, execute_kwargs): def test_no_trainable_parameters(self, execute_kwargs): """Test evaluation and Jacobian if there are no trainable parameters""" b = tf.constant(0.2, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -576,7 +576,7 @@ def test_matrix_parameter(self, execute_kwargs, U, tol): with a matrix parameter""" a = tf.Variable(0.1, dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as t: with qml.queuing.AnnotatedQueue() as q: @@ -606,7 +606,7 @@ def decomposition(self): qml.PhaseShift(phi + lam, wires=wires), ] - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = np.array(0.1) p = tf.Variable([0.1, 0.2, 0.3], dtype=tf.float64) @@ -644,7 +644,7 @@ def test_probability_differentiation(self, execute_kwargs, tol): if execute_kwargs["gradient_fn"] == "device": pytest.skip("Adjoint differentiation does not yet support probabilities") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -689,7 +689,7 @@ def test_ragged_differentiation(self, execute_kwargs, tol): if execute_kwargs["gradient_fn"] == "device": pytest.skip("Adjoint differentiation does not yet support probabilities") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -727,7 +727,7 @@ def test_sampling(self, execute_kwargs): ): pytest.skip("Adjoint differentiation does not support samples") - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) with tf.GradientTape(): with qml.queuing.AnnotatedQueue() as q: @@ -855,7 +855,7 @@ def test_hessian_vector_valued(self, tol, interface): def test_adjoint_hessian(self, interface): """Since the adjoint hessian is not a differentiable transform, higher-order derivatives are not supported.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = tf.Variable([0.543, -0.654]) with tf.GradientTape() as t2: @@ -994,7 +994,7 @@ def test_multiple_hamiltonians_not_trainable(self, cost_fn, execute_kwargs, tol) weights = tf.Variable([0.4, 0.5], dtype=tf.float64) coeffs1 = tf.constant([0.1, 0.2, 0.3], dtype=tf.float64) coeffs2 = tf.constant([0.7], dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as tape: res = cost_fn(weights, coeffs1, coeffs2, dev=dev) @@ -1013,7 +1013,7 @@ def test_multiple_hamiltonians_trainable(self, cost_fn, execute_kwargs, tol): weights = tf.Variable([0.4, 0.5], dtype=tf.float64) coeffs1 = tf.Variable([0.1, 0.2, 0.3], dtype=tf.float64) coeffs2 = tf.Variable([0.7], dtype=tf.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with tf.GradientTape() as tape: res = cost_fn(weights, coeffs1, coeffs2, dev=dev) diff --git a/tests/interfaces/test_tensorflow_autograph_qnode_shot_vector.py b/tests/interfaces/test_tensorflow_autograph_qnode_shot_vector.py index a31aeed16b2..6dd465672b7 100644 --- a/tests/interfaces/test_tensorflow_autograph_qnode_shot_vector.py +++ b/tests/interfaces/test_tensorflow_autograph_qnode_shot_vector.py @@ -27,9 +27,9 @@ shots_and_num_copies_hess = [((10, (5, 1)), 2)] qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", {"h": 10e-2}], - ["default.qubit", "parameter-shift", {}], - ["default.qubit", "spsa", {"h": 10e-2, "num_directions": 20}], + ["default.qubit.legacy", "finite-diff", {"h": 10e-2}], + ["default.qubit.legacy", "parameter-shift", {}], + ["default.qubit.legacy", "spsa", {"h": 10e-2, "num_directions": 20}], ] TOLS = { diff --git a/tests/interfaces/test_tensorflow_qnode.py b/tests/interfaces/test_tensorflow_qnode.py index 8e7bc6ea451..52ffb398c11 100644 --- a/tests/interfaces/test_tensorflow_qnode.py +++ b/tests/interfaces/test_tensorflow_qnode.py @@ -24,13 +24,13 @@ qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "backprop", True], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "spsa", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "spsa", False], + ["default.qubit.legacy", "hadamard", False], ] TOL_FOR_SPSA = 1.0 @@ -532,7 +532,7 @@ class TestShotsIntegration: def test_changing_shots(self, mocker, tol, interface): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = [0.543, -0.654] weights = tf.Variable([a, b], dtype=tf.float64) @@ -567,7 +567,7 @@ def test_gradient_integration(self, interface): """Test that temporarily setting the shots works for gradient computations""" # pylint: disable=unexpected-keyword-arg - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = [0.543, -0.654] weights = tf.Variable([a, b], dtype=tf.float64) @@ -593,7 +593,7 @@ def test_multiple_gradient_integration(self, tol, interface): """Test that temporarily setting the shots works for gradient computations, even if the QNode has been re-evaluated with a different number of shots in the meantime.""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = [0.543, -0.654] weights = tf.Variable([a, b], dtype=tf.float64) @@ -618,7 +618,7 @@ def circuit(weights): def test_update_diff_method(self, mocker, interface): """Test that temporarily setting the shots updates the diff method""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) weights = tf.Variable([0.543, -0.654], dtype=tf.float64) spy = mocker.spy(qml, "execute") @@ -654,7 +654,7 @@ class TestAdjoint: def test_reuse_state(self, mocker, interface): """Tests that the TF interface reuses the device state for adjoint differentiation""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev, diff_method="adjoint", interface=interface) def circ(x): @@ -681,7 +681,7 @@ def circ(x): def test_resuse_state_multiple_evals(self, mocker, tol, interface): """Tests that the TF interface reuses the device state for adjoint differentiation, even where there are intermediate evaluations.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x_val = 0.543 y_val = -0.654 @@ -1516,7 +1516,7 @@ class TestSample: def test_sample_dimension(self): """Test sampling works as expected""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) @qnode(dev, diff_method="parameter-shift", interface="tf") def circuit(): @@ -1536,7 +1536,7 @@ def circuit(): def test_sampling_expval(self): """Test sampling works as expected if combined with expectation values""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) @qnode(dev, diff_method="parameter-shift", interface="tf") def circuit(): @@ -1557,7 +1557,7 @@ def test_sample_combination(self): """Test the output of combining expval, var and sample""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="tf") def circuit(): @@ -1582,7 +1582,7 @@ def test_single_wire_sample(self): """Test the return type and shape of sampling a single wire""" n_sample = 10 - dev = qml.device("default.qubit", wires=1, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="tf") def circuit(): @@ -1600,7 +1600,7 @@ def test_multi_wire_sample_regular_shape(self): where a rectangular array is expected""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="tf") def circuit(): @@ -1616,7 +1616,7 @@ def circuit(): def test_counts(self): """Test counts works as expected for TF""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) @qnode(dev, interface="tf") def circuit(): @@ -1654,7 +1654,7 @@ class TestAutograph: def test_autograph_gradients(self, decorator, interface, tol): """Test that a parameter-shift QNode can be compiled using @tf.function, and differentiated""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -1680,7 +1680,7 @@ def circuit(x, y): def test_autograph_jacobian(self, decorator, interface, tol): """Test that a parameter-shift vector-valued QNode can be compiled using @tf.function, and differentiated""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -1723,7 +1723,7 @@ def circuit(x, y): def test_autograph_adjoint_single_param(self, grad_on_execution, decorator, interface, tol): """Test that a parameter-shift QNode can be compiled using @tf.function, and differentiated to second order""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @decorator @qnode(dev, diff_method="adjoint", interface=interface, grad_on_execution=grad_on_execution) @@ -1747,7 +1747,7 @@ def circuit(x): def test_autograph_adjoint_multi_params(self, grad_on_execution, decorator, interface, tol): """Test that a parameter-shift QNode can be compiled using @tf.function, and differentiated to second order""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @decorator @qnode(dev, diff_method="adjoint", interface=interface, grad_on_execution=grad_on_execution) @@ -1772,7 +1772,7 @@ def circuit(x): def test_autograph_ragged_differentiation(self, decorator, interface, tol): """Tests correct output shape and evaluation for a tape with prob and expval outputs""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -1810,7 +1810,7 @@ def circuit(x, y): def test_autograph_hessian(self, decorator, interface, tol): """Test that a parameter-shift QNode can be compiled using @tf.function, and differentiated to second order""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = tf.Variable(0.543, dtype=tf.float64) b = tf.Variable(-0.654, dtype=tf.float64) @@ -1844,7 +1844,7 @@ def circuit(x, y): def test_autograph_state(self, decorator, interface, tol): """Test that a parameter-shift QNode returning a state can be compiled using @tf.function""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x = tf.Variable(0.543, dtype=tf.float64) y = tf.Variable(-0.654, dtype=tf.float64) @@ -1867,7 +1867,7 @@ def circuit(x, y): def test_autograph_dimension(self, decorator, interface): """Test sampling works as expected""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) @decorator @qnode(dev, diff_method="parameter-shift", interface=interface) @@ -2541,7 +2541,7 @@ def circuit(x): assert hess.shape == (3, 2, 2) -@pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) +@pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_no_ops(dev_name): """Test that the return value of the QNode matches in the interface even if there are no ops""" diff --git a/tests/interfaces/test_tensorflow_qnode_shot_vector.py b/tests/interfaces/test_tensorflow_qnode_shot_vector.py index 882bd89bb6c..113e4f04412 100644 --- a/tests/interfaces/test_tensorflow_qnode_shot_vector.py +++ b/tests/interfaces/test_tensorflow_qnode_shot_vector.py @@ -27,9 +27,9 @@ shots_and_num_copies_hess = [((10, (5, 1)), 2)] qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", {"h": 10e-2}], - ["default.qubit", "parameter-shift", {}], - ["default.qubit", "spsa", {"h": 10e-2, "num_directions": 20}], + ["default.qubit.legacy", "finite-diff", {"h": 10e-2}], + ["default.qubit.legacy", "parameter-shift", {}], + ["default.qubit.legacy", "spsa", {"h": 10e-2, "num_directions": 20}], ] TOLS = { diff --git a/tests/interfaces/test_torch.py b/tests/interfaces/test_torch.py index 84a0a08b7a7..5a2a0a93f84 100644 --- a/tests/interfaces/test_torch.py +++ b/tests/interfaces/test_torch.py @@ -36,7 +36,7 @@ def test_jacobian_options(self, interface, mocker): a = torch.tensor([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with qml.queuing.AnnotatedQueue() as q: qml.RY(a[0], wires=0) @@ -63,7 +63,7 @@ def test_incorrect_grad_on_execution(self, interface): is used with grad_on_execution=True""" a = torch.tensor([0.1, 0.2], requires_grad=True) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with qml.queuing.AnnotatedQueue() as q: qml.RY(a[0], wires=0) @@ -82,7 +82,7 @@ def test_incorrect_grad_on_execution(self, interface): def test_grad_on_execution_reuse_state(self, interface, mocker): """Test that grad_on_execution uses the `device.execute_and_gradients` pathway while reusing the quantum state.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(dev, "execute_and_gradients") a = torch.tensor([0.1, 0.2], requires_grad=True) @@ -108,7 +108,7 @@ def test_grad_on_execution_reuse_state(self, interface, mocker): def test_grad_on_execution(self, interface, mocker): """Test that grad on execution uses the `device.execute_and_gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(dev, "execute_and_gradients") a = torch.tensor([0.1, 0.2], requires_grad=True) @@ -134,7 +134,7 @@ def test_grad_on_execution(self, interface, mocker): def test_no_grad_on_execution(self, interface, mocker): """Test that no grad on execution uses the `device.batch_execute` and `device.gradients` pathway""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy_execute = mocker.spy(qml.devices.DefaultQubit, "batch_execute") spy_gradients = mocker.spy(qml.devices.DefaultQubit, "gradients") @@ -169,7 +169,7 @@ class TestCaching: def test_cache_maxsize(self, mocker): """Test the cachesize property of the cache""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cachesize): @@ -195,7 +195,7 @@ def cost(a, cachesize): def test_custom_cache(self, mocker): """Test the use of a custom cache object""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.interfaces, "cache_execute") def cost(a, cache): @@ -221,7 +221,7 @@ def cost(a, cache): def test_caching_param_shift(self): """Test that, with the parameter-shift transform, Torch always uses the optimum number of evals when computing the Jacobian.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def cost(a, cache): with qml.queuing.AnnotatedQueue() as q: @@ -252,7 +252,7 @@ def test_caching_param_shift_hessian(self, num_params, tol): """Test that, with the parameter-shift transform, caching reduces the number of evaluations to their optimum when computing Hessians.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = torch.tensor(np.arange(1, num_params + 1) / 10, requires_grad=True) N = len(params) @@ -309,7 +309,7 @@ def cost(x, cache): def test_caching_adjoint_no_grad_on_execution(self): """Test that caching reduces the number of adjoint evaluations when grad_on_execution=False""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = torch.tensor([0.1, 0.2, 0.3]) def cost(a, cache): @@ -402,7 +402,7 @@ class TestTorchExecuteIntegration: def test_execution(self, torch_device, execute_kwargs): """Test that the execute function produces results with the expected shapes""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = torch.tensor(0.1, requires_grad=True, device=torch_device) b = torch.tensor(0.2, requires_grad=False, device=torch_device) @@ -430,7 +430,7 @@ def test_execution(self, torch_device, execute_kwargs): def test_scalar_jacobian(self, torch_device, execute_kwargs, tol): """Test scalar jacobian calculation by comparing two types of pipelines""" a = torch.tensor(0.1, requires_grad=True, dtype=torch.float64, device=torch_device) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -463,7 +463,7 @@ def test_jacobian(self, torch_device, execute_kwargs, tol): a = torch.tensor(a_val, requires_grad=True, device=torch_device) b = torch.tensor(b_val, requires_grad=True, device=torch_device) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RZ(torch.tensor(0.543, device=torch_device), wires=0) @@ -506,7 +506,7 @@ def test_jacobian(self, torch_device, execute_kwargs, tol): def test_tape_no_parameters(self, torch_device, execute_kwargs, tol): """Test that a tape with no parameters is correctly ignored during the gradient computation""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) params = torch.tensor([0.1, 0.2], requires_grad=True, device=torch_device) x, y = params.detach() @@ -549,7 +549,7 @@ def test_reusing_quantum_tape(self, torch_device, execute_kwargs, tol): a = torch.tensor(0.1, requires_grad=True, device=torch_device) b = torch.tensor(0.2, requires_grad=True, device=torch_device) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(a, wires=0) @@ -602,7 +602,7 @@ def test_classical_processing(self, torch_device, execute_kwargs, tol): p_val = [0.1, 0.2] params = torch.tensor(p_val, requires_grad=True, device=torch_device) - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) with qml.queuing.AnnotatedQueue() as q: qml.RY(params[0] * params[1], wires=0) @@ -637,7 +637,7 @@ def test_classical_processing(self, torch_device, execute_kwargs, tol): def test_no_trainable_parameters(self, torch_device, execute_kwargs): """Test evaluation and Jacobian if there are no trainable parameters""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.RY(0.2, wires=0) @@ -684,7 +684,7 @@ def test_matrix_parameter(self, torch_device, U, execute_kwargs, tol): if isinstance(U, torch.Tensor) and torch_device is not None: U = U.to(torch_device) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) with qml.queuing.AnnotatedQueue() as q: qml.QubitUnitary(U, wires=0) @@ -716,7 +716,7 @@ def decomposition(self): qml.PhaseShift(phi + lam, wires=wires), ] - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) a = np.array(0.1) p_val = [0.1, 0.2, 0.3] p = torch.tensor(p_val, requires_grad=True, device=torch_device) @@ -768,7 +768,7 @@ def test_probability_differentiation(self, torch_device, execute_kwargs, tol): if execute_kwargs["gradient_fn"] == "device": pytest.skip("Adjoint differentiation does not yet support probabilities") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x_val = 0.543 y_val = -0.654 x = torch.tensor(x_val, requires_grad=True, device=torch_device) @@ -835,7 +835,7 @@ def test_ragged_differentiation(self, torch_device, execute_kwargs, tol): if execute_kwargs["gradient_fn"] == "device": pytest.skip("Adjoint differentiation does not yet support probabilities") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x_val = 0.543 y_val = -0.654 x = torch.tensor(x_val, requires_grad=True, device=torch_device) @@ -908,7 +908,7 @@ def test_sampling(self, torch_device, execute_kwargs): if execute_kwargs["interface"] == "auto": pytest.skip("Can't detect interface without a parametrized gate in the tape") - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) with qml.queuing.AnnotatedQueue() as q: qml.Hadamard(wires=[0]) @@ -940,7 +940,7 @@ def test_sampling_expval(self, torch_device, execute_kwargs): if execute_kwargs["interface"] == "auto": pytest.skip("Can't detect interface without a parametrized gate in the tape") - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) with qml.queuing.AnnotatedQueue() as q: qml.Hadamard(wires=[0]) @@ -968,7 +968,7 @@ def test_sampling_gradient_error(self, torch_device, execute_kwargs): ): pytest.skip("Adjoint differentiation does not support samples") - dev = qml.device("default.qubit", wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) x = torch.tensor(0.65, requires_grad=True) @@ -991,7 +991,7 @@ def test_repeated_application_after_expand(self, torch_device, execute_kwargs): tape expansions""" # pylint: disable=unused-argument n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) weights = torch.ones((3,)) @@ -1021,7 +1021,7 @@ def test_parameter_shift_hessian(self, torch_device, params, tol): """Tests that the output of the parameter-shift transform can be differentiated using torch, yielding second derivatives.""" # pylint: disable=unused-argument - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = torch.tensor([0.543, -0.654], requires_grad=True, dtype=torch.float64) def cost_fn(x): @@ -1068,7 +1068,7 @@ def cost_fn(x): def test_hessian_vector_valued(self, torch_device, tol): """Test hessian calculation of a vector valued tape""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) def circuit(x): with qml.queuing.AnnotatedQueue() as q: @@ -1135,7 +1135,7 @@ def circuit(x): def test_adjoint_hessian(self, torch_device, tol): """Since the adjoint hessian is not a differentiable transform, higher-order derivatives are not supported.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = torch.tensor( [0.543, -0.654], requires_grad=True, dtype=torch.float64, device=torch_device ) @@ -1164,7 +1164,7 @@ def cost_fn(x): def test_max_diff(self, torch_device, tol): """Test that setting the max_diff parameter blocks higher-order derivatives""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = torch.tensor([0.543, -0.654], requires_grad=True, dtype=torch.float64) def cost_fn(x): @@ -1275,7 +1275,7 @@ def test_multiple_hamiltonians_not_trainable(self, cost_fn, execute_kwargs, tol) coeffs1 = torch.tensor([0.1, 0.2, 0.3], requires_grad=False, dtype=torch.float64) coeffs2 = torch.tensor([0.7], requires_grad=False, dtype=torch.float64) weights = torch.tensor([0.4, 0.5], requires_grad=True, dtype=torch.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost_fn(weights, coeffs1, coeffs2, dev=dev) expected = self.cost_fn_expected(weights, coeffs1, coeffs2) @@ -1293,7 +1293,7 @@ def test_multiple_hamiltonians_trainable(self, cost_fn, execute_kwargs, tol): coeffs1 = torch.tensor([0.1, 0.2, 0.3], requires_grad=True, dtype=torch.float64) coeffs2 = torch.tensor([0.7], requires_grad=True, dtype=torch.float64) weights = torch.tensor([0.4, 0.5], requires_grad=True, dtype=torch.float64) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) res = cost_fn(weights, coeffs1, coeffs2, dev=dev) expected = self.cost_fn_expected(weights, coeffs1, coeffs2) diff --git a/tests/interfaces/test_torch_qnode.py b/tests/interfaces/test_torch_qnode.py index b23eea54c90..1f924860af7 100644 --- a/tests/interfaces/test_torch_qnode.py +++ b/tests/interfaces/test_torch_qnode.py @@ -26,13 +26,13 @@ hessian = torch.autograd.functional.hessian qubit_device_and_diff_method = [ - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "backprop", True], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "spsa", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "spsa", False], + ["default.qubit.legacy", "hadamard", False], ] interface_and_qubit_device_and_diff_method = [ @@ -551,7 +551,7 @@ class TestShotsIntegration: def test_changing_shots(self, mocker, tol): """Test that changing shots works on execution""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = torch.tensor([0.543, -0.654], requires_grad=True, dtype=torch.float64) @qnode(dev, interface="torch", diff_method=qml.gradients.param_shift) @@ -585,7 +585,7 @@ def test_gradient_integration(self): """Test that temporarily setting the shots works for gradient computations""" # pylint: disable=unexpected-keyword-arg - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) a, b = torch.tensor([0.543, -0.654], requires_grad=True) @qnode(dev, interface="torch", diff_method=qml.gradients.param_shift) @@ -607,7 +607,7 @@ def test_multiple_gradient_integration(self, tol): """Test that temporarily setting the shots works for gradient computations, even if the QNode has been re-evaluated with a different number of shots in the meantime.""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) weights = torch.tensor([0.543, -0.654], requires_grad=True) a, b = weights @@ -631,7 +631,7 @@ def circuit(a, b): def test_update_diff_method(self, mocker): """Test that temporarily setting the shots updates the diff method""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) a, b = torch.tensor([0.543, -0.654], requires_grad=True) spy = mocker.spy(qml, "execute") @@ -665,7 +665,7 @@ class TestAdjoint: def test_reuse_state(self, mocker): """Tests that the Torch interface reuses the device state for adjoint differentiation""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qnode(dev, diff_method="adjoint", interface="torch") def circ(x): @@ -689,7 +689,7 @@ def circ(x): def test_resuse_state_multiple_evals(self, mocker, tol): """Tests that the Torch interface reuses the device state for adjoint differentiation, even where there are intermediate evaluations.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) x_val = 0.543 y_val = -0.654 @@ -1600,7 +1600,7 @@ class TestSample: def test_sample_dimension(self): """Test sampling works as expected""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1622,7 +1622,7 @@ def circuit(): def test_sampling_expval(self): """Test sampling works as expected if combined with expectation values""" shots = 10 - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1643,7 +1643,7 @@ def circuit(): def test_counts_expval(self): """Test counts works as expected if combined with expectation values""" shots = 10 - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1664,7 +1664,7 @@ def test_sample_combination(self): """Test the output of combining expval, var and sample""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1688,7 +1688,7 @@ def test_single_wire_sample(self): """Test the return type and shape of sampling a single wire""" n_sample = 10 - dev = qml.device("default.qubit", wires=1, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1705,7 +1705,7 @@ def test_multi_wire_sample_regular_shape(self): where a rectangular array is expected""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) @qnode(dev, diff_method="parameter-shift", interface="torch") def circuit(): @@ -1724,12 +1724,12 @@ def circuit(): qubit_device_and_diff_method_and_grad_on_execution = [ - ["default.qubit", "backprop", True], - ["default.qubit", "finite-diff", False], - ["default.qubit", "parameter-shift", False], - ["default.qubit", "adjoint", True], - ["default.qubit", "adjoint", False], - ["default.qubit", "hadamard", False], + ["default.qubit.legacy", "backprop", True], + ["default.qubit.legacy", "finite-diff", False], + ["default.qubit.legacy", "parameter-shift", False], + ["default.qubit.legacy", "adjoint", True], + ["default.qubit.legacy", "adjoint", False], + ["default.qubit.legacy", "hadamard", False], ] @@ -2565,7 +2565,7 @@ def circuit_stack(x): assert tuple(hess.shape) == (3, 2, 2) -@pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) +@pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_no_ops(dev_name): """Test that the return value of the QNode matches in the interface even if there are no ops""" diff --git a/tests/interfaces/test_transform_program_integration.py b/tests/interfaces/test_transform_program_integration.py index 39c84a02c48..3708c52552b 100644 --- a/tests/interfaces/test_transform_program_integration.py +++ b/tests/interfaces/test_transform_program_integration.py @@ -25,7 +25,7 @@ device_suite = ( - qml.device("default.qubit", wires=5), + qml.device("default.qubit.legacy", wires=5), qml.devices.experimental.DefaultQubit2(), qml.device("lightning.qubit", wires=5), ) @@ -168,7 +168,7 @@ def split_sum_terms(tape): def test_chained_preprocessing(self): """Test a transform program with two transforms where their order affects the output.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) def null_postprocessing(results): return results[0] From f3af9612f0eff59a03367d7b0cdeb5524207839a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 15 Aug 2023 09:11:51 -0400 Subject: [PATCH 16/78] xfail test for amplitudeembedding found mid-circuit --- .../test_optimization/test_merge_amplitude_embedding.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py index 066007f0578..c8db378185d 100644 --- a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py +++ b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py @@ -44,6 +44,7 @@ def qfunc(): dev = qml.device("default.qubit.legacy", wires=2) assert np.allclose(qml.QNode(transformed_qfunc, dev)()[-1], 1) + @pytest.mark.xfail(reason="fails earlier because the operator inherits from StatePrep") def test_repeated_qubit(self): """Check that AmplitudeEmbedding cannot be applied if the qubit has already been used.""" From 3ae33b5492a9b692c2a5be38015ef78e504279c3 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 15 Aug 2023 09:13:29 -0400 Subject: [PATCH 17/78] test amplitudeembedding using new device --- .../test_merge_amplitude_embedding.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py index c8db378185d..563de73daa3 100644 --- a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py +++ b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py @@ -41,7 +41,7 @@ def qfunc(): assert len(ops) == 3 # Check that the solution is as expected. - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) assert np.allclose(qml.QNode(transformed_qfunc, dev)()[-1], 1) @pytest.mark.xfail(reason="fails earlier because the operator inherits from StatePrep") @@ -54,7 +54,7 @@ def qfunc(): transformed_qfunc = merge_amplitude_embedding(qfunc) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) qnode = qml.QNode(transformed_qfunc, dev) with pytest.raises(DeviceError, match="applied in the same qubit"): @@ -70,13 +70,13 @@ def qfunc(): return qml.state() - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) qnode = qml.QNode(qfunc, dev) assert qnode()[3] == 1.0 def test_broadcasting(self): """Test that merging preserves the batch dimension""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) @qml.transforms.merge_amplitude_embedding @@ -106,7 +106,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -124,7 +124,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -142,7 +142,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) @@ -163,7 +163,7 @@ def qfunc(amplitude): qml.AmplitudeEmbedding(amplitude, wires=1) return qml.state() - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) optimized_qfunc = qml.transforms.merge_amplitude_embedding(qfunc) optimized_qnode = qml.QNode(optimized_qfunc, dev) From cfc016e15ecf2413f828fe01e6e218ddcffe7c9c Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 15 Aug 2023 11:28:51 -0400 Subject: [PATCH 18/78] use dev.execute in gradients; adjoint_diff uses legacy --- tests/gradients/core/test_adjoint_diff.py | 10 +- .../gradients/core/test_hadamard_gradient.py | 18 +- .../core/test_hamiltonian_gradient.py | 4 +- tests/gradients/core/test_jvp.py | 28 +-- .../core/test_pulse_generator_gradient.py | 4 +- tests/gradients/core/test_vjp.py | 20 +-- .../finite_diff/test_finite_difference.py | 36 ++-- .../test_finite_difference_shot_vec.py | 44 ++--- .../finite_diff/test_spsa_gradient.py | 36 ++-- .../test_spsa_gradient_shot_vec.py | 44 ++--- .../parameter_shift/test_parameter_shift.py | 164 +++++++++--------- .../test_parameter_shift_cv.py | 54 +++--- .../test_parameter_shift_shot_vec.py | 116 ++++++------- 13 files changed, 289 insertions(+), 289 deletions(-) diff --git a/tests/gradients/core/test_adjoint_diff.py b/tests/gradients/core/test_adjoint_diff.py index b10fecc2946..e72841a8630 100644 --- a/tests/gradients/core/test_adjoint_diff.py +++ b/tests/gradients/core/test_adjoint_diff.py @@ -26,7 +26,7 @@ class TestAdjointJacobian: @pytest.fixture def dev(self): """Fixture that creates a device with two wires.""" - return qml.device("default.qubit", wires=2) + return qml.device("default.qubit.legacy", wires=2) def test_not_expval(self, dev): """Test if a QuantumFunctionError is raised for a tape with measurements that are not @@ -43,7 +43,7 @@ def test_not_expval(self, dev): def test_finite_shots_warns(self): """Tests warning raised when finite shots specified""" - dev = qml.device("default.qubit", wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) with qml.queuing.AnnotatedQueue() as q: qml.expval(qml.PauliZ(0)) @@ -88,7 +88,7 @@ def test_trainable_hermitian_warns(self): """Test attempting to compute the gradient of a tape that obtains the expectation value of a Hermitian operator emits a warning if the parameters to Hermitian are trainable.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) mx = qml.matrix(qml.PauliX(0) @ qml.PauliY(2)) with qml.queuing.AnnotatedQueue() as q: @@ -193,7 +193,7 @@ def test_rx_gradient(self, tol, dev): def test_multiple_rx_gradient(self, tol): """Tests that the gradient of multiple RX gates in a circuit yields the correct result.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) params = np.array([np.pi, np.pi / 2, np.pi / 3]) with qml.queuing.AnnotatedQueue() as q: @@ -331,7 +331,7 @@ def test_provide_starting_state(self, tol, dev): def test_gradient_of_tape_with_hermitian(self, tol): """Test that computing the gradient of a tape that obtains the expectation value of a Hermitian operator works correctly.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) a, b, c = [0.5, 0.3, -0.7] diff --git a/tests/gradients/core/test_hadamard_gradient.py b/tests/gradients/core/test_hadamard_gradient.py index 987c495dcd6..e53a8e17bf6 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): @@ -980,7 +980,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(dev.execute(tapes)) return qml.math.stack(jac) def cost_fn_param_shift(x): @@ -993,7 +993,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(dev.execute(tapes)) return qml.math.stack(jac) res_hadamard = qml.jacobian(cost_fn_hadamard)(params) @@ -1019,7 +1019,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(dev.execute(tapes)) jac_h = qml.math.stack(jac_h) with tf.GradientTape() as t_p: @@ -1032,7 +1032,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(dev.execute(tapes)) jac_p = qml.math.stack(jac_p) res_hadamard = t_h.jacobian(jac_h, params) @@ -1059,7 +1059,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(dev.execute(tapes)) return jac def cost_p(x): @@ -1072,7 +1072,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(dev.execute(tapes)) return jac res_hadamard = torch.autograd.functional.jacobian(cost_h, params) @@ -1105,7 +1105,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(dev.execute(tapes)) return jac def cost_p(x): @@ -1119,7 +1119,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(dev.execute(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..738eecc5fc7 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) diff --git a/tests/gradients/core/test_jvp.py b/tests/gradients/core/test_jvp.py index 97729a18d37..7c56df6f7da 100644 --- a/tests/gradients/core/test_jvp.py +++ b/tests/gradients/core/test_jvp.py @@ -481,7 +481,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) @@ -508,7 +508,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) @@ -537,7 +537,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,) @@ -571,7 +571,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 @@ -658,7 +658,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(dev.execute(tapes)) return jvp res = cost_fn(params, tangent) @@ -692,7 +692,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(dev.execute(tapes)) return jvp res = cost_fn(params, tangent) @@ -726,7 +726,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(dev.execute(tapes)) return jvp with tf.GradientTape() as t: @@ -762,7 +762,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(dev.execute(tapes)) return jvp res = cost_fn(params, tangent) @@ -805,7 +805,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 @@ -861,7 +861,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 @@ -893,7 +893,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 @@ -926,7 +926,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): @@ -961,7 +961,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 @@ -992,6 +992,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 ccfda26bd1d..e077b3beb75 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): @@ -863,7 +863,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) diff --git a/tests/gradients/core/test_vjp.py b/tests/gradients/core/test_vjp.py index bc8c7b44510..ca4690962cc 100644 --- a/tests/gradients/core/test_vjp.py +++ b/tests/gradients/core/test_vjp.py @@ -257,7 +257,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)]) @@ -284,7 +284,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)]) @@ -311,7 +311,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 = ( @@ -397,7 +397,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(dev.execute(tapes)) return vjp dy = np.array([-1.0, 0.0, 0.0, 1.0], requires_grad=False) @@ -455,7 +455,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(dev.execute(tapes)) assert np.allclose(vjp, expected(params), atol=tol, rtol=0) @@ -518,7 +518,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(dev.execute(tapes)) return vjp res = cost_fn(params) @@ -560,7 +560,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 @@ -614,7 +614,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 @@ -645,7 +645,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 @@ -676,7 +676,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 4441c213262..8fbd708e7f5 100644 --- a/tests/gradients/finite_diff/test_finite_difference.py +++ b/tests/gradients/finite_diff/test_finite_difference.py @@ -123,7 +123,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) @@ -145,7 +145,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 @@ -406,13 +406,13 @@ 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)) + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter (2 executions) assert dev.num_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) @@ -557,7 +557,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) @@ -590,7 +590,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 @@ -627,7 +627,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 @@ -664,7 +664,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 @@ -705,7 +705,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) @@ -731,7 +731,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 @@ -766,7 +766,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 @@ -801,7 +801,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 @@ -863,7 +863,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(dev.execute(tapes))) return jac res = qml.jacobian(cost_fn)(params) @@ -895,7 +895,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(dev.execute(tapes)) return jac[1][0] x, y = params @@ -923,7 +923,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(dev.execute(tapes)) x, y = 1.0 * params @@ -959,7 +959,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(dev.execute(tapes))[1][0] x, y = 1.0 * params @@ -987,7 +987,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(dev.execute(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1027,7 +1027,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(dev.execute(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 afc84464bfd..470d6e15ba9 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) @@ -358,13 +358,13 @@ 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)) + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter (2 executions) assert dev.num_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) @@ -519,7 +519,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) @@ -559,7 +559,7 @@ 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) @@ -601,7 +601,7 @@ 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) @@ -647,7 +647,7 @@ 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) @@ -695,7 +695,7 @@ 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) @@ -734,7 +734,7 @@ 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) @@ -777,7 +777,7 @@ 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) @@ -822,7 +822,7 @@ 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) @@ -895,7 +895,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(dev.execute(tapes))) return jac all_res = qml.jacobian(cost_fn)(params) @@ -938,7 +938,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac[1][0] x, y = params @@ -977,7 +977,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(dev.execute(tapes)) x, y = 1.0 * params @@ -1019,7 +1019,7 @@ def test_tf_ragged(self, approx_order, strategy): h=h_val, ) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(dev.execute(tapes))[1][0] x, y = 1.0 * params @@ -1053,7 +1053,7 @@ def cost_fn(params): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1103,7 +1103,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac all_res = jax.jacobian(cost_fn)(params) @@ -1176,7 +1176,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 +1210,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 +1244,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 +1286,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 33f1faeba25..d26fccc63a2 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient.py +++ b/tests/gradients/finite_diff/test_spsa_gradient.py @@ -64,7 +64,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 @@ -88,7 +88,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 @@ -359,13 +359,13 @@ def test_independent_parameters(self): tape2 = qml.tape.QuantumScript.from_queue(q2) n1 = 5 tapes, fn = spsa_grad(tape1, approx_order=1, strategy="forward", num_directions=n1) - j1 = fn(dev.batch_execute(tapes)) + j1 = fn(dev.execute(tapes)) assert len(tapes) == dev.num_executions == n1 + 1 n2 = 11 tapes, fn = spsa_grad(tape2, num_directions=n2) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) assert len(tapes) == 2 * n2 @@ -518,7 +518,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) @@ -557,7 +557,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 @@ -601,7 +601,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 @@ -650,7 +650,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 @@ -695,7 +695,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) @@ -726,7 +726,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 @@ -771,7 +771,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 @@ -816,7 +816,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 @@ -885,7 +885,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(dev.execute(tapes))) if sampler is coordinate_sampler: jac *= 2 return jac @@ -920,7 +920,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) if sampler is coordinate_sampler: jac = tuple(tuple(2 * _j for _j in _jac) for _jac in jac) return jac[1][0] @@ -951,7 +951,7 @@ def test_tf(self, sampler, num_directions, atol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac_0, jac_1 = fn(dev.batch_execute(tapes)) + jac_0, jac_1 = fn(dev.execute(tapes)) if sampler is coordinate_sampler: jac_0 *= 2 jac_1 *= 2 @@ -992,7 +992,7 @@ def test_tf_ragged(self, sampler, num_directions, atol): tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(dev.execute(tapes))[1][0] if sampler is coordinate_sampler: jac_01 *= 2 @@ -1023,7 +1023,7 @@ def cost_fn(params): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) if sampler is coordinate_sampler: jac = tuple(2 * _jac for _jac in jac) return jac @@ -1066,7 +1066,7 @@ def cost_fn(x): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = spsa_grad(tape, n=1, num_directions=num_directions, sampler=sampler) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(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 d93647b128d..a602ae4e937 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) @@ -404,7 +404,7 @@ def test_independent_parameters(self): num_directions=n1, h=h_val, ) - j1 = fn(dev.batch_execute(tapes)) + j1 = fn(dev.execute(tapes)) assert len(tapes) == dev.num_executions == n1 + 1 @@ -416,7 +416,7 @@ def test_independent_parameters(self): h=h_val, num_directions=n2, ) - j2 = fn(dev.batch_execute(tapes)) + j2 = fn(dev.execute(tapes)) assert len(tapes) == n2 + 1 @@ -577,7 +577,7 @@ def test_ragged_output(self, approx_order, strategy, validate): validate_params=validate, num_directions=3, ) - 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) @@ -620,7 +620,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate): num_directions=4, sampler=coordinate_sampler, ) - 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) @@ -668,7 +668,7 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, sampler=coordinate_sampler, 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) @@ -720,7 +720,7 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, sampler=coordinate_sampler, 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) @@ -773,7 +773,7 @@ def test_multiple_expectation_value_with_argnum_one(self, approx_order, strategy sampler=coordinate_sampler, 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) @@ -812,7 +812,7 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate): h=h_val, num_directions=4, ) - 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) @@ -865,7 +865,7 @@ def test_var_expectation_values(self, approx_order, strategy, validate): num_directions=6, sampler=coordinate_sampler, ) - 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) @@ -919,7 +919,7 @@ def test_prob_expectation_values(self, approx_order, strategy, validate): num_directions=4, 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) @@ -1000,7 +1000,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = np.array(fn(dev.batch_execute(tapes))) + jac = np.array(fn(dev.execute(tapes))) return jac all_res = qml.jacobian(cost_fn)(params) @@ -1044,7 +1044,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac[1][0] x, y = params @@ -1084,7 +1084,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(dev.execute(tapes)) x, y = 1.0 * params @@ -1127,7 +1127,7 @@ def test_tf_ragged(self, approx_order, strategy): h=h_val, ) - jac_01 = fn(dev.batch_execute(tapes))[1][0] + jac_01 = fn(dev.execute(tapes))[1][0] x, y = 1.0 * params @@ -1162,7 +1162,7 @@ def cost_fn(params): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac hess = torch.autograd.functional.jacobian(cost_fn, params) @@ -1209,7 +1209,7 @@ def cost_fn(x): strategy=strategy, h=h_val, ) - jac = fn(dev.batch_execute(tapes)) + jac = fn(dev.execute(tapes)) return jac all_res = jax.jacobian(cost_fn)(params) @@ -1282,7 +1282,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) @@ -1316,7 +1316,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) @@ -1350,7 +1350,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) @@ -1389,7 +1389,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 8aa6fe6cfa4..05dc4dffb36 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,7 +825,7 @@ 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)) + 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. @@ -833,7 +833,7 @@ def test_independent_parameters_analytic(self): assert dev.num_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 +863,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): @@ -930,7 +930,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 @@ -958,7 +958,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 @@ -985,7 +985,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 == () @@ -1064,7 +1064,7 @@ 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)) + j1 = fn(dev.execute(tapes)) # We should only be executing the device to differentiate 1 parameter # (1 broadcasted execution) @@ -1072,7 +1072,7 @@ def test_independent_parameters_analytic(self): assert dev.num_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) @@ -1106,7 +1106,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)) @@ -1137,12 +1137,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) @@ -1151,7 +1151,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)) @@ -1174,7 +1174,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 @@ -1199,7 +1199,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) @@ -1221,12 +1221,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)) @@ -1251,7 +1251,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)), @@ -1265,7 +1265,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) @@ -1357,7 +1357,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) @@ -1409,7 +1409,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) @@ -1451,7 +1451,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {argnum} - return fn(dev.batch_execute(tapes)) + return fn(dev.execute(tapes)) res = cost_fn(params) @@ -1532,7 +1532,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(dev.execute(tapes)) assert isinstance(res, tuple) assert res[0].shape == () @@ -1558,7 +1558,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) @@ -1585,7 +1585,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 @@ -1612,7 +1612,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 @@ -1641,7 +1641,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: @@ -1698,13 +1698,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) @@ -1731,7 +1731,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) @@ -1743,7 +1743,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) @@ -1772,13 +1772,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) @@ -1806,7 +1806,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) @@ -1817,7 +1817,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)) @@ -1850,11 +1850,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] @@ -1903,7 +1903,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 @@ -1953,7 +1953,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 @@ -2083,10 +2083,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) @@ -2130,10 +2130,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( [ @@ -2204,10 +2204,10 @@ def test_projector_variance(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( [ @@ -2398,7 +2398,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 @@ -2429,18 +2429,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)) @@ -2463,7 +2463,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)): @@ -2482,7 +2482,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): @@ -2506,12 +2506,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)) @@ -2537,7 +2537,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)), @@ -2550,7 +2550,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): @@ -2641,7 +2641,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)) with pytest.raises(NotImplementedError, match="Broadcasting with multiple measurements"): cost_fn(params) @@ -2681,7 +2681,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(dev.execute(tapes)) assert len(res) == 2 assert res[0].shape == () assert res[1].shape == () @@ -2707,7 +2707,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 == () @@ -2739,7 +2739,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)]]) @@ -2768,7 +2768,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)]]) @@ -2798,7 +2798,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 = ( @@ -2844,7 +2844,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 == () @@ -2853,7 +2853,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) @@ -2880,7 +2880,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 == () @@ -2889,7 +2889,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) @@ -2921,11 +2921,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)] @@ -2967,10 +2967,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( @@ -3004,10 +3004,10 @@ def test_projector_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)) tapes, fn = qml.gradients.finite_diff(tape) - gradF = fn(dev.batch_execute(tapes)) + gradF = fn(dev.execute(tapes)) expected = np.array( [ @@ -3098,7 +3098,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(dev.execute(tapes)) return jac res = qml.jacobian(cost_fn)(params) @@ -3160,7 +3160,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) @@ -3170,7 +3170,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 @@ -3206,7 +3206,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) @@ -3217,7 +3217,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 == () @@ -3264,7 +3264,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) @@ -3279,7 +3279,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 @@ -3317,7 +3317,7 @@ 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)) + jac = fn(dev.execute(tapes)) return jac @staticmethod diff --git a/tests/gradients/parameter_shift/test_parameter_shift_cv.py b/tests/gradients/parameter_shift/test_parameter_shift_cv.py index f911dbcb7bb..3db8ad8b76b 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift_cv.py +++ b/tests/gradients/parameter_shift/test_parameter_shift_cv.py @@ -530,7 +530,7 @@ def test_independent_parameters_analytic(self): # (first order, so 2 executions) assert len(tapes) == 2 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert np.allclose(res, [0, 2]) tape.trainable_params = {0, 2} @@ -540,7 +540,7 @@ def test_independent_parameters_analytic(self): # (second order, so 0 executions) assert len(tapes) == 0 - res = fn(dev.batch_execute(tapes)) + res = fn(dev.execute(tapes)) assert np.allclose(res, [0, 2]) def test_all_independent(self): @@ -557,7 +557,7 @@ def test_all_independent(self): tapes, fn = qml.gradients.param_shift_cv(tape, dev) assert len(tapes) == 0 - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) assert np.allclose(grad, [0, 0]) @@ -587,11 +587,11 @@ def test_rotation_gradient(self, gradient_recipes, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev, gradient_recipes=gradient_recipes) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, gradient_recipes=gradient_recipes, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) spy2.assert_called() expected = -hbar * alpha * np.sin(theta) @@ -616,11 +616,11 @@ def test_beamsplitter_gradient(self, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) spy2.assert_called() expected = -hbar * alpha * np.sin(theta) @@ -644,11 +644,11 @@ def test_displacement_gradient(self, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) spy2.assert_called() expected = [hbar * np.cos(phi), -hbar * r * np.sin(phi)] @@ -690,11 +690,11 @@ class Rotation(qml.operation.CVOperation): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) spy2.assert_called() expected = -np.exp(-r) * hbar * alpha @@ -719,7 +719,7 @@ def test_squeezed_number_state_gradient(self, mocker, tol): spy = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) assert tape._par_info[0]["grad_method"] == "F" spy.assert_not_called() @@ -743,7 +743,7 @@ def test_multiple_squeezing_gradient(self, mocker, tol): tape = qml.tape.QuantumScript.from_queue(q) spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) spy2.assert_called() # check against the known analytic formula @@ -806,10 +806,10 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): tape.trainable_params = set(range(2, 2 + op.num_params)) tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.batch_execute(tapes)) + grad_F = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) # check that every parameter is analytic for i in range(op.num_params): @@ -819,7 +819,7 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): if obs.ev_order == 1: tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) assert np.allclose(grad_A, grad_F, atol=tol, rtol=0) @pytest.mark.parametrize("t", [0, 1]) @@ -882,13 +882,13 @@ def test_interferometer_unitary(self, t, tol): dev = qml.device("default.gaussian", wires=2) tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.batch_execute(tapes)) + grad_F = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) assert tape._par_info[0]["grad_method"] == "A" assert tape._par_info[1]["grad_method"] == "A" @@ -923,10 +923,10 @@ def test_first_order_observable(self, tol): # circuit jacobians tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.batch_execute(tapes)) + grad_F = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) expected = np.array( [ @@ -960,7 +960,7 @@ def test_second_order_cv(self, tol): # circuit jacobians tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.batch_execute(tapes)) + grad_F = fn(dev.execute(tapes)) expected = np.array([[2 * a**2 + 2 * n + 1, 2 * a * (2 * n + 1)]]) assert np.allclose(grad_F, expected, atol=tol, rtol=0) @@ -1063,13 +1063,13 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): # jacobians must match tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.batch_execute(tapes)) + grad_F = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.batch_execute(tapes)) + grad_A = fn(dev.execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.batch_execute(tapes)) + grad_A2 = fn(dev.execute(tapes)) assert np.allclose(grad_A2, grad_F, atol=tol, rtol=0) assert np.allclose(grad_A, grad_F, atol=tol, rtol=0) @@ -1094,7 +1094,7 @@ def test_squeezed_mean_photon_variance(self, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 2} tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.array( [ 2 * np.exp(2 * r) * np.sin(phi) ** 2 - 2 * np.exp(-2 * r) * np.cos(phi) ** 2, @@ -1118,7 +1118,7 @@ def test_displaced_thermal_mean_photon_variance(self, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.batch_execute(tapes)) + grad = fn(dev.execute(tapes)) expected = np.array([2 * a**2 + 2 * n + 1, 2 * a * (2 * n + 1)]) assert np.allclose(grad, expected, atol=tol, rtol=0) 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 f0e62b76e8f..de65697867f 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,7 +484,7 @@ 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)) + 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. @@ -492,7 +492,7 @@ def test_independent_parameters_analytic(self): assert dev.num_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 +532,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 +606,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 +628,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 +654,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 +687,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 +710,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 +744,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 +762,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) @@ -869,7 +869,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)) all_res = cost_fn(params) @@ -923,7 +923,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)) all_res = cost_fn(params) @@ -967,7 +967,7 @@ def cost_fn(params): spy.assert_called() assert spy.call_args[1]["argnum"] == {argnum} - return fn(dev.batch_execute(tapes)) + return fn(dev.execute(tapes)) all_res = cost_fn(params) assert isinstance(all_res, tuple) @@ -1053,7 +1053,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(dev.execute(tapes)) assert len(all_res) == len(fallback_shot_vec) assert isinstance(all_res, tuple) @@ -1085,7 +1085,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 +1118,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 +1151,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 +1185,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 +1272,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 +1280,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 +1312,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 +1326,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 +1359,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 +1401,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 +1419,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 +1456,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 +1507,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 +1524,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 +1590,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 +1647,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 +1750,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 +1764,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 +1806,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 +1831,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 +1861,7 @@ def test_projector_variance(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) @@ -1876,7 +1876,7 @@ def test_projector_variance(self): 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 +2074,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 +2132,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 +2142,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 +2183,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 +2194,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 +2243,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 +2258,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 +2296,7 @@ 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)) + return fn(dev.execute(tapes)) @staticmethod def cost_fn_expected(weights, coeffs1, coeffs2): @@ -2516,7 +2516,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 +2550,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 +2584,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 +2624,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) From 6576771bad6534189701680ab817fa3fb0ae1323 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 16 Aug 2023 10:19:12 -0400 Subject: [PATCH 19/78] wip: start testing old and new interface devices --- .../gradients/core/test_hadamard_gradient.py | 128 +++++++++++++++--- tests/gradients/core/test_jvp.py | 33 +++-- .../core/test_pulse_generator_gradient.py | 77 ++++++----- .../test_parameter_shift_shot_vec.py | 63 +++++---- 4 files changed, 212 insertions(+), 89 deletions(-) diff --git a/tests/gradients/core/test_hadamard_gradient.py b/tests/gradients/core/test_hadamard_gradient.py index e53a8e17bf6..fc342c2faa1 100644 --- a/tests/gradients/core/test_hadamard_gradient.py +++ b/tests/gradients/core/test_hadamard_gradient.py @@ -541,6 +541,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])] @@ -718,7 +720,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): @@ -738,7 +740,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): @@ -758,7 +760,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): @@ -778,6 +780,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") @@ -964,10 +1046,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): @@ -980,7 +1064,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.execute(tapes)) + jac = fn(execute_fn(tapes)) return qml.math.stack(jac) def cost_fn_param_shift(x): @@ -993,7 +1077,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.execute(tapes)) + jac = fn(execute_fn(tapes)) return qml.math.stack(jac) res_hadamard = qml.jacobian(cost_fn_hadamard)(params) @@ -1001,12 +1085,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: @@ -1019,7 +1105,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.execute(tapes)) + jac_h = fn(execute_fn(tapes)) jac_h = qml.math.stack(jac_h) with tf.GradientTape() as t_p: @@ -1032,7 +1118,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.execute(tapes)) + jac_p = fn(execute_fn(tapes)) jac_p = qml.math.stack(jac_p) res_hadamard = t_h.jacobian(jac_h, params) @@ -1041,12 +1127,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): @@ -1059,7 +1147,7 @@ def cost_h(x): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac def cost_p(x): @@ -1072,7 +1160,7 @@ def cost_p(x): tape = qml.tape.QuantumScript.from_queue(q) tapes, fn = qml.gradients.param_shift(tape) - jac = fn(dev.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res_hadamard = torch.autograd.functional.jacobian(cost_h, params) @@ -1082,7 +1170,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 @@ -1091,7 +1180,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): @@ -1105,7 +1195,7 @@ def cost_h(x): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac def cost_p(x): @@ -1119,7 +1209,7 @@ def cost_p(x): tape.trainable_params = {0, 1} tapes, fn = qml.gradients.hadamard_grad(tape) - jac = fn(dev.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res_hadamard = jax.jacobian(cost_h)(params) diff --git a/tests/gradients/core/test_jvp.py b/tests/gradients/core/test_jvp.py index 7c56df6f7da..4e1b66186c2 100644 --- a/tests/gradients/core/test_jvp.py +++ b/tests/gradients/core/test_jvp.py @@ -487,6 +487,7 @@ def test_single_expectation_value(self, tol, batch_dim): exp = np.sum(np.array([-np.sin(y) * np.sin(x), np.cos(y) * np.cos(x)]), axis=0) assert np.allclose(res, exp, atol=tol, rtol=0) + @pytest.mark.xfail(reason="batch dimension of 1 gets squeezed out") def test_multiple_expectation_values(self, tol, batch_dim): """Tests correct output shape and evaluation for a tape with multiple expval outputs""" @@ -642,10 +643,12 @@ class TestJVPGradients: @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) @@ -658,7 +661,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.execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) @@ -671,12 +674,14 @@ def cost_fn(params, tangent): @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: @@ -692,7 +697,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.execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) @@ -706,12 +711,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) @@ -726,7 +733,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.execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp with tf.GradientTape() as t: @@ -741,13 +748,15 @@ def cost_fn(params, tangent): @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) @@ -762,7 +771,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.execute(tapes)) + jvp = fn(execute_fn(tapes)) return jvp res = cost_fn(params, tangent) diff --git a/tests/gradients/core/test_pulse_generator_gradient.py b/tests/gradients/core/test_pulse_generator_gradient.py index e077b3beb75..7fbbde0712e 100644 --- a/tests/gradients/core/test_pulse_generator_gradient.py +++ b/tests/gradients/core/test_pulse_generator_gradient.py @@ -958,19 +958,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]) @@ -998,15 +1000,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]) @@ -1038,13 +1040,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]) @@ -1078,15 +1080,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) @@ -1122,14 +1124,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") @@ -1143,14 +1146,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) @@ -1169,14 +1172,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) @@ -1201,14 +1204,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) @@ -1241,17 +1244,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) @@ -1268,14 +1272,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) @@ -1294,14 +1298,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) @@ -1316,14 +1320,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) @@ -1345,13 +1349,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) @@ -1367,15 +1371,18 @@ 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 + if dev_name == "default.qubit": + pytest.skip("num_executions is not correct") + 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) @@ -1403,14 +1410,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) @@ -1435,7 +1442,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, @@ -1443,14 +1452,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/parameter_shift/test_parameter_shift_shot_vec.py b/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py index de65697867f..4f3d10ffac5 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py +++ b/tests/gradients/parameter_shift/test_parameter_shift_shot_vec.py @@ -484,12 +484,13 @@ 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.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.execute(tapes)) @@ -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.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.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.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.execute(tapes)) + all_res = fn(execute_fn(tapes)) assert len(all_res) == len(fallback_shot_vec) assert isinstance(all_res, tuple) @@ -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.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( From c59ee295906bd446b801c1d6bb4f1dc5cef01f32 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 18 Aug 2023 16:53:36 -0400 Subject: [PATCH 20/78] finish touching up gradients --- pennylane/gradients/spsa_gradient.py | 2 +- pennylane/interfaces/execution.py | 1 + tests/gradients/core/test_pulse_gradient.py | 120 +++++++++--------- tests/gradients/core/test_vjp.py | 29 +++-- .../finite_diff/test_finite_difference.py | 53 +++++--- .../test_finite_difference_shot_vec.py | 84 +++++++----- .../finite_diff/test_spsa_gradient.py | 53 +++++--- .../test_spsa_gradient_shot_vec.py | 53 +++++--- .../parameter_shift/test_parameter_shift.py | 81 +++++++----- 9 files changed, 282 insertions(+), 194 deletions(-) diff --git a/pennylane/gradients/spsa_gradient.py b/pennylane/gradients/spsa_gradient.py index 169c202d752..b88e6098333 100644 --- a/pennylane/gradients/spsa_gradient.py +++ b/pennylane/gradients/spsa_gradient.py @@ -345,7 +345,7 @@ def _single_shot_batch_result(results): if num_measurements == 1: grads = 0 for rep, _coeffs in enumerate(all_coeffs): - res = results[rep * tapes_per_grad : (rep + 1) * tapes_per_grad] + res = list(results[rep * tapes_per_grad : (rep + 1) * tapes_per_grad]) if r0 is not None: res.insert(0, r0) res = qml.math.stack(res) diff --git a/pennylane/interfaces/execution.py b/pennylane/interfaces/execution.py index 5e151434f4d..f716741e9b7 100644 --- a/pennylane/interfaces/execution.py +++ b/pennylane/interfaces/execution.py @@ -254,6 +254,7 @@ def inner_execute(tapes: Sequence[QuantumTape], **_) -> ResultBatch: tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes) return cached_device_execution(tapes) + # TODO: set as pure_callback if interface is jax-jit return inner_execute 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 ca4690962cc..515ff9b2beb 100644 --- a/tests/gradients/core/test_vjp.py +++ b/tests/gradients/core/test_vjp.py @@ -384,10 +384,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): @@ -397,7 +399,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.execute(tapes)) + vjp = fn(execute_fn(tapes)) return vjp dy = np.array([-1.0, 0.0, 0.0, 1.0], requires_grad=False) @@ -408,12 +410,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) @@ -437,12 +440,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) @@ -455,7 +460,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.execute(tapes)) + vjp = fn(execute_fn(tapes)) assert np.allclose(vjp, expected(params), atol=tol, rtol=0) @@ -500,13 +505,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) @@ -518,7 +525,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.execute(tapes)) + vjp = fn(execute_fn(tapes)) return vjp res = cost_fn(params) diff --git a/tests/gradients/finite_diff/test_finite_difference.py b/tests/gradients/finite_diff/test_finite_difference.py index dcc972a0554..b0bc499fef3 100644 --- a/tests/gradients/finite_diff/test_finite_difference.py +++ b/tests/gradients/finite_diff/test_finite_difference.py @@ -413,10 +413,11 @@ def test_independent_parameters(self): tape2 = qml.tape.QuantumScript.from_queue(q2) tapes, fn = finite_diff(tape1, approx_order=1) - j1 = fn(dev.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.execute(tapes)) @@ -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.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.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.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.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.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.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 fe6487f6503..711b1a2817e 100644 --- a/tests/gradients/finite_diff/test_finite_difference_shot_vec.py +++ b/tests/gradients/finite_diff/test_finite_difference_shot_vec.py @@ -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,10 +358,11 @@ 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.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.execute(tapes)) @@ -369,9 +370,9 @@ def test_independent_parameters(self): 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) @@ -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, @@ -562,7 +563,7 @@ def test_single_expectation_value(self, approx_order, strategy, validate): 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: @@ -604,7 +605,7 @@ def test_single_expectation_value_with_argnum_all(self, approx_order, strategy, 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: @@ -650,7 +651,7 @@ def test_single_expectation_value_with_argnum_one(self, approx_order, strategy, 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 @@ -698,7 +702,7 @@ def test_probs_expval_with_argnum_one(self, approx_order, strategy, validate): 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] @@ -737,7 +741,7 @@ def test_multiple_expectation_values(self, approx_order, strategy, validate): 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) @@ -780,7 +784,7 @@ def test_var_expectation_values(self, approx_order, strategy, validate): 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) @@ -825,7 +829,7 @@ def test_prob_expectation_values(self, approx_order, strategy, validate): 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.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.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.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.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.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.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( diff --git a/tests/gradients/finite_diff/test_spsa_gradient.py b/tests/gradients/finite_diff/test_spsa_gradient.py index 50218ecedb6..e8ebe3b7845 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient.py +++ b/tests/gradients/finite_diff/test_spsa_gradient.py @@ -528,9 +528,10 @@ def test_independent_parameters(self): tapes, fn = spsa_grad( tape1, approx_order=1, strategy="forward", num_directions=n1, sampler_rng=rng ) - j1 = fn(dev.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) @@ -1037,10 +1038,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) @@ -1056,7 +1059,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.execute(tapes))) + jac = np.array(fn(execute_fn(tapes))) if sampler is coordinate_sampler: jac *= 2 return jac @@ -1073,10 +1076,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) @@ -1093,7 +1098,7 @@ def cost_fn(x): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.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] @@ -1105,12 +1110,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) @@ -1126,7 +1133,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.execute(tapes)) + jac_0, jac_1 = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac_0 *= 2 jac_1 *= 2 @@ -1146,12 +1153,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) @@ -1169,7 +1178,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.execute(tapes))[1][0] + jac_01 = fn(execute_fn(tapes))[1][0] if sampler is coordinate_sampler: jac_01 *= 2 @@ -1182,12 +1191,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) @@ -1202,7 +1213,7 @@ def cost_fn(params): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.execute(tapes)) + jac = fn(execute_fn(tapes)) if sampler is coordinate_sampler: jac = tuple(2 * _jac for _jac in jac) return jac @@ -1222,7 +1233,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 @@ -1231,7 +1243,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) @@ -1247,7 +1260,7 @@ def cost_fn(x): tapes, fn = spsa_grad( tape, n=1, num_directions=num_directions, sampler=sampler, sampler_rng=rng ) - jac = fn(dev.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 660a82773bf..bdb9b232dde 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py +++ b/tests/gradients/finite_diff/test_spsa_gradient_shot_vec.py @@ -409,9 +409,10 @@ def test_independent_parameters(self): h=h_val, sampler_rng=rng, ) - j1 = fn(dev.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( @@ -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.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.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.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.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.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.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac all_res = jax.jacobian(cost_fn)(params) diff --git a/tests/gradients/parameter_shift/test_parameter_shift.py b/tests/gradients/parameter_shift/test_parameter_shift.py index 4a414191706..4071acc8716 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift.py +++ b/tests/gradients/parameter_shift/test_parameter_shift.py @@ -825,12 +825,13 @@ def test_independent_parameters_analytic(self): tape2 = qml.tape.QuantumScript.from_queue(q2) tapes, fn = qml.gradients.param_shift(tape1) - j1 = fn(dev.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.execute(tapes)) @@ -1080,12 +1081,13 @@ 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.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.execute(tapes)) @@ -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.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.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.execute(tapes)) + res = fn(execute_fn(tapes)) assert isinstance(res, tuple) assert res[0].shape == () @@ -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.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.execute(tapes)) + res = fn(execute_fn(tapes)) assert len(res) == 2 assert res[0].shape == () assert res[1].shape == () @@ -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.execute(tapes)) + jac = fn(execute_fn(tapes)) return jac res = qml.jacobian(cost_fn)(params) @@ -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.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( From 8c15eeae1fe599e92a51ae28e5f4458e7643f2b1 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 18 Aug 2023 17:04:17 -0400 Subject: [PATCH 21/78] rename measurement test devices; copy for new device api --- tests/interfaces/test_autograd.py | 2 +- .../test_classical_shadow_default_qubit_2.py | 763 +++++++++++++++ .../test_counts_default_qubit_2.py | 803 ++++++++++++++++ .../test_expval_default_qubit_2.py | 238 +++++ .../test_measurements_default_qubit_2.py | 614 ++++++++++++ .../test_mid_measure_default_qubit_2.py | 471 ++++++++++ .../test_mutual_info_default_qubit_2.py | 479 ++++++++++ .../test_probs_default_qubit_2.py | 710 ++++++++++++++ ...test_purity_measurement_default_qubit_2.py | 380 ++++++++ .../test_sample_default_qubit_2.py | 441 +++++++++ .../test_shots_default_qubit_2.py | 252 +++++ .../test_state_default_qubit_2.py | 888 ++++++++++++++++++ .../test_var_default_qubit_2.py | 184 ++++ .../test_vn_entropy_default_qubit_2.py | 419 +++++++++ tests/measurements/test_classical_shadow.py | 38 +- tests/measurements/test_counts.py | 56 +- tests/measurements/test_expval.py | 14 +- tests/measurements/test_measurements.py | 22 +- tests/measurements/test_mutual_info.py | 30 +- tests/measurements/test_probs.py | 44 +- tests/measurements/test_purity_measurement.py | 6 +- tests/measurements/test_sample.py | 36 +- tests/measurements/test_state.py | 64 +- tests/measurements/test_var.py | 14 +- tests/measurements/test_vn_entropy.py | 22 +- 25 files changed, 6816 insertions(+), 174 deletions(-) create mode 100644 tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py create mode 100644 tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py diff --git a/tests/interfaces/test_autograd.py b/tests/interfaces/test_autograd.py index e93e7ce8037..6732eb9316b 100644 --- a/tests/interfaces/test_autograd.py +++ b/tests/interfaces/test_autograd.py @@ -1056,7 +1056,7 @@ def cost_fn(x): def test_max_diff(self, tol): """Test that setting the max_diff parameter blocks higher-order derivatives""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = np.array([0.543, -0.654], requires_grad=True) def cost_fn(x): diff --git a/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py new file mode 100644 index 00000000000..8b523526b40 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py @@ -0,0 +1,763 @@ +# 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 classical shadows measurement processes""" + +import copy + +import autograd.numpy +import pytest + +import pennylane as qml +from pennylane import numpy as np +from pennylane.measurements import ClassicalShadowMP, Shots +from pennylane.measurements.classical_shadow import ShadowExpvalMP + +# pylint: disable=dangerous-default-value, too-many-arguments, comparison-with-callable, no-member + + +def get_circuit(wires, shots, seed_recipes, interface="autograd", device="default.qubit"): + """ + Return a QNode that prepares the state (|00...0> + |11...1>) / sqrt(2) + and performs the classical shadow measurement + """ + if device is not None: + dev = qml.device(device, wires=wires, shots=shots) + else: + dev = qml.device("default.qubit", wires=wires, shots=shots) + + # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) + dev.classical_shadow = super(type(dev), dev).classical_shadow + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.Hadamard(wires=0) + + for target in range(1, wires): + qml.CNOT(wires=[0, target]) + + return qml.classical_shadow(wires=range(wires), seed=seed_recipes) + + return circuit + + +def get_x_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): + """ + Return a QNode that prepares the |++..+> state and performs a classical shadow measurement + """ + if device is not None: + dev = qml.device(device, wires=wires, shots=shots) + else: + dev = qml.device("default.qubit", wires=wires, shots=shots) + + # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) + dev.classical_shadow = super(type(dev), dev).classical_shadow + + @qml.qnode(dev, interface=interface) + def circuit(): + for wire in range(wires): + qml.Hadamard(wire) + return qml.classical_shadow(wires=range(wires)) + + return circuit + + +def get_y_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): + """ + Return a QNode that prepares the |+i>|+i>...|+i> state and performs a classical shadow measurement + """ + if device is not None: + dev = qml.device(device, wires=wires, shots=shots) + else: + dev = qml.device("default.qubit", wires=wires, shots=shots) + + # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) + dev.classical_shadow = super(type(dev), dev).classical_shadow + + @qml.qnode(dev, interface=interface) + def circuit(): + for wire in range(wires): + qml.Hadamard(wire) + qml.RZ(np.pi / 2, wire) + return qml.classical_shadow(wires=range(wires)) + + return circuit + + +def get_z_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): + """ + Return a QNode that prepares the |00..0> state and performs a classical shadow measurement + """ + if device is not None: + dev = qml.device(device, wires=wires, shots=shots) + else: + dev = qml.device("default.qubit", wires=wires, shots=shots) + + # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) + dev.classical_shadow = super(type(dev), dev).classical_shadow + + @qml.qnode(dev, interface=interface) + def circuit(): + return qml.classical_shadow(wires=range(wires)) + + return circuit + + +wires_list = [1, 3] + + +class TestProcessState: + """Unit tests for process_state_with_shots for the classical_shadow + and shadow_expval measurements""" + + def test_shape_and_dtype(self): + """Test that the shape and dtype of the measurement is correct""" + mp = qml.classical_shadow(wires=[0, 1]) + res = mp.process_state_with_shots(np.ones((2, 2)) / 2, qml.wires.Wires([0, 1]), shots=100) + + assert res.shape == (2, 100, 2) + assert res.dtype == np.int8 + + # test that the bits are either 0 and 1 + assert np.all(np.logical_or(res[0] == 0, res[0] == 1)) + + # test that the recipes are either 0, 1, or 2 (X, Y, or Z) + assert np.all(np.logical_or(np.logical_or(res[1] == 0, res[1] == 1), res[1] == 2)) + + def test_wire_order(self): + """Test that the wire order is respected""" + state = np.array([[1, 1], [0, 0]]) / np.sqrt(2) + + mp = qml.classical_shadow(wires=[0, 1]) + res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000) + + assert res.shape == (2, 1000, 2) + assert res.dtype == np.int8 + + # test that the first qubit samples are all 0s when the recipe is Z + assert np.all(res[0][res[1, ..., 0] == 2][:, 0] == 0) + + # test that the second qubit samples contain 1s when the recipe is Z + assert np.any(res[0][res[1, ..., 1] == 2][:, 1] == 1) + + res = mp.process_state_with_shots(state, qml.wires.Wires([1, 0]), shots=1000) + + assert res.shape == (2, 1000, 2) + assert res.dtype == np.int8 + + # now test that the first qubit samples contain 1s when the recipe is Z + assert np.any(res[0][res[1, ..., 0] == 2][:, 0] == 1) + + # now test that the second qubit samples are all 0s when the recipe is Z + assert np.all(res[0][res[1, ..., 1] == 2][:, 1] == 0) + + def test_subset_wires(self): + """Test that the measurement is correct when only a subset of wires is measured""" + mp = qml.classical_shadow(wires=[0, 1]) + + # GHZ state + state = np.zeros((2, 2, 2)) + state[np.array([0, 1]), np.array([0, 1]), np.array([0, 1])] = 1 / np.sqrt(2) + + res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) + + assert res.shape == (2, 100, 2) + assert res.dtype == np.int8 + + # test that the bits are either 0 and 1 + assert np.all(np.logical_or(res[0] == 0, res[0] == 1)) + + # test that the recipes are either 0, 1, or 2 (X, Y, or Z) + assert np.all(np.logical_or(np.logical_or(res[1] == 0, res[1] == 1), res[1] == 2)) + + def test_same_rng(self): + """Test results when the rng is the same""" + state = np.ones((2, 2)) / 2 + + mp1 = qml.classical_shadow(wires=[0, 1], seed=123) + mp2 = qml.classical_shadow(wires=[0, 1], seed=123) + + res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) + res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) + + # test recipes are the same but bits are different + assert np.all(res1[1] == res2[1]) + assert np.any(res1[0] != res2[0]) + + res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100, rng=456) + res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100, rng=456) + + # now test everything is the same + assert np.all(res1[1] == res2[1]) + assert np.all(res1[0] == res2[0]) + + def test_expval_shape_and_val(self): + """Test that shadow expval measurements work as expected""" + mp = qml.shadow_expval(qml.PauliX(0) @ qml.PauliX(1), seed=200) + res = mp.process_state_with_shots( + np.ones((2, 2)) / 2, qml.wires.Wires([0, 1]), shots=1000, rng=100 + ) + + assert res.shape == () + assert np.allclose(res, 1.0, atol=0.05) + + def test_expval_wire_order(self): + """Test that shadow expval respects the wire order""" + state = np.array([[1, 1], [0, 0]]) / np.sqrt(2) + + mp = qml.shadow_expval(qml.PauliZ(0), seed=200) + res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=3000, rng=100) + + assert res.shape == () + assert np.allclose(res, 1.0, atol=0.05) + + res = mp.process_state_with_shots(state, qml.wires.Wires([1, 0]), shots=3000, rng=100) + + assert res.shape == () + assert np.allclose(res, 0.0, atol=0.05) + + def test_expval_same_rng(self): + """Test expval results when the rng is the same""" + state = np.ones((2, 2)) / 2 + + mp1 = qml.shadow_expval(qml.PauliZ(0) @ qml.PauliZ(1), seed=123) + mp2 = qml.shadow_expval(qml.PauliZ(0) @ qml.PauliZ(1), seed=123) + + res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=100) + res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=200) + + # test results are different + assert res1 != res2 + + res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=456) + res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=456) + + # now test that results are the same + assert res1 == res2 + + +@pytest.mark.parametrize("wires", wires_list) +class TestClassicalShadow: + """Unit tests for classical_shadow measurement""" + + shots_list = [1, 100] + seed_recipes_list = [None, 74] # random seed + + @pytest.mark.parametrize("seed", seed_recipes_list) + def test_measurement_process_numeric_type(self, wires, seed): + """Test that the numeric type of the MeasurementProcess instance is correct""" + res = qml.classical_shadow(wires=range(wires), seed=seed) + assert res.numeric_type == int + + @pytest.mark.parametrize("shots", shots_list) + @pytest.mark.parametrize("seed", seed_recipes_list) + def test_measurement_process_shape(self, wires, shots, seed): + """Test that the shape of the MeasurementProcess instance is correct""" + dev = qml.device("default.qubit", wires=wires, shots=shots) + shots_obj = Shots(shots) + res = qml.classical_shadow(wires=range(wires), seed=seed) + assert res.shape(dev, shots_obj) == (2, shots, wires) + + # test an error is raised when device is None + msg = "Shots must be specified to obtain the shape of a classical shadow measurement" + with pytest.raises(qml.measurements.MeasurementShapeError, match=msg): + res.shape(dev, Shots(None)) + + def test_shape_matches(self, wires): + """Test that the shape of the MeasurementProcess matches the shape + of the tape execution""" + shots = 100 + + circuit = get_circuit(wires, shots, True) + circuit.construct((), {}) + + res = qml.execute([circuit.tape], circuit.device, None)[0] + expected_shape = qml.classical_shadow(wires=range(wires)).shape( + circuit.device, Shots(shots) + ) + + assert res.shape == expected_shape + + @pytest.mark.parametrize("seed", seed_recipes_list) + def test_measurement_process_copy(self, wires, seed): + """Test that the attributes of the MeasurementProcess instance are + correctly copied""" + res = qml.classical_shadow(wires=range(wires), seed=seed) + + copied_res = copy.copy(res) + assert isinstance(copied_res, ClassicalShadowMP) + assert copied_res.return_type == res.return_type + assert copied_res.wires == res.wires + assert copied_res.seed == res.seed + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("shots", shots_list) + @pytest.mark.parametrize("seed", seed_recipes_list) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", None]) + def test_format(self, wires, shots, seed, interface, device): + """Test that the format of the returned classical shadow + measurement is correct""" + import tensorflow as tf + import torch + + circuit = get_circuit(wires, shots, seed, interface, device) + shadow = circuit() + + # test shape is correct + assert shadow.shape == (2, shots, wires) + + # test dtype is correct + expected_dtype = np.int8 + if interface == "tf": + expected_dtype = tf.int8 + elif interface == "torch": + expected_dtype = torch.int8 + + assert shadow.dtype == expected_dtype + + bits, recipes = shadow # pylint: disable=unpacking-non-sequence + + # test allowed values of bits and recipes + assert qml.math.all(np.logical_or(bits == 0, bits == 1)) + assert qml.math.all(np.logical_or(recipes == 0, np.logical_or(recipes == 1, recipes == 2))) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) + @pytest.mark.parametrize("device", ["default.qubit", None]) + @pytest.mark.parametrize( + "circuit_fn, basis_recipe", + [(get_x_basis_circuit, 0), (get_y_basis_circuit, 1), (get_z_basis_circuit, 2)], + ) + def test_return_distribution(self, wires, interface, device, circuit_fn, basis_recipe): + """Test that the distribution of the bits and recipes are correct for a circuit + that prepares all qubits in a Pauli basis""" + # high number of shots to prevent true negatives + np.random.seed(42) + shots = 1000 + + circuit = circuit_fn(wires, shots=shots, interface=interface, device=device) + bits, recipes = circuit() + new_bits, new_recipes = circuit.tape.measurements[0].process(circuit.tape, circuit.device) + + # test that the recipes follow a rough uniform distribution + ratios = np.unique(recipes, return_counts=True)[1] / (wires * shots) + assert np.allclose(ratios, 1 / 3, atol=1e-1) + new_ratios = np.unique(new_recipes, return_counts=True)[1] / (wires * shots) + assert np.allclose(new_ratios, 1 / 3, atol=1e-1) + + # test that the bit is 0 for all X measurements + assert qml.math.allequal(bits[recipes == basis_recipe], 0) + assert qml.math.allequal(new_bits[new_recipes == basis_recipe], 0) + + # test that the bits are uniformly distributed for all Y and Z measurements + bits1 = bits[recipes == (basis_recipe + 1) % 3] + ratios1 = np.unique(bits1, return_counts=True)[1] / bits1.shape[0] + assert np.allclose(ratios1, 1 / 2, atol=1e-1) + new_bits1 = new_bits[new_recipes == (basis_recipe + 1) % 3] + new_ratios1 = np.unique(new_bits1, return_counts=True)[1] / new_bits1.shape[0] + assert np.allclose(new_ratios1, 1 / 2, atol=1e-1) + + bits2 = bits[recipes == (basis_recipe + 2) % 3] + ratios2 = np.unique(bits2, return_counts=True)[1] / bits2.shape[0] + assert np.allclose(ratios2, 1 / 2, atol=1e-1) + + new_bits2 = new_bits[new_recipes == (basis_recipe + 2) % 3] + new_ratios2 = np.unique(new_bits2, return_counts=True)[1] / new_bits2.shape[0] + assert np.allclose(new_ratios2, 1 / 2, atol=1e-1) + + @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 + to obtain classical shadows""" + circuit = get_circuit(wires, None, seed) + + msg = "The number of shots has to be explicitly set on the device when using sample-based measurements" + with pytest.raises(qml.QuantumFunctionError, match=msg): + circuit() + + @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 + with other measurement processes""" + dev = qml.device("default.qubit", wires=wires, shots=shots) + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + + for target in range(1, wires): + qml.CNOT(wires=[0, target]) + + return qml.classical_shadow(wires=range(wires)), 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() + + +def hadamard_circuit(wires, shots=10000, interface="autograd"): + dev = qml.device("default.qubit", wires=wires, shots=shots) + + @qml.qnode(dev, interface=interface) + def circuit(obs, k=1): + for i in range(wires): + qml.Hadamard(wires=i) + return qml.shadow_expval(obs, k=k) + + return circuit + + +def max_entangled_circuit(wires, shots=10000, interface="autograd"): + dev = qml.device("default.qubit", wires=wires, shots=shots) + + @qml.qnode(dev, interface=interface) + def circuit(obs, k=1): + qml.Hadamard(wires=0) + for i in range(1, wires): + qml.CNOT(wires=[0, i]) + return qml.shadow_expval(obs, k=k) + + return circuit + + +def qft_circuit(wires, shots=10000, interface="autograd"): + dev = qml.device("default.qubit", wires=wires, shots=shots) + + one_state = np.zeros(wires) + one_state[-1] = 1 + + @qml.qnode(dev, interface=interface) + def circuit(obs, k=1): + qml.BasisState(one_state, wires=range(wires)) + qml.QFT(wires=range(wires)) + return qml.shadow_expval(obs, k=k) + + return circuit + + +@pytest.mark.autograd +class TestExpvalMeasurement: + def test_measurement_process_numeric_type(self): + """Test that the numeric type of the MeasurementProcess instance is correct""" + H = qml.PauliZ(0) + res = qml.shadow_expval(H) + assert res.numeric_type == float + + @pytest.mark.parametrize("wires", [1, 2]) + @pytest.mark.parametrize("shots", [1, 10]) + def test_measurement_process_shape(self, wires, shots): + """Test that the shape of the MeasurementProcess instance is correct""" + dev = qml.device("default.qubit", wires=wires, shots=shots) + H = qml.PauliZ(0) + res = qml.shadow_expval(H) + assert len(res.shape(dev, Shots(shots))) == 0 + + def test_shape_matches(self): + """Test that the shape of the MeasurementProcess matches the shape + of the tape execution""" + wires = 2 + shots = 100 + H = qml.PauliZ(0) + + circuit = hadamard_circuit(wires, shots) + circuit.construct((H,), {}) + + res = qml.execute([circuit.tape], circuit.device, None)[0] + expected_shape = qml.shadow_expval(H).shape(circuit.device, Shots(shots)) + + assert res.shape == expected_shape + + def test_measurement_process_copy(self): + """Test that the attributes of the MeasurementProcess instance are + correctly copied""" + H = qml.PauliZ(0) + res = qml.shadow_expval(H, k=10) + + copied_res = copy.copy(res) + assert type(copied_res) == type(res) # pylint: disable=unidiomatic-typecheck + assert copied_res.return_type == res.return_type + assert qml.equal(copied_res.H, res.H) + assert copied_res.k == res.k + assert copied_res.seed == res.seed + + def test_shots_none_error(self): + """Test that an error is raised when a device with shots=None is used + to obtain classical shadows""" + circuit = hadamard_circuit(2, None) + H = qml.PauliZ(0) + + msg = "The number of shots has to be explicitly set on the device when using sample-based measurements" + with pytest.raises(qml.QuantumFunctionError, match=msg): + _ = circuit(H, k=10) + + def test_multi_measurement_error(self): + """Test that an error is raised when classical shadows is returned + with other measurement processes""" + dev = qml.device("default.qubit", wires=2, shots=100) + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + return qml.shadow_expval(qml.PauliZ(0)), 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() + + def test_obs_not_queued(self): + """Test that the observable passed to qml.shadow_expval is not queued""" + with qml.queuing.AnnotatedQueue() as q: + qml.PauliY(0) + qml.shadow_expval(qml.PauliZ(0)) + + tape = qml.tape.QuantumScript.from_queue(q) + assert len(tape.operations) == 1 + assert tape.operations[0].name == "PauliY" + assert len(tape.measurements) == 1 + assert isinstance(tape.measurements[0], ShadowExpvalMP) + + +obs_hadamard = [ + qml.PauliX(1), + qml.PauliX(0) @ qml.PauliX(2), + qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), + qml.PauliY(2), + qml.PauliY(1) @ qml.PauliZ(2), + qml.PauliX(0) @ qml.PauliY(1), + qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), +] +expected_hadamard = [1, 1, 1, 0, 0, 0, 0] + +obs_max_entangled = [ + qml.PauliX(1), + qml.PauliX(0) @ qml.PauliX(2), + qml.PauliZ(2), + qml.Identity(1) @ qml.PauliZ(2), + qml.PauliZ(1) @ qml.PauliZ(2), + qml.PauliX(0) @ qml.PauliY(1), + qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), + qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliY(2), +] +expected_max_entangled = [0, 0, 0, 0, 1, 0, 0, -1] + +obs_qft = [ + qml.PauliX(0), + qml.PauliX(0) @ qml.PauliX(1), + qml.PauliX(0) @ qml.PauliX(2), + qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), + qml.PauliZ(2), + qml.PauliX(1) @ qml.PauliY(2), + qml.PauliY(1) @ qml.PauliX(2), + qml.Identity(0) @ qml.PauliY(1) @ qml.PauliX(2), + qml.PauliX(0) @ qml.PauliY(1) @ qml.PauliY(2), + qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliX(2), +] +expected_qft = [ + -1, + 0, + -1 / np.sqrt(2), + -1 / np.sqrt(2), + 0, + 0, + 1 / np.sqrt(2), + 1 / np.sqrt(2), + -1 / np.sqrt(2), + 0, +] + + +@pytest.mark.autograd +class TestExpvalForward: + """Test the shadow_expval measurement process forward pass""" + + def test_hadamard_expval(self, k=1, obs=obs_hadamard, expected=expected_hadamard): + """Test that the expval estimation is correct for a uniform + superposition of qubits""" + circuit = hadamard_circuit(3, shots=100000) + actual = circuit(obs, k=k) + new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) + + assert actual.shape == (len(obs_hadamard),) + assert actual.dtype == np.float64 + assert qml.math.allclose(actual, expected, atol=1e-1) + assert qml.math.allclose(new_actual, expected, atol=1e-1) + + def test_max_entangled_expval( + self, k=1, obs=obs_max_entangled, expected=expected_max_entangled + ): + """Test that the expval estimation is correct for a maximally + entangled state""" + circuit = max_entangled_circuit(3, shots=100000) + actual = circuit(obs, k=k) + new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) + + assert actual.shape == (len(obs_max_entangled),) + assert actual.dtype == np.float64 + assert qml.math.allclose(actual, expected, atol=1e-1) + assert qml.math.allclose(new_actual, expected, atol=1e-1) + + def test_non_pauli_error(self): + """Test that an error is raised when a non-Pauli observable is passed""" + circuit = hadamard_circuit(3) + + msg = "Observable must be a linear combination of Pauli observables" + with pytest.raises(ValueError, match=msg): + circuit(qml.Hadamard(0) @ qml.Hadamard(2)) + + +# pylint: disable=too-few-public-methods +@pytest.mark.all_interfaces +class TestExpvalForwardInterfaces: + @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) + def test_qft_expval(self, interface, k=1, obs=obs_qft, expected=expected_qft): + """Test that the expval estimation is correct for a QFT state""" + import torch + + circuit = qft_circuit(3, shots=100000, interface=interface) + actual = circuit(obs, k=k) + new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) + + assert actual.shape == (len(obs_qft),) + assert actual.dtype == torch.float64 if interface == "torch" else np.float64 + assert qml.math.allclose(actual, expected, atol=1e-1) + assert qml.math.allclose(new_actual, expected, atol=1e-1) + + +obs_strongly_entangled = [ + qml.PauliX(1), + qml.PauliX(0) @ qml.PauliX(2), + qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), + qml.PauliY(2), + qml.PauliY(1) @ qml.PauliZ(2), + qml.PauliX(0) @ qml.PauliY(1), + qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), +] + + +def strongly_entangling_circuit(wires, shots=10000, interface="autograd"): + dev = qml.device("default.qubit", wires=wires, shots=shots) + + @qml.qnode(dev, interface=interface) + def circuit(x, obs, k): + qml.StronglyEntanglingLayers(weights=x, wires=range(wires)) + return qml.shadow_expval(obs, k=k) + + return circuit + + +def strongly_entangling_circuit_exact(wires, interface="autograd"): + dev = qml.device("default.qubit", wires=wires) + + @qml.qnode(dev, interface=interface) + def circuit(x, obs): + qml.StronglyEntanglingLayers(weights=x, wires=range(wires)) + return [qml.expval(o) for o in obs] + + return circuit + + +class TestExpvalBackward: + """Test the shadow_expval measurement process backward pass""" + + @pytest.mark.autograd + def test_backward_autograd(self, obs=obs_strongly_entangled): + """Test that the gradient of the expval estimation is correct for + the autograd interface""" + shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="autograd") + exact_circuit = strongly_entangling_circuit_exact(3, "autograd") + + def cost_exact(x, obs): + return autograd.numpy.hstack(exact_circuit(x, obs)) + + # make rotations close to pi / 2 to ensure gradients are not too small + x = np.random.uniform( + 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) + ) + actual = qml.jacobian(shadow_circuit)(x, obs, k=1) + expected = qml.jacobian(cost_exact, argnum=0)(x, obs) + + assert qml.math.allclose(actual, expected, atol=1e-1) + + @pytest.mark.jax + def test_backward_jax(self, obs=obs_strongly_entangled): + """Test that the gradient of the expval estimation is correct for + the jax interface""" + import jax + from jax import numpy as jnp + + shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="jax") + exact_circuit = strongly_entangling_circuit_exact(3, "jax") + + # make rotations close to pi / 2 to ensure gradients are not too small + x = jnp.array( + np.random.uniform( + 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) + ) + ) + + actual = jax.jacrev(shadow_circuit)(x, obs, k=1) + expected = jax.jacrev(exact_circuit)(x, obs) + + assert qml.math.allclose(actual, expected, atol=1e-1) + + @pytest.mark.tf + def test_backward_tf(self, obs=obs_strongly_entangled): + """Test that the gradient of the expval estimation is correct for + the tensorflow interface""" + import tensorflow as tf + + shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="tf") + exact_circuit = strongly_entangling_circuit_exact(3, "tf") + + # make rotations close to pi / 2 to ensure gradients are not too small + x = tf.Variable( + np.random.uniform( + 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) + ) + ) + + with tf.GradientTape() as tape: + out = shadow_circuit(x, obs, k=10) + + actual = tape.jacobian(out, x) + + with tf.GradientTape() as tape2: + out2 = qml.math.hstack(exact_circuit(x, obs)) + + expected = tape2.jacobian(out2, x) + + assert qml.math.allclose(actual, expected, atol=1e-1) + + @pytest.mark.torch + def test_backward_torch(self, obs=obs_strongly_entangled): + """Test that the gradient of the expval estimation is correct for + the pytorch interface""" + import torch + + shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="torch") + exact_circuit = strongly_entangling_circuit_exact(3, "torch") + + # make rotations close to pi / 2 to ensure gradients are not too small + x = torch.tensor( + np.random.uniform( + 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) + ), + requires_grad=True, + ) + + actual = torch.autograd.functional.jacobian(lambda x: shadow_circuit(x, obs, k=10), x) + expected = torch.autograd.functional.jacobian(lambda x: tuple(exact_circuit(x, obs)), x) + + assert qml.math.allclose(actual, qml.math.stack(expected), atol=1e-1) diff --git a/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py new file mode 100644 index 00000000000..eeee4a24e5f --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py @@ -0,0 +1,803 @@ +# Copyright 2018-2023 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. +"""Tests for the qml.counts measurement process.""" +import copy +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import AllCounts, Counts, CountsMP +from pennylane.operation import Operator +from pennylane.wires import Wires + + +# TODO: Remove this when new CustomMP are the default +def custom_measurement_process(device, spy): + assert len(spy.call_args_list) > 0 # make sure method is mocked properly + + samples = device._samples # pylint:disable=protected-access + call_args_list = list(spy.call_args_list) + for call_args in call_args_list: + if not call_args.kwargs.get("counts", False): + continue + meas = call_args.args[1] + shot_range, bin_size = (call_args.kwargs["shot_range"], call_args.kwargs["bin_size"]) + if isinstance(meas, Operator): + all_outcomes = meas.return_type is AllCounts + meas = qml.counts(op=meas, all_outcomes=all_outcomes) + old_res = device.sample(call_args.args[1], **call_args.kwargs) + new_res = meas.process_samples( + samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size + ) + if isinstance(old_res, dict): + old_res = [old_res] + new_res = [new_res] + for old, new in zip(old_res, new_res): + assert old.keys() == new.keys() + assert qml.math.allequal(list(old.values()), list(new.values())) + + +class TestCounts: + """Tests for the counts function""" + + def test_counts_properties(self): + """Test that the properties are correct.""" + meas1 = qml.counts(wires=0) + meas2 = qml.counts(op=qml.PauliX(0), all_outcomes=True) + assert meas1.samples_computational_basis is True + assert meas1.return_type == Counts + assert meas2.samples_computational_basis is False + assert meas2.return_type == AllCounts + + def test_queue(self): + """Test that the right measurement class is queued.""" + + with qml.queuing.AnnotatedQueue() as q: + op = qml.PauliX(0) + m = qml.counts(op) + + assert q.queue[0] is m + assert isinstance(m, CountsMP) + + def test_copy(self): + """Test that the ``__copy__`` method also copies the ``all_outcomes`` information.""" + meas = qml.counts(wires=0, all_outcomes=True) + meas_copy = copy.copy(meas) + assert meas_copy.wires == Wires(0) + assert meas_copy.all_outcomes is True + + def test_providing_observable_and_wires(self): + """Test that a ValueError is raised if both an observable is provided and wires are + specified""" + + with pytest.raises( + ValueError, + match="Cannot specify the wires to sample if an observable is provided." + " The wires to sample will be determined directly from the observable.", + ): + qml.counts(qml.PauliZ(0), wires=[0, 1]) + + def test_observable_might_not_be_hermitian(self): + """Test that a UserWarning is raised if the provided + argument might not be hermitian.""" + + with pytest.warns(UserWarning, match="Prod might not be hermitian."): + qml.counts(qml.prod(qml.PauliX(0), qml.PauliZ(0))) + + def test_hash(self): + """Test that the hash property includes the all_outcomes property.""" + m1 = qml.counts(all_outcomes=True) + m2 = qml.counts(all_outcomes=False) + + assert m1.hash != m2.hash + + m3 = CountsMP(eigvals=[0.5, -0.5], wires=qml.wires.Wires(0), all_outcomes=True) + assert m3.hash != m1.hash + + def test_repr(self): + """Test that the repr includes the all_outcomes property.""" + m1 = CountsMP(wires=Wires(0), all_outcomes=True) + assert repr(m1) == "CountsMP(wires=[0], all_outcomes=True)" + + m2 = CountsMP(obs=qml.PauliX(0), all_outcomes=True) + assert repr(m2) == "CountsMP(PauliX(wires=[0]), all_outcomes=True)" + + m3 = CountsMP(eigvals=(-1, 1), all_outcomes=False) + assert repr(m3) == "CountsMP(eigvals=[-1 1], wires=[], all_outcomes=False)" + + +class TestProcessSamples: + """Unit tests for the counts.process_samples method""" + + def test_counts_shape_single_wires(self): + """Test that the counts output is correct for single wires""" + shots = 1000 + samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) + + result = qml.counts(wires=0).process_samples(samples, wire_order=[0]) + + assert len(result) == 2 + assert set(result.keys()) == {"0", "1"} + assert result["0"] == np.count_nonzero(samples[:, 0] == 0) + assert result["1"] == np.count_nonzero(samples[:, 0] == 1) + + def test_counts_shape_multi_wires(self): + """Test that the counts function outputs counts of the right size + for multiple wires""" + shots = 1000 + samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) + + result = qml.counts(wires=[0, 1]).process_samples(samples, wire_order=[0, 1]) + + assert len(result) == 4 + assert set(result.keys()) == {"00", "01", "10", "11"} + assert result["00"] == np.count_nonzero( + np.logical_and(samples[:, 0] == 0, samples[:, 1] == 0) + ) + assert result["01"] == np.count_nonzero( + np.logical_and(samples[:, 0] == 0, samples[:, 1] == 1) + ) + assert result["10"] == np.count_nonzero( + np.logical_and(samples[:, 0] == 1, samples[:, 1] == 0) + ) + assert result["11"] == np.count_nonzero( + np.logical_and(samples[:, 0] == 1, samples[:, 1] == 1) + ) + + def test_counts_obs(self): + """Test that the counts function outputs counts of the right size for observables""" + shots = 1000 + samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) + + result = qml.counts(qml.PauliZ(0)).process_samples(samples, wire_order=[0]) + + assert len(result) == 2 + assert set(result.keys()) == {1, -1} + assert result[1] == np.count_nonzero(samples[:, 0] == 0) + assert result[-1] == np.count_nonzero(samples[:, 0] == 1) + + def test_counts_all_outcomes_wires(self): + """Test that the counts output is correct when all_outcomes is passed""" + shots = 1000 + samples = np.zeros((shots, 2)).astype(np.bool8) + + result1 = qml.counts(wires=0, all_outcomes=False).process_samples(samples, wire_order=[0]) + + assert len(result1) == 1 + assert set(result1.keys()) == {"0"} + assert result1["0"] == shots + + result2 = qml.counts(wires=0, all_outcomes=True).process_samples(samples, wire_order=[0]) + + assert len(result2) == 2 + assert set(result2.keys()) == {"0", "1"} + assert result2["0"] == shots + assert result2["1"] == 0 + + def test_counts_all_outcomes_obs(self): + """Test that the counts output is correct when all_outcomes is passed""" + shots = 1000 + samples = np.zeros((shots, 2)).astype(np.bool8) + + result1 = qml.counts(qml.PauliZ(0), all_outcomes=False).process_samples( + samples, wire_order=[0] + ) + + assert len(result1) == 1 + assert set(result1.keys()) == {1} + assert result1[1] == shots + + result2 = qml.counts(qml.PauliZ(0), all_outcomes=True).process_samples( + samples, wire_order=[0] + ) + + assert len(result2) == 2 + assert set(result2.keys()) == {1, -1} + assert result2[1] == shots + assert result2[-1] == 0 + + +class TestCountsIntegration: + # pylint:disable=too-many-public-methods,not-an-iterable + + def test_counts_dimension(self, mocker): + """Test that the counts function outputs counts of the right size""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=2, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.54, wires=0) + return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliX(1)) + + sample = circuit() + + assert len(sample) == 2 + assert np.all([sum(s.values()) == n_sample for s in sample]) + + custom_measurement_process(dev, spy) + + def test_batched_counts_dimension(self, mocker): + """Test that the counts function outputs counts of the right size with batching""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=2, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX([0.54, 0.65], wires=0) + return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliX(1)) + + sample = circuit() + + assert isinstance(sample, tuple) + assert len(sample) == 2 + assert np.all([sum(s.values()) == n_sample for batch in sample for s in batch]) + + custom_measurement_process(dev, spy) + + def test_counts_combination(self, mocker): + """Test the output of combining expval, var and counts""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=3, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(0.54, wires=0) + + return ( + qml.counts(qml.PauliZ(0)), + qml.expval(qml.PauliX(1)), + qml.var(qml.PauliY(2)), + ) + + result = circuit() + + assert len(result) == 3 + assert sum(result[0].values()) == n_sample + + custom_measurement_process(dev, spy) + + def test_single_wire_counts(self, mocker): + """Test the return type and shape of sampling counts from a single wire""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=1, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.54, wires=0) + + return qml.counts(qml.PauliZ(0)) + + result = circuit() + + assert isinstance(result, dict) + assert sum(result.values()) == n_sample + + custom_measurement_process(dev, spy) + + def test_multi_wire_counts_regular_shape(self, mocker): + """Test the return type and shape of sampling multiple wires + where a rectangular array is expected""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=3, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + return ( + qml.counts(qml.PauliZ(0)), + qml.counts(qml.PauliZ(1)), + qml.counts(qml.PauliZ(2)), + ) + + result = circuit() + + # If all the dimensions are equal the result will end up to be a proper rectangular array + assert isinstance(result, tuple) + assert len(result) == 3 + assert all(sum(r.values()) == n_sample for r in result) + assert all(all(v.dtype == np.dtype("int") for v in r.values()) for r in result) + + custom_measurement_process(dev, spy) + + def test_observable_return_type_is_counts(self): + """Test that the return type of the observable is :attr:`ObservableReturnTypes.Counts`""" + n_shots = 10 + dev = qml.device("default.qubit", wires=1, shots=n_shots) + + @qml.qnode(dev) + def circuit(): + res = qml.counts(qml.PauliZ(0)) + return res + + circuit() + assert circuit._qfunc_output.return_type is Counts # pylint: disable=protected-access + + def test_providing_no_observable_and_no_wires_counts(self, mocker): + """Test that we can provide no observable and no wires to sample function""" + dev = qml.device("default.qubit", wires=2, shots=1000) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + res = qml.counts() + assert res.obs is None + assert res.wires == qml.wires.Wires([]) + return res + + circuit() + + custom_measurement_process(dev, spy) + + def test_providing_no_observable_and_wires_counts(self, mocker): + """Test that we can provide no observable but specify wires to the sample function""" + wires = [0, 2] + wires_obj = qml.wires.Wires(wires) + dev = qml.device("default.qubit", wires=3, shots=1000) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + res = qml.counts(wires=wires) + + assert res.obs is None + assert res.wires == wires_obj + return res + + circuit() + + custom_measurement_process(dev, spy) + + def test_batched_counts_work_individually(self, mocker): + """Test that each counts call operates independently""" + n_shots = 10 + dev = qml.device("default.qubit", wires=1, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.pow(qml.PauliX(0), z=[1, 2]) + return qml.counts() + + assert circuit() == [{"1": 10}, {"0": 10}] + custom_measurement_process(dev, spy) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + def test_counts_no_op_finite_shots(self, interface, wires, basis_state, mocker): + """Check all interfaces with computational basis state counts and + finite shot""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.PauliX(1) + return qml.counts(wires=wires) + + res = circuit() + assert res == {basis_state: n_shots} + assert qml.math.get_interface(res[basis_state]) == interface + + custom_measurement_process(dev, spy) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + def test_counts_operator_finite_shots(self, interface, mocker): + """Check all interfaces with observable measurement counts and finite + shot""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + return qml.counts(qml.PauliZ(0)) + + res = circuit() + assert res == {1: n_shots} + + custom_measurement_process(dev, spy) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) + @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + def test_counts_binned( + self, shot_vec, interface, wires, basis_state, mocker + ): # pylint:disable=too-many-arguments + """Check all interfaces with computational basis state counts and + different shot vectors""" + dev = qml.device("default.qubit", wires=3, shots=shot_vec) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.PauliX(1) + return qml.counts(wires=wires) + + res = circuit() + + assert isinstance(res, tuple) + assert res[0] == {basis_state: shot_vec[0]} + assert res[1] == {basis_state: shot_vec[1]} + assert res[2] == {basis_state: shot_vec[2]} + assert len(res) == len(shot_vec) + assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) + + custom_measurement_process(dev, spy) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + def test_counts_operator_binned(self, shot_vec, interface, mocker): + """Check all interfaces with observable measurement counts and different + shot vectors""" + dev = qml.device("default.qubit", wires=3, shots=shot_vec) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + return qml.counts(qml.PauliZ(0)) + + res = circuit() + + assert isinstance(res, tuple) + assert res[0] == {1: shot_vec[0]} + assert res[1] == {1: shot_vec[1]} + assert res[2] == {1: shot_vec[2]} + assert len(res) == len(shot_vec) + assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) + def test_counts_binned_4_wires(self, shot_vec, mocker): + """Check the autograd interface with computational basis state counts and + different shot vectors on a device with 4 wires""" + dev = qml.device("default.qubit", wires=4, shots=shot_vec) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface="autograd") + def circuit(): + qml.PauliX(1) + qml.PauliX(2) + qml.PauliX(3) + return qml.counts() + + res = circuit() + basis_state = "0111" + + assert isinstance(res, tuple) + assert res[0][basis_state] == shot_vec[0] + assert res[1][basis_state] == shot_vec[1] + assert res[2][basis_state] == shot_vec[2] + assert len(res) == len(shot_vec) + assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) + def test_counts_operator_binned_4_wires(self, shot_vec, mocker): + """Check the autograd interface with observable samples to obtain + counts from and different shot vectors on a device with 4 wires""" + dev = qml.device("default.qubit", wires=4, shots=shot_vec) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface="autograd") + def circuit(): + qml.PauliX(1) + qml.PauliX(2) + qml.PauliX(3) + return qml.counts(qml.PauliZ(0)) + + res = circuit() + sample = 1 + + assert isinstance(res, tuple) + assert res[0][sample] == shot_vec[0] + assert res[1][sample] == shot_vec[1] + assert res[2][sample] == shot_vec[2] + assert len(res) == len(shot_vec) + assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) + + custom_measurement_process(dev, spy) + + meas2 = [ + qml.expval(qml.PauliZ(0)), + qml.var(qml.PauliZ(0)), + qml.probs(wires=[1, 0]), + qml.sample(wires=1), + ] + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + @pytest.mark.parametrize("meas2", meas2) + @pytest.mark.parametrize("shots", [1000, (1, 10)]) + def test_counts_observable_finite_shots(self, interface, meas2, shots, mocker): + """Check all interfaces with observable measurement counts and finite + shot""" + dev = qml.device("default.qubit", wires=3, shots=shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + if isinstance(shots, tuple) and interface == "torch": + pytest.skip("Torch needs to be updated for shot vectors.") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.PauliX(0) + return qml.counts(wires=0), qml.apply(meas2) + + res = circuit() + assert isinstance(res, tuple) + + num_shot_bins = 1 if isinstance(shots, int) else len(shots) + + if num_shot_bins == 1: + counts_term_indices = [i * 2 for i in range(num_shot_bins)] + for ind in counts_term_indices: + assert isinstance(res[ind], dict) + else: + assert len(res) == 2 + + assert isinstance(res[0], tuple) + assert isinstance(res[0][0], dict) + assert isinstance(res[1], tuple) + assert isinstance(res[1][0], dict) + + custom_measurement_process(dev, spy) + + def test_all_outcomes_kwarg_providing_observable(self, mocker): + """Test that the dictionary keys *all* eigenvalues of the observable, + including 0 count values, if observable is given and all_outcomes=True""" + + n_shots = 10 + dev = qml.device("default.qubit", wires=1, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + res = qml.counts(qml.PauliZ(0), all_outcomes=True) + return res + + res = circuit() + + assert res == {1: n_shots, -1: 0} + + custom_measurement_process(dev, spy) + + def test_all_outcomes_kwarg_no_observable_no_wires(self, mocker): + """Test that the dictionary keys are *all* the possible combinations + of basis states for the device, including 0 count values, if no wire + count and no observable are given and all_outcomes=True""" + + n_shots = 10 + dev = qml.device("default.qubit", wires=2, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + return qml.counts(all_outcomes=True) + + res = circuit() + + assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} + + custom_measurement_process(dev, spy) + + def test_all_outcomes_kwarg_providing_wires_and_no_observable(self, mocker): + """Test that the dictionary keys are *all* possible combinations + of basis states for the specified wires, including 0 count values, + if wire count is given and all_outcomes=True""" + + n_shots = 10 + dev = qml.device("default.qubit", wires=4, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + return qml.counts(wires=[0, 2], all_outcomes=True) + + res = circuit() + + assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} + + custom_measurement_process(dev, spy) + + def test_all_outcomes_hermitian(self, mocker): + """Tests that the all_outcomes=True option for counts works with the + qml.Hermitian observable""" + + n_shots = 10 + dev = qml.device("default.qubit", wires=2, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + A = np.array([[1, 0], [0, -1]]) + + @qml.qnode(dev) + def circuit(x): + return qml.counts(qml.Hermitian(x, wires=0), all_outcomes=True) + + res = circuit(A) + + assert res == {-1.0: 0, 1.0: n_shots} + + custom_measurement_process(dev, spy) + + def test_all_outcomes_multiple_measurements(self, mocker): + """Tests that the all_outcomes=True option for counts works when + multiple measurements are performed""" + + dev = qml.device("default.qubit", wires=2, shots=10) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + return qml.sample(qml.PauliZ(0)), qml.counts(), qml.counts(all_outcomes=True) + + res = circuit() + + assert len(res[0]) == 10 + assert res[1] == {"00": 10} + assert res[2] == {"00": 10, "01": 0, "10": 0, "11": 0} + custom_measurement_process(dev, spy) + + def test_batched_all_outcomes(self, mocker): + """Tests that all_outcomes=True works with broadcasting.""" + n_shots = 10 + dev = qml.device("default.qubit", wires=1, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.pow(qml.PauliX(0), z=[1, 2]) + return qml.counts(qml.PauliZ(0), all_outcomes=True) + + assert circuit() == [{1: 0, -1: n_shots}, {1: n_shots, -1: 0}] + + custom_measurement_process(dev, spy) + + def test_counts_empty_wires(self): + """Test that using ``qml.counts`` with an empty wire list raises an error.""" + with pytest.raises(ValueError, match="Cannot set an empty list of wires."): + qml.counts(wires=[]) + + @pytest.mark.parametrize("shots", [1, 100]) + def test_counts_no_arguments(self, shots): + """Test that using ``qml.counts`` with no arguments returns the counts of all wires.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + + @qml.qnode(dev) + def circuit(): + return qml.counts() + + res = circuit() + + assert qml.math.allequal(res, {"000": shots}) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) +@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) +def test_counts_no_op_finite_shots(interface, wires, basis_state, mocker): + """Check all interfaces with computational basis state counts and finite shot""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.PauliX(1) + return qml.counts(wires=wires) + + res = circuit() + assert res == {basis_state: n_shots} + assert qml.math.get_interface(res[basis_state]) == interface + + custom_measurement_process(dev, spy) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) +@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) +def test_batched_counts_no_op_finite_shots(interface, wires, basis_states, mocker): + """Check all interfaces with computational basis state counts and + finite shot""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.pow(qml.PauliX(1), z=[1, 2]) + return qml.counts(wires=wires) + + assert circuit() == [{basis_state: n_shots} for basis_state in basis_states] + + custom_measurement_process(dev, spy) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) +@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) +def test_batched_counts_and_expval_no_op_finite_shots(interface, wires, basis_states, mocker): + """Check all interfaces with computational basis state counts and + finite shot""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.pow(qml.PauliX(1), z=[1, 2]) + return qml.counts(wires=wires), qml.expval(qml.PauliZ(0)) + + res = circuit() + assert isinstance(res, tuple) and len(res) == 2 + assert res[0] == [{basis_state: n_shots} for basis_state in basis_states] + assert len(res[1]) == 2 and qml.math.allequal(res[1], 1) + + custom_measurement_process(dev, spy) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) +def test_batched_counts_operator_finite_shots(interface, mocker): + """Check all interfaces with observable measurement counts, batching and finite shots""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.pow(qml.PauliX(0), z=[1, 2]) + return qml.counts(qml.PauliZ(0)) + + assert circuit() == [{-1: n_shots}, {1: n_shots}] + + custom_measurement_process(dev, spy) + + +@pytest.mark.all_interfaces +@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) +def test_batched_counts_and_expval_operator_finite_shots(interface, mocker): + """Check all interfaces with observable measurement counts, batching and finite shots""" + n_shots = 10 + dev = qml.device("default.qubit", wires=3, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.pow(qml.PauliX(0), z=[1, 2]) + return qml.counts(qml.PauliZ(0)), qml.expval(qml.PauliZ(0)) + + res = circuit() + assert isinstance(res, tuple) and len(res) == 2 + assert res[0] == [{-1: n_shots}, {1: n_shots}] + assert len(res[1]) == 2 and qml.math.allequal(res[1], [-1, 1]) + + custom_measurement_process(dev, spy) diff --git a/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py new file mode 100644 index 00000000000..3d0e5c009b2 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py @@ -0,0 +1,238 @@ +# Copyright 2018-2020 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 expval module""" +import copy +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import Expectation, Shots +from pennylane.measurements.expval import ExpectationMP + + +# TODO: Remove this when new CustomMP are the default +def custom_measurement_process(device, spy): + assert len(spy.call_args_list) > 0 # make sure method is mocked properly + + samples = device._samples # pylint: disable=protected-access + state = device._state # pylint: disable=protected-access + call_args_list = list(spy.call_args_list) + for call_args in call_args_list: + obs = call_args.args[1] + shot_range, bin_size = ( + call_args.kwargs["shot_range"], + call_args.kwargs["bin_size"], + ) + # no need to use op, because the observable has already been applied to ``self.dev._state`` + meas = qml.expval(op=obs) + old_res = device.expval(obs, shot_range=shot_range, bin_size=bin_size) + if device.shots is None: + new_res = meas.process_state(state=state, wire_order=device.wires) + else: + new_res = meas.process_samples( + samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size + ) + assert qml.math.allclose(old_res, new_res) + + +class TestExpval: + """Tests for the expval function""" + + @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + def test_value(self, tol, r_dtype, mocker, shots): + """Test that the expval interface works""" + dev = qml.device("default.qubit", wires=2, shots=shots) + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.expval(qml.PauliY(0)) + + new_dev = circuit.device + spy = mocker.spy(qml.QubitDevice, "expval") + + x = 0.54 + res = circuit(x) + expected = -np.sin(x) + + atol = tol if shots is None else 0.05 + rtol = 0 if shots is None else 0.05 + assert np.allclose(res, expected, atol=atol, rtol=rtol) + + # pylint: disable=no-member, unsubscriptable-object + if isinstance(res, tuple): + assert res[0].dtype == r_dtype + assert res[1].dtype == r_dtype + else: + assert res.dtype == r_dtype + + custom_measurement_process(new_dev, spy) + + def test_not_an_observable(self, mocker): + """Test that a warning is raised if the provided + argument might not be hermitian.""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.RX(0.52, wires=0) + return qml.expval(qml.prod(qml.PauliX(0), qml.PauliZ(0))) + + new_dev = circuit.device + spy = mocker.spy(qml.QubitDevice, "expval") + + with pytest.warns(UserWarning, match="Prod might not be hermitian."): + _ = circuit() + + custom_measurement_process(new_dev, spy) + + def test_observable_return_type_is_expectation(self, mocker): + """Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + res = qml.expval(qml.PauliZ(0)) + assert res.return_type is Expectation + return res + + new_dev = circuit.device + spy = mocker.spy(qml.QubitDevice, "expval") + + circuit() + + custom_measurement_process(new_dev, spy) + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_numeric_type(self, obs): + """Test that the numeric type is correct.""" + res = qml.expval(obs) + assert res.numeric_type is float + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_shape(self, obs): + """Test that the shape is correct.""" + dev = qml.device("default.qubit", wires=1) + + res = qml.expval(obs) + # pylint: disable=use-implicit-booleaness-not-comparison + assert res.shape(dev, Shots(None)) == () + assert res.shape(dev, Shots(100)) == () + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_shape_shot_vector(self, obs): + """Test that the shape is correct with the shot vector too.""" + res = qml.expval(obs) + shot_vector = (1, 2, 3) + dev = qml.device("default.qubit", wires=3, shots=shot_vector) + assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) + + @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) + @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) + def test_projector_expval(self, state, shots, mocker): + """Tests that the expectation of a ``Projector`` object is computed correctly for both of + its subclasses.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + np.random.seed(42) + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(0) + return qml.expval(qml.Projector(state, wires=range(3))) + + new_dev = circuit.device + spy = mocker.spy(qml.QubitDevice, "expval") + + res = circuit() + expected = [0.5, 0.5] if isinstance(shots, list) else 0.5 + assert np.allclose(res, expected, atol=0.02, rtol=0.02) + + custom_measurement_process(new_dev, spy) + + def test_permuted_wires(self, mocker): + """Test that the expectation value of an operator with permuted wires is the same.""" + obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) + obs_2 = qml.prod( + qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) + ) + + dev = qml.device("default.qubit", wires=["h", 8, 10]) + spy = mocker.spy(qml.QubitDevice, "expval") + + @qml.qnode(dev) + def circuit(): + qml.RX(1.23, wires=["h"]) + qml.RY(2.34, wires=[8]) + return qml.expval(obs) + + @qml.qnode(dev) + def circuit2(): + qml.RX(1.23, wires=["h"]) + qml.RY(2.34, wires=[8]) + return qml.expval(obs_2) + + assert circuit() == circuit2() + custom_measurement_process(dev, spy) + + def test_copy_observable(self): + """Test that the observable is copied if present.""" + m = qml.expval(qml.PauliX(0)) + copied_m = copy.copy(m) + assert m.obs is not copied_m.obs + assert qml.equal(m.obs, copied_m.obs) + + def test_copy_eigvals(self): + """Test that the eigvals value is just assigned to new mp without copying.""" + # pylint: disable=protected-access + m = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0)) + copied_m = copy.copy(m) + assert m._eigvals is copied_m._eigvals + + def test_standard_obs(self): + """Check that the hash of an expectation value of an observable can distinguish different observables.""" + + o1 = qml.prod(qml.PauliX(0), qml.PauliY(1)) + o2 = qml.prod(qml.PauliX(0), qml.PauliZ(1)) + + assert qml.expval(o1).hash == qml.expval(o1).hash + assert qml.expval(o2).hash == qml.expval(o2).hash + assert qml.expval(o1).hash != qml.expval(o2).hash + + o3 = qml.sum(qml.PauliX("a"), qml.PauliY("b")) + assert qml.expval(o1).hash != qml.expval(o3).hash + + def test_eigvals(self): + """Test that the eigvals property controls the hash property.""" + m1 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0)) + m2 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0), id="something") + + assert m1.hash == m2.hash + + m3 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(1)) + assert m1.hash != m3.hash + + m4 = ExpectationMP(eigvals=[-1, 1], wires=qml.wires.Wires(1)) + assert m1.hash != m4.hash + assert m3.hash != m4.hash diff --git a/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py new file mode 100644 index 00000000000..3b8160419a5 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py @@ -0,0 +1,614 @@ +# Copyright 2018-2020 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 measurements module""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import ( + ClassicalShadowMP, + Counts, + CountsMP, + Expectation, + ExpectationMP, + MeasurementProcess, + MeasurementTransform, + MidMeasure, + MutualInfoMP, + Probability, + ProbabilityMP, + Sample, + SampleMeasurement, + SampleMP, + ShadowExpvalMP, + Shots, + State, + StateMeasurement, + StateMP, + Variance, + VarianceMP, + VnEntropyMP, + expval, + sample, + var, +) +from pennylane.operation import DecompositionUndefinedError +from pennylane.queuing import AnnotatedQueue + +# pylint: disable=too-few-public-methods, unused-argument + + +class NotValidMeasurement(MeasurementProcess): + @property + def return_type(self): + return "NotValidReturnType" + + +@pytest.mark.parametrize( + "return_type, value", + [ + (Expectation, "expval"), + (Sample, "sample"), + (Counts, "counts"), + (Variance, "var"), + (Probability, "probs"), + (State, "state"), + (MidMeasure, "measure"), + ], +) +def test_ObservableReturnTypes(return_type, value): + """Test the ObservableReturnTypes enum value, repr, and enum membership.""" + + assert return_type.value == value + assert isinstance(return_type, qml.measurements.ObservableReturnTypes) + assert repr(return_type) == value + + +def test_no_measure(): + """Test that failing to specify a measurement + raises an exception""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(x): + qml.RX(x, wires=0) + return qml.PauliY(0) + + with pytest.raises(qml.QuantumFunctionError, match="must return either a single measurement"): + _ = circuit(0.65) + + +def test_numeric_type_unrecognized_error(): + """Test that querying the numeric type of a measurement process with an + unrecognized return type raises an error.""" + + mp = NotValidMeasurement() + with pytest.raises( + qml.QuantumFunctionError, + match="The numeric type of the measurement NotValidMeasurement is not defined", + ): + _ = mp.numeric_type + + +def test_shape_unrecognized_error(): + """Test that querying the shape of a measurement process with an + unrecognized return type raises an error.""" + dev = qml.device("default.qubit", wires=2) + mp = NotValidMeasurement() + with pytest.raises( + qml.QuantumFunctionError, + match="The shape of the measurement NotValidMeasurement is not defined", + ): + mp.shape(dev, Shots(None)) + + +def test_none_return_type(): + """Test that a measurement process without a return type property has return_type + `None`""" + + class NoReturnTypeMeasurement(MeasurementProcess): + """Dummy measurement process with no return type.""" + + mp = NoReturnTypeMeasurement() + assert mp.return_type is None + + +def test_eq_correctness(): + """Test that using `==` on two equivalent operators is True when both measurement + processes are the same object and False otherwise.""" + + class DummyMP(MeasurementProcess): + """Dummy measurement process with no return type.""" + + mp1 = DummyMP(0) + mp2 = DummyMP(0) + + with pytest.warns(UserWarning, match="The behaviour of measurement process equality"): + assert mp1 == mp1 # pylint: disable=comparison-with-itself + assert mp1 != mp2 + + +def test_hash_correctness(): + """Test that the hash of two equivalent measurement processes is the same when + both are the same object and different otherwise.""" + + class DummyMP(MeasurementProcess): + """Dummy measurement process with no return type.""" + + mp1 = DummyMP(0) + mp2 = DummyMP(0) + + with pytest.warns(UserWarning, match="The behaviour of measurement process hashing"): + assert len({mp1, mp1}) == 1 + assert len({mp1, mp2}) == 2 + + +@pytest.mark.parametrize( + "stat_func,return_type", [(expval, Expectation), (var, Variance), (sample, Sample)] +) +class TestStatisticsQueuing: + """Tests for annotating the return types of the statistics functions""" + + @pytest.mark.parametrize( + "op", + [qml.PauliX, qml.PauliY, qml.PauliZ, qml.Hadamard, qml.Identity], + ) + def test_annotating_obs_return_type(self, stat_func, return_type, op): + """Test that the return_type related info is updated for a + measurement""" + with AnnotatedQueue() as q: + A = op(0) + stat_func(A) + + assert len(q.queue) == 1 + meas_proc = q.queue[0] + assert isinstance(meas_proc, MeasurementProcess) + assert meas_proc.return_type == return_type + + def test_annotating_tensor_hermitian(self, stat_func, return_type): + """Test that the return_type related info is updated for a measurement + when called for an Hermitian observable""" + + mx = np.array([[1, 0], [0, 1]]) + + with AnnotatedQueue() as q: + Herm = qml.Hermitian(mx, wires=[1]) + stat_func(Herm) + + assert len(q.queue) == 1 + meas_proc = q.queue[0] + assert isinstance(meas_proc, MeasurementProcess) + assert meas_proc.return_type == return_type + + @pytest.mark.parametrize( + "op1,op2", + [ + (qml.PauliY, qml.PauliX), + (qml.Hadamard, qml.Hadamard), + (qml.PauliY, qml.Identity), + (qml.Identity, qml.Identity), + ], + ) + def test_annotating_tensor_return_type(self, op1, op2, stat_func, return_type): + """Test that the return_type related info is updated for a measurement + when called for an Tensor observable""" + with AnnotatedQueue() as q: + A = op1(0) + B = op2(1) + tensor_op = A @ B + stat_func(tensor_op) + + assert len(q.queue) == 1 + meas_proc = q.queue[0] + assert isinstance(meas_proc, MeasurementProcess) + assert meas_proc.return_type == return_type + + @pytest.mark.parametrize( + "op1,op2", + [ + (qml.PauliY, qml.PauliX), + (qml.Hadamard, qml.Hadamard), + (qml.PauliY, qml.Identity), + (qml.Identity, qml.Identity), + ], + ) + def test_queueing_tensor_observable(self, op1, op2, stat_func, return_type): + """Test that if the constituent components of a tensor operation are not + found in the queue for annotation, they are not queued or annotated.""" + A = op1(0) + B = op2(1) + + with AnnotatedQueue() as q: + tensor_op = A @ B + stat_func(tensor_op) + + assert len(q.queue) == 1 + + meas_proc = q.queue[0] + assert isinstance(meas_proc, MeasurementProcess) + assert meas_proc.return_type == return_type + + def test_not_an_observable(self, stat_func, return_type): # pylint: disable=unused-argument + """Test that a UserWarning is raised if the provided + argument might not be hermitian.""" + if stat_func is sample: + pytest.skip("Sampling is not yet supported with symbolic operators.") + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.RX(0.52, wires=0) + return stat_func(qml.prod(qml.PauliX(0), qml.PauliZ(0))) + + with pytest.warns(UserWarning, match="Prod might not be hermitian."): + _ = circuit() + + +class TestProperties: + """Test for the properties""" + + def test_wires_match_observable(self): + """Test that the wires of the measurement process + match an internal observable""" + obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=["a", "b"]) + m = qml.expval(op=obs) + + assert np.all(m.wires == obs.wires) + + def test_eigvals_match_observable(self): + """Test that the eigenvalues of the measurement process + match an internal observable""" + obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) + m = qml.expval(op=obs) + + assert np.all(m.eigvals() == np.array([1, 2, 3, 4])) + + # changing the observable data should be reflected + obs.data = [np.diag([5, 6, 7, 8])] + assert np.all(m.eigvals() == np.array([5, 6, 7, 8])) + + def test_error_obs_and_eigvals(self): + """Test that providing both eigenvalues and an observable + results in an error""" + obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) + + with pytest.raises(ValueError, match="Cannot set the eigenvalues"): + ExpectationMP(obs=obs, eigvals=[0, 1]) + + def test_error_obs_and_wires(self): + """Test that providing both wires and an observable + results in an error""" + obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) + + with pytest.raises(ValueError, match="Cannot set the wires"): + ExpectationMP(obs=obs, wires=qml.wires.Wires([0, 1])) + + def test_observable_with_no_eigvals(self): + """An observable with no eigenvalues defined should cause + the eigvals method to return a NotImplementedError""" + obs = qml.NumberOperator(wires=0) + m = qml.expval(op=obs) + assert m.eigvals() is None + + def test_repr(self): + """Test the string representation of a MeasurementProcess.""" + m = qml.expval(op=qml.PauliZ(wires="a") @ qml.PauliZ(wires="b")) + expected = "expval(PauliZ(wires=['a']) @ PauliZ(wires=['b']))" + assert str(m) == expected + + m = qml.probs(op=qml.PauliZ(wires="a")) + expected = "probs(PauliZ(wires=['a']))" + assert str(m) == expected + + m = ProbabilityMP(eigvals=(1, 0), wires=qml.wires.Wires(0)) + assert repr(m) == "probs(eigvals=[1 0], wires=[0])" + + +class TestExpansion: + """Test for measurement expansion""" + + def test_expand_pauli(self): + """Test the expansion of a Pauli observable""" + obs = qml.PauliX(0) @ qml.PauliY(1) + m = qml.expval(op=obs) + tape = m.expand() + + assert len(tape.operations) == 4 + + assert tape.operations[0].name == "Hadamard" + assert tape.operations[0].wires.tolist() == [0] + + assert tape.operations[1].name == "PauliZ" + assert tape.operations[1].wires.tolist() == [1] + assert tape.operations[2].name == "S" + assert tape.operations[2].wires.tolist() == [1] + assert tape.operations[3].name == "Hadamard" + assert tape.operations[3].wires.tolist() == [1] + + assert len(tape.measurements) == 1 + assert tape.measurements[0].return_type is Expectation + assert tape.measurements[0].wires.tolist() == [0, 1] + assert np.all(tape.measurements[0].eigvals() == np.array([1, -1, -1, 1])) + + def test_expand_hermitian(self, tol): + """Test the expansion of an hermitian observable""" + H = np.array([[1, 2], [2, 4]]) + obs = qml.Hermitian(H, wires=["a"]) + + m = qml.expval(op=obs) + tape = m.expand() + + assert len(tape.operations) == 1 + + assert tape.operations[0].name == "QubitUnitary" + assert tape.operations[0].wires.tolist() == ["a"] + assert np.allclose( + tape.operations[0].parameters[0], + np.array([[-2, 1], [1, 2]]) / np.sqrt(5), + atol=tol, + rtol=0, + ) + + assert len(tape.measurements) == 1 + assert tape.measurements[0].return_type is Expectation + assert tape.measurements[0].wires.tolist() == ["a"] + assert np.all(tape.measurements[0].eigvals() == np.array([0, 5])) + + def test_expand_no_observable(self): + """Check that an exception is raised if the measurement to + be expanded has no observable""" + with pytest.raises(DecompositionUndefinedError): + ProbabilityMP(wires=qml.wires.Wires([0, 1])).expand() + + @pytest.mark.parametrize( + "m", + [ + ExpectationMP(obs=qml.PauliX(0) @ qml.PauliY(1)), + VarianceMP(obs=qml.PauliX(0) @ qml.PauliY(1)), + ProbabilityMP(obs=qml.PauliX(0) @ qml.PauliY(1)), + ExpectationMP(obs=qml.PauliX(5)), + VarianceMP(obs=qml.PauliZ(0) @ qml.Identity(3)), + ProbabilityMP(obs=qml.PauliZ(0) @ qml.Identity(3)), + ], + ) + def test_has_decomposition_true_pauli(self, m): + """Test that measurements of Paulis report to have a decomposition.""" + assert m.has_decomposition is True + + def test_has_decomposition_true_hermitian(self): + """Test that measurements of Hermitians report to have a decomposition.""" + H = np.array([[1, 2], [2, 4]]) + obs = qml.Hermitian(H, wires=["a"]) + m = qml.expval(op=obs) + assert m.has_decomposition is True + + def test_has_decomposition_false_hermitian_wo_diaggates(self): + """Test that measurements of Hermitians report to have a decomposition.""" + + class HermitianNoDiagGates(qml.Hermitian): + @property + def has_diagonalizing_gates( + self, + ): # pylint: disable=invalid-overridden-method, arguments-renamed + return False + + H = np.array([[1, 2], [2, 4]]) + obs = HermitianNoDiagGates(H, wires=["a"]) + m = ExpectationMP(obs=obs) + assert m.has_decomposition is False + + def test_has_decomposition_false_no_observable(self): + """Check a MeasurementProcess without observable to report not having a decomposition""" + m = ProbabilityMP(wires=qml.wires.Wires([0, 1])) + assert m.has_decomposition is False + + m = ExpectationMP(wires=qml.wires.Wires([0, 1]), eigvals=np.ones(4)) + assert m.has_decomposition is False + + @pytest.mark.parametrize( + "m", + [ + SampleMP(), + SampleMP(wires=["a", 1]), + CountsMP(all_outcomes=True), + CountsMP(wires=["a", 1], all_outcomes=True), + CountsMP(), + CountsMP(wires=["a", 1]), + StateMP(), + VnEntropyMP(wires=["a", 1]), + MutualInfoMP(wires=[["a", 1], ["b", 2]]), + ProbabilityMP(wires=["a", 1]), + ], + ) + def test_samples_computational_basis_true(self, m): + """Test that measurements of Paulis report to have a decomposition.""" + assert m.samples_computational_basis is True + + @pytest.mark.parametrize( + "m", + [ + ExpectationMP(obs=qml.PauliX(2)), + VarianceMP(obs=qml.PauliX("a")), + ProbabilityMP(obs=qml.PauliX("b")), + SampleMP(obs=qml.PauliX("a")), + CountsMP(obs=qml.PauliX("a")), + ShadowExpvalMP(H=qml.PauliX("a")), + ClassicalShadowMP(wires=[["a", 1], ["b", 2]]), + ], + ) + def test_samples_computational_basis_false(self, m): + """Test that measurements of Paulis report to have a decomposition.""" + assert m.samples_computational_basis is False + + +class TestDiagonalizingGates: + def test_no_expansion(self): + """Test a measurement that has no expansion""" + m = qml.sample() + + assert m.diagonalizing_gates() == [] + + def test_obs_diagonalizing_gates(self): + """Test diagonalizing_gates method with and observable.""" + m = qml.expval(qml.PauliY(0)) + + res = m.diagonalizing_gates() + + assert len(res) == 3 + + expected_classes = [qml.PauliZ, qml.S, qml.Hadamard] + for op, c in zip(res, expected_classes): + assert isinstance(op, c) + + +class TestSampleMeasurement: + """Tests for the SampleMeasurement class.""" + + def test_custom_sample_measurement(self): + """Test the execution of a custom sampled measurement.""" + + class MyMeasurement(SampleMeasurement): + # pylint: disable=signature-differs + def process_samples(self, samples, wire_order, shot_range, bin_size): + return qml.math.sum(samples[..., self.wires]) + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev) + def circuit(): + qml.PauliX(0) + return MyMeasurement(wires=[0]), MyMeasurement(wires=[1]) + + assert qml.math.allequal(circuit(), [1000, 0]) + + def test_sample_measurement_without_shots(self): + """Test that executing a sampled measurement with ``shots=None`` raises an error.""" + + class MyMeasurement(SampleMeasurement): + # pylint: disable=signature-differs + def process_samples(self, samples, wire_order, shot_range, bin_size): + return qml.math.sum(samples[..., self.wires]) + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.PauliX(0) + return MyMeasurement(wires=[0]), MyMeasurement(wires=[1]) + + with pytest.raises( + ValueError, match="Shots must be specified in the device to compute the measurement " + ): + circuit() + + def test_method_overriden_by_device(self): + """Test that the device can override a measurement process.""" + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev) + def circuit(): + qml.PauliX(0) + return qml.sample(wires=[0]), qml.sample(wires=[1]) + + circuit.device.measurement_map[SampleMP] = "test_method" + circuit.device.test_method = lambda obs, shot_range=None, bin_size=None: 2 + + assert qml.math.allequal(circuit(), [2, 2]) + + +class TestStateMeasurement: + """Tests for the SampleMeasurement class.""" + + def test_custom_state_measurement(self): + """Test the execution of a custom state measurement.""" + + class MyMeasurement(StateMeasurement): + def process_state(self, state, wire_order): + return qml.math.sum(state) + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + return MyMeasurement() + + assert circuit() == 1 + + def test_sample_measurement_with_shots(self): + """Test that executing a state measurement with shots raises a warning.""" + + class MyMeasurement(StateMeasurement): + def process_state(self, state, wire_order): + return qml.math.sum(state) + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev) + def circuit(): + return MyMeasurement() + + with pytest.warns( + UserWarning, + match="Requested measurement MyMeasurement with finite shots", + ): + circuit() + + def test_method_overriden_by_device(self): + """Test that the device can override a measurement process.""" + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface="autograd") + def circuit(): + return qml.state() + + circuit.device.measurement_map[StateMP] = "test_method" + circuit.device.test_method = lambda obs, shot_range=None, bin_size=None: 2 + + assert circuit() == 2 + + +class TestMeasurementTransform: + """Tests for the MeasurementTransform class.""" + + def test_custom_measurement(self): + """Test the execution of a custom measurement.""" + + class MyMeasurement(MeasurementTransform): + def process(self, tape, device): + return {device.shots: len(tape)} + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev) + def circuit(): + return MyMeasurement() + + assert circuit() == {dev.shots: len(circuit.tape)} + + def test_method_overriden_by_device(self): + """Test that the device can override a measurement process.""" + + dev = qml.device("default.qubit", wires=2, shots=1000) + + @qml.qnode(dev) + def circuit(): + return qml.classical_shadow(wires=0) + + circuit.device.measurement_map[ClassicalShadowMP] = "test_method" + circuit.device.test_method = lambda tape: 2 + + assert circuit() == 2 diff --git a/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py new file mode 100644 index 00000000000..6aa70a21457 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py @@ -0,0 +1,471 @@ +# Copyright 2018-2020 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 mid_measure module""" + +from itertools import product +import pytest + +import pennylane as qml +import pennylane.numpy as np +from pennylane.measurements import MidMeasureMP, MeasurementValue +from pennylane.wires import Wires + +# pylint: disable=too-few-public-methods, too-many-public-methods + + +def test_samples_computational_basis(): + """Test that samples_computational_basis is always false for mid circuit measurements.""" + m = MidMeasureMP(Wires(0)) + assert not m.samples_computational_basis + + +class TestMeasure: + """Tests for the measure function""" + + def test_many_wires_error(self): + """Test that an error is raised if multiple wires are passed to + measure.""" + with pytest.raises( + qml.QuantumFunctionError, + match="Only a single qubit can be measured in the middle of the circuit", + ): + qml.measure(wires=[0, 1]) + + def test_hash(self): + """Test that the hash for `MidMeasureMP` is defined correctly.""" + m1 = MidMeasureMP(Wires(0), id="m1") + m2 = MidMeasureMP(Wires(0), id="m2") + m3 = MidMeasureMP(Wires(1), id="m1") + m4 = MidMeasureMP(Wires(0), id="m1") + + assert m1.hash != m2.hash + assert m1.hash != m3.hash + assert m1.hash == m4.hash + + +mp1 = MidMeasureMP(Wires(0), id="m0") +mp2 = MidMeasureMP(Wires(1), id="m1") +mp3 = MidMeasureMP(Wires(2), id="m2") + + +class TestMeasurementValueManipulation: + """Test all the dunder methods associated with the MeasurementValue class""" + + def test_apply_function_to_measurement(self): + """Test the general _apply method that can apply an arbitrary function to a measurement.""" + + m = MeasurementValue([mp1], lambda v: v) + + sin_of_m = m._apply(np.sin) # pylint: disable=protected-access + assert sin_of_m[0] == 0.0 + assert sin_of_m[1] == np.sin(1) + + def test_and_with_bool(self): + """Test the __add__ dunder method between MeasurementValue and scalar.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = m & False + assert not m_add[0] + assert not m_add[1] + + def test_and_to_measurements(self): + """Test the __add__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + sum_of_measurements = m0 & m1 + assert not sum_of_measurements[0] + assert not sum_of_measurements[1] + assert not sum_of_measurements[2] + assert sum_of_measurements[3] + + def test_or_with_bool(self): + """Test the __or__ dunder method between MeasurementValue and scalar.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = m | False + assert not m_add[0] + assert m_add[1] + + def test_or_to_measurements(self): + """Test the __or__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + sum_of_measurements = m0 | m1 + assert not sum_of_measurements[0] + assert sum_of_measurements[1] + assert sum_of_measurements[2] + assert sum_of_measurements[3] + + def test_add_with_scalar(self): + """Test the __add__ dunder method between MeasurementValue and scalar.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = m + 5 + assert m_add[0] == 5 + assert m_add[1] == 6 + + def test_add_to_measurements(self): + """Test the __add__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + sum_of_measurements = m0 + m1 + assert sum_of_measurements[0] == 0 + assert sum_of_measurements[1] == 1 + assert sum_of_measurements[2] == 1 + assert sum_of_measurements[3] == 2 + + def test_radd_with_scalar(self): + """Test the __radd__ dunder method between a scalar and a MeasurementValue.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = 5 + m + assert m_add[0] == 5 + assert m_add[1] == 6 + + def test_sub_with_scalar(self): + """Test the __sub__ dunder method between MeasurementValue and scalar.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = m - 5 + assert m_add[0] == -5 + assert m_add[1] == -4 + + def test_sub_to_measurements(self): + """Test the __sub__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + sum_of_measurements = m0 - m1 + assert sum_of_measurements[0] == 0 + assert sum_of_measurements[1] == -1 + assert sum_of_measurements[2] == 1 + assert sum_of_measurements[3] == 0 + + def test_rsub_with_scalar(self): + """Test the __rsub__ dunder method between a scalar and a MeasurementValue.""" + m = MeasurementValue([mp1], lambda v: v) + m_add = 5 - m + assert m_add[0] == 5 + assert m_add[1] == 4 + + def test_mul_with_scalar(self): + """Test the __mul__ dunder method between a MeasurementValue and a scalar""" + m = MeasurementValue([mp1], lambda v: v) + m_mul = m * 5 + assert m_mul[0] == 0 + assert m_mul[1] == 5 + + def test_mul_with_measurement(self): + """Test the __mul__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + mul_of_measurements = m0 * m1 + assert mul_of_measurements[0] == 0 + assert mul_of_measurements[1] == 0 + assert mul_of_measurements[2] == 0 + assert mul_of_measurements[3] == 1 + + def test_rmul_with_scalar(self): + """Test the __rmul__ dunder method between a scalar and a MeasurementValue.""" + m = MeasurementValue([mp1], lambda v: v) + m_mul = 5 * m + assert m_mul[0] == 0 + assert m_mul[1] == 5 + + def test_truediv_with_scalar(self): + """Test the __truediv__ dunder method between a MeasurementValue and a scalar""" + m = MeasurementValue([mp1], lambda v: v) + m_mul = m / 5.0 + assert m_mul[0] == 0 + assert m_mul[1] == 1 / 5.0 + + def test_truediv_with_measurement(self): + """Test the __truediv__ dunder method between two MeasurementValues.""" + m0 = MeasurementValue([mp1], lambda v: v) + 3.0 + m1 = MeasurementValue([mp2], lambda v: v) + 5.0 + mul_of_measurements = m0 / m1 + assert mul_of_measurements[0] == 3.0 / 5.0 + assert mul_of_measurements[1] == 3.0 / 6.0 + assert mul_of_measurements[2] == 4.0 / 5.0 + assert mul_of_measurements[3] == 4.0 / 6.0 + + def test_rtruediv_with_scalar(self): + """Test the __rtruediv__ dunder method between a scalar and a MeasurementValue.""" + m = MeasurementValue([mp1], lambda v: v) + 3.0 + m_mul = 5 / m + assert m_mul[0] == 5 / 3.0 + assert m_mul[1] == 5 / 4.0 + + def test_inversion(self): + """Test the __inv__ dunder method.""" + m = MeasurementValue([mp1], lambda v: v) + m_inversion = ~m + assert m_inversion[0] is True + assert m_inversion[1] is False + + def test_lt(self): + """Test the __lt__ dunder method between a MeasurementValue and a float.""" + m = MeasurementValue([mp1], lambda v: v) + m_inversion = m < 0.5 + assert m_inversion[0] is True + assert m_inversion[1] is False + + def test_lt_with_other_measurement_value(self): + """Test the __lt__ dunder method between two MeasurementValues""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 < m2 + assert compared[0] is False + assert compared[1] is True + assert compared[2] is False + assert compared[3] is False + + def test_gt(self): + """Test the __gt__ dunder method between a MeasurementValue and a float.""" + m = MeasurementValue([mp1], lambda v: v) + m_inversion = m > 0.5 + assert m_inversion[0] is False + assert m_inversion[1] is True + + def test_gt_with_other_measurement_value(self): + """Test the __gt__ dunder method between two MeasurementValues.""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 > m2 + assert compared[0] is False + assert compared[1] is False + assert compared[2] is True + assert compared[3] is False + + def test_le(self): + """Test the __le__ dunder method between a MeasurementValue and a float.""" + m = MeasurementValue([mp1], lambda v: v) + m_inversion = m <= 0.5 + assert m_inversion[0] is True + assert m_inversion[1] is False + + def test_le_with_other_measurement_value(self): + """Test the __le__ dunder method between two MeasurementValues""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 <= m2 + assert compared[0] is True + assert compared[1] is True + assert compared[2] is False + assert compared[3] is True + + def test_ge(self): + """Test the __ge__ dunder method between a MeasurementValue and a flaot.""" + m = MeasurementValue([mp1], lambda v: v) + m_inversion = m >= 0.5 + assert m_inversion[0] is False + assert m_inversion[1] is True + + def test_ge_with_other_measurement_value(self): + """Test the __ge__ dunder method between two MeasurementValues.""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 >= m2 + assert compared[0] is True + assert compared[1] is False + assert compared[2] is True + assert compared[3] is True + + def test_equality_with_scalar(self): + """Test the __eq__ dunder method between a MeasurementValue and an integer.""" + m = MeasurementValue([mp1], lambda v: v) + m_eq = m == 0 + assert m_eq[0] is True # confirming value is actually eq to True, not just truthy + assert m_eq[1] is False + + def test_equality_with_scalar_opposite(self): + """Test the __eq__ dunder method between a MeasurementValue and an integer.""" + m = MeasurementValue([mp1], lambda v: v) + m_eq = m == 1 + assert m_eq[0] is False + assert m_eq[1] is True + + def test_eq_with_other_measurement_value(self): + """Test the __eq__ dunder method between two MeasurementValues.""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 == m2 + assert compared[0] is True + assert compared[1] is False + assert compared[2] is False + assert compared[3] is True + + def test_non_equality_with_scalar(self): + """Test the __ne__ dunder method between a MeasurementValue and an integer.""" + m = MeasurementValue([mp1], lambda v: v) + m_eq = m != 0 + assert m_eq[0] is False # confirming value is actually eq to True, not just truthy + assert m_eq[1] is True + + def test_non_equality_with_scalar_opposite(self): + """Test the __ne__ dunder method between a MeasurementValue and an integer.""" + m = MeasurementValue([mp1], lambda v: v) + m_eq = m != 1 + assert m_eq[0] is True + assert m_eq[1] is False + + def test_non_eq_with_other_measurement_value(self): + """Test the __ne__ dunder method between two MeasurementValues.""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 != m2 + assert compared[0] is False + assert compared[1] is True + assert compared[2] is True + assert compared[3] is False + + def test_merge_measurements_values_dependant_on_same_measurement(self): + """Test that the _merge operation does not create more than 2 branches when combining two MeasurementValues + that are based on the same measurement.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp1], lambda v: v) + combined = m0 + m1 + assert combined[0] == 0 + assert combined[1] == 2 + + def test_combine_measurement_value_with_non_measurement(self): + """Test that we can use dunder methods to combine a MeasurementValue with the underlying "primitive" + of that measurement value.""" + m0 = MeasurementValue([mp1], lambda v: v) + out = m0 + 10 + assert out[0] == 10 + assert out[1] == 11 + + def test_branches_method(self): + """Test the __eq__ dunder method between two MeasurementValues.""" + m1 = MeasurementValue([mp1], lambda v: v) + m2 = MeasurementValue([mp2], lambda v: v) + compared = m1 == m2 + branches = compared.branches + assert branches[(0, 0)] is True + assert branches[(0, 1)] is False + assert branches[(1, 0)] is False + assert branches[(1, 1)] is True + + def test_str(self): + """Test that the output of the __str__ dunder method is as expected""" + m = MeasurementValue([mp1], lambda v: v) + assert str(m) == "if m0=0 => 0\nif m0=1 => 1" + + def test_complex_str(self): + """Test that the output of the __str__ dunder method is as expected + w.r.t a more complicated MeasurementValue""" + a = MeasurementValue([mp1], lambda v: v) + b = MeasurementValue([mp2], lambda v: v) + assert ( + str(a + b) + == """if m0=0,m1=0 => 0 +if m0=0,m1=1 => 1 +if m0=1,m1=0 => 1 +if m0=1,m1=1 => 2""" + ) + + +unary_dunders = ["__invert__"] + + +measurement_value_binary_dunders = [ + "__add__", + "__mul__", + "__radd__", + "__rmul__", + "__rsub__", + "__sub__", +] + +boolean_binary_dunders = [ + "__and__", + "__eq__", + "__ge__", + "__gt__", + "__le__", + "__lt__", + "__ne__", + "__or__", +] + +binary_dunders = measurement_value_binary_dunders + boolean_binary_dunders + +divisions = ["__rtruediv__", "__truediv__"] + + +class TestMeasurementCompositeValueManipulation: + """Test composite application of dunder methods associated with the MeasurementValue class""" + + @pytest.mark.parametrize("unary_name", unary_dunders) + @pytest.mark.parametrize("binary1_name, binary2_name", product(binary_dunders, binary_dunders)) + def test_composition_between_measurement_values(self, unary_name, binary1_name, binary2_name): + """Test the composition of dunder methods.""" + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + + # 1. Apply a unary dunder method + unary = getattr(m0, unary_name) + m0 = unary() + assert isinstance(m0, MeasurementValue) + + # 2. Apply first binary dunder method + binary_dunder1 = getattr(m0, binary1_name) + sum_of_measurements = binary_dunder1(m1) + assert isinstance(sum_of_measurements, MeasurementValue) + + # 3. Apply a unary dunder method on the new MV + unary = getattr(sum_of_measurements, unary_name) + m0 = unary() + assert isinstance(m0, MeasurementValue) + + # 4. Apply second binary dunder method + binary_dunder2 = getattr(m0, binary2_name) + + m2 = MeasurementValue([mp1], lambda v: v) + boolean_of_measurements = binary_dunder2(m2) + + assert isinstance(boolean_of_measurements, MeasurementValue) + + @pytest.mark.parametrize("mv_dunder_name", measurement_value_binary_dunders) + @pytest.mark.parametrize("boolean_dunder_name", boolean_binary_dunders) + @pytest.mark.parametrize("scalar", [MeasurementValue([mp2], lambda v: v), 0, 1.0, 1.0 + 0j]) + @pytest.mark.parametrize("boolean", [MeasurementValue([mp3], lambda v: v), True, False, None]) + def test_composition_measurement_values_and_boolean( + self, mv_dunder_name, boolean_dunder_name, scalar, boolean + ): # pylint: disable=too-many-arguments + """Test the composition of dunder methods, applying one whose argument is scalar and one whose argument + is a boolean.""" + m0 = MeasurementValue([mp1], lambda v: v) + + # 1. Apply first binary dunder method between m0 and scalar + binary_dunder1 = getattr(m0, mv_dunder_name) + sum_of_measurements = binary_dunder1(scalar) + assert isinstance(sum_of_measurements, MeasurementValue) + + # 2. Apply second binary dunder method between m0 and boolean + binary_dunder2 = getattr(m0, boolean_dunder_name) + boolean_of_measurements = binary_dunder2(boolean) + assert isinstance(boolean_of_measurements, MeasurementValue) + + @pytest.mark.parametrize("div", divisions) + @pytest.mark.parametrize("other", [MeasurementValue([mp3], lambda v: v) + 5, np.pi]) + @pytest.mark.parametrize("binary", binary_dunders) + def test_composition_with_division(self, binary, div, other): + """Test the composition of dunder methods with division.""" + # 1. Apply a binary dundar + m0 = MeasurementValue([mp1], lambda v: v) + m1 = MeasurementValue([mp2], lambda v: v) + + binary_dunder = getattr(m0, binary) + m0 = binary_dunder(m1) + + # 2. Apply a division method + division_dunder = getattr(m0, div) + res = division_dunder(other) + assert isinstance(res, MeasurementValue) diff --git a/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py new file mode 100644 index 00000000000..79eedc1d44e --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py @@ -0,0 +1,479 @@ +# Copyright 2018-2020 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 mutual_info module""" +import copy + +import numpy as np +import pytest + +import pennylane as qml +from pennylane.interfaces import INTERFACE_MAP +from pennylane.measurements import MutualInfo, Shots +from pennylane.measurements.mutual_info import MutualInfoMP +from pennylane.wires import Wires + + +class TestMutualInfoUnitTests: + """Tests for the mutual_info function""" + + def test_queue(self): + """Test that the right measurement class is queued.""" + + with qml.queuing.AnnotatedQueue() as q: + m = qml.mutual_info(wires0=[0], wires1=[1]) + + assert q.queue[0] is m + assert isinstance(q.queue[0], MutualInfoMP) + + @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ([1, 10], ((), ()))]) + def test_shape(self, shots, shape): + """Test that the shape is correct.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + res = qml.mutual_info(wires0=[0], wires1=[1]) + assert res.shape(dev, Shots(shots)) == shape + + def test_properties(self): + """Test that the properties are correct.""" + meas = qml.mutual_info(wires0=[0], wires1=[1]) + assert meas.numeric_type == float + assert meas.return_type == MutualInfo + + def test_copy(self): + """Test that the ``__copy__`` method also copies the ``log_base`` information.""" + meas = qml.mutual_info(wires0=[0], wires1=[1], log_base=2) + meas_copy = copy.copy(meas) + assert meas_copy.log_base == 2 + assert meas_copy.wires == Wires([0, 1]) + + def test_repr(self): + """Test that the representation includes information about both wires and the log_base""" + m1 = qml.mutual_info(wires0=[0], wires1=[1]) + assert repr(m1) == "MutualInfo(wires0=[0], wires1=[1], log_base=None)" + + def test_hash(self): + """Test the hash property includes the log_base property and the separation of the wires into two subsytems.""" + m1 = MutualInfoMP(wires=[Wires(0), Wires(1)], log_base=2) + m2 = MutualInfoMP(wires=[Wires(0), Wires(1)], log_base=10) + assert m1.hash != m2.hash + + m3 = MutualInfoMP(wires=[Wires((0, 1)), Wires(2)]) + m4 = MutualInfoMP(wires=[Wires((0)), Wires((1, 2))]) + assert m3.hash != m4.hash + + +class TestIntegration: + """Tests for the mutual information functions""" + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) + @pytest.mark.parametrize( + "state, expected", + [ + ([1.0, 0.0, 0.0, 0.0], 0), + ([qml.math.sqrt(2) / 2, 0.0, qml.math.sqrt(2) / 2, 0.0], 0), + ([qml.math.sqrt(2) / 2, 0.0, 0.0, qml.math.sqrt(2) / 2], 2 * qml.math.log(2)), + (qml.math.ones(4) * 0.5, 0.0), + ], + ) + def test_mutual_info_output(self, interface, state, expected): + """Test the output of qml.mutual_info""" + dev = qml.device("default.qubit", wires=4) + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.StatePrep(state, wires=[0, 1]) + return qml.mutual_info(wires0=[0, 2], wires1=[1, 3]) + + res = circuit() + new_res = qml.mutual_info(wires0=[0, 2], wires1=[1, 3]).process_state( + state=circuit.device.state, wire_order=circuit.device.wires + ) + assert np.allclose(res, expected, atol=1e-6) + assert np.allclose(new_res, expected, atol=1e-6) + assert INTERFACE_MAP.get(qml.math.get_interface(new_res)) == interface + assert res.dtype == new_res.dtype # pylint: disable=no-member + + def test_shot_vec_error(self): + """Test an error is raised when using shot vectors with mutual_info.""" + dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + + @qml.qnode(device=dev) + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + with pytest.raises( + NotImplementedError, match="mutual information is not supported with shot vectors" + ): + circuit(0.5) + + diff_methods = ["backprop", "finite-diff"] + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + @pytest.mark.parametrize("params", np.linspace(0, 2 * np.pi, 8)) + def test_qnode_state(self, device, interface, params): + """Test that the mutual information transform works for QNodes by comparing + against analytic values""" + dev = qml.device(device, wires=2) + + params = qml.math.asarray(params, like=interface) + + @qml.qnode(dev, interface=interface) + def circuit(params): + qml.RY(params, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.state() + + actual = qml.qinfo.mutual_info(circuit, wires0=[0], wires1=[1])(params) + + # compare transform results with analytic values + expected = -2 * np.cos(params / 2) ** 2 * np.log( + np.cos(params / 2) ** 2 + 1e-10 + ) - 2 * np.sin(params / 2) ** 2 * np.log(np.sin(params / 2) ** 2 + 1e-10) + + assert np.allclose(actual, expected) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + @pytest.mark.parametrize("params", zip(np.linspace(0, np.pi, 8), np.linspace(0, 2 * np.pi, 8))) + def test_qnode_mutual_info(self, device, interface, params): + """Test that the measurement process for mutual information works for QNodes + by comparing against the mutual information transform""" + dev = qml.device(device, wires=2) + + params = qml.math.asarray(np.array(params), like=interface) + + @qml.qnode(dev, interface=interface) + def circuit_mutual_info(params): + qml.RY(params[0], wires=0) + qml.RY(params[1], wires=1) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + @qml.qnode(dev, interface=interface) + def circuit_state(params): + qml.RY(params[0], wires=0) + qml.RY(params[1], wires=1) + qml.CNOT(wires=[0, 1]) + return qml.state() + + actual = circuit_mutual_info(params) + + # compare measurement results with transform results + expected = qml.qinfo.mutual_info(circuit_state, wires0=[0], wires1=[1])(params) + + assert np.allclose(actual, expected) + + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + def test_mutual_info_wire_labels(self, device): + """Test that mutual_info is correct with custom wire labels""" + param = np.array([0.678, 1.234]) + wires = ["a", 8] + dev = qml.device(device, wires=wires) + + @qml.qnode(dev) + def circuit(param): + qml.RY(param, wires=wires[0]) + qml.CNOT(wires=wires) + return qml.state() + + actual = qml.qinfo.mutual_info(circuit, wires0=[wires[0]], wires1=[wires[1]])(param) + + # compare transform results with analytic values + expected = -2 * np.cos(param / 2) ** 2 * np.log(np.cos(param / 2) ** 2) - 2 * np.sin( + param / 2 + ) ** 2 * np.log(np.sin(param / 2) ** 2) + + assert np.allclose(actual, expected) + + @pytest.mark.jax + @pytest.mark.parametrize("params", np.linspace(0, 2 * np.pi, 8)) + def test_qnode_state_jax_jit(self, params): + """Test that the mutual information transform works for QNodes by comparing + against analytic values, for the JAX-jit interface""" + import jax + import jax.numpy as jnp + + dev = qml.device("default.qubit", wires=2) + + params = jnp.array(params) + + @qml.qnode(dev, interface="jax-jit") + def circuit(params): + qml.RY(params, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.state() + + actual = jax.jit(qml.qinfo.mutual_info(circuit, wires0=[0], wires1=[1]))(params) + + # compare transform results with analytic values + expected = -2 * jnp.cos(params / 2) ** 2 * jnp.log( + jnp.cos(params / 2) ** 2 + 1e-10 + ) - 2 * jnp.sin(params / 2) ** 2 * jnp.log(jnp.sin(params / 2) ** 2 + 1e-10) + + assert np.allclose(actual, expected) + + @pytest.mark.jax + @pytest.mark.parametrize("params", zip(np.linspace(0, np.pi, 8), np.linspace(0, 2 * np.pi, 8))) + @pytest.mark.parametrize("interface", ["jax-jit"]) + def test_qnode_mutual_info_jax_jit(self, params, interface): + """Test that the measurement process for mutual information works for QNodes + by comparing against the mutual information transform, for the JAX-jit interface""" + import jax + import jax.numpy as jnp + + dev = qml.device("default.qubit", wires=2) + + params = jnp.array(params) + + @qml.qnode(dev, interface=interface) + def circuit_mutual_info(params): + qml.RY(params[0], wires=0) + qml.RY(params[1], wires=1) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + @qml.qnode(dev, interface="jax-jit") + def circuit_state(params): + qml.RY(params[0], wires=0) + qml.RY(params[1], wires=1) + qml.CNOT(wires=[0, 1]) + return qml.state() + + actual = jax.jit(circuit_mutual_info)(params) + + # compare measurement results with transform results + expected = jax.jit(qml.qinfo.mutual_info(circuit_state, wires0=[0], wires1=[1]))(params) + + assert np.allclose(actual, expected) + + @pytest.mark.autograd + @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["auto", "autograd"]) + def test_qnode_grad(self, param, diff_method, interface): + """Test that the gradient of mutual information works for QNodes + with the autograd interface""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(param): + qml.RY(param, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + if param == 0: + # we don't allow gradients to flow through the discontinuity at 0 + expected = 0 + else: + expected = np.sin(param) * ( + np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) + ) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + actual = qml.grad(circuit)(param) + assert np.allclose(actual, expected, atol=tol) + + @pytest.mark.jax + @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax"]) + def test_qnode_grad_jax(self, param, diff_method, interface): + """Test that the gradient of mutual information works for QNodes + with the JAX interface""" + import jax + import jax.numpy as jnp + + dev = qml.device("default.qubit", wires=2) + + param = jnp.array(param) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(param): + qml.RY(param, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + if param == 0: + # we don't allow gradients to flow through the discontinuity at 0 + expected = 0 + else: + expected = jnp.sin(param) * ( + jnp.log(jnp.cos(param / 2) ** 2) - jnp.log(jnp.sin(param / 2) ** 2) + ) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + actual = jax.grad(circuit)(param) + assert np.allclose(actual, expected, atol=tol) + + @pytest.mark.jax + @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax-jit"]) + def test_qnode_grad_jax_jit(self, param, diff_method, interface): + """Test that the gradient of mutual information works for QNodes + with the JAX-jit interface""" + import jax + import jax.numpy as jnp + + dev = qml.device("default.qubit", wires=2) + + param = jnp.array(param) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(param): + qml.RY(param, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + if param == 0: + # we don't allow gradients to flow through the discontinuity at 0 + expected = 0 + else: + expected = jnp.sin(param) * ( + jnp.log(jnp.cos(param / 2) ** 2) - jnp.log(jnp.sin(param / 2) ** 2) + ) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + actual = jax.jit(jax.grad(circuit))(param) + assert np.allclose(actual, expected, atol=tol) + + @pytest.mark.tf + @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["tf"]) + def test_qnode_grad_tf(self, param, diff_method, interface): + """Test that the gradient of mutual information works for QNodes + with the tensorflow interface""" + import tensorflow as tf + + dev = qml.device("default.qubit", wires=2) + + param = tf.Variable(param) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(param): + qml.RY(param, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + if param == 0: + # we don't allow gradients to flow through the discontinuity at 0 + expected = 0 + else: + expected = np.sin(param) * ( + np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) + ) + + with tf.GradientTape() as tape: + out = circuit(param) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + actual = tape.gradient(out, param) + assert np.allclose(actual, expected, atol=tol) + + @pytest.mark.torch + @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["torch"]) + def test_qnode_grad_torch(self, param, diff_method, interface): + """Test that the gradient of mutual information works for QNodes + with the torch interface""" + import torch + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(param): + qml.RY(param, wires=0) + qml.CNOT(wires=[0, 1]) + return qml.mutual_info(wires0=[0], wires1=[1]) + + if param == 0: + # we don't allow gradients to flow through the discontinuity at 0 + expected = 0 + else: + expected = np.sin(param) * ( + np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) + ) + + param = torch.tensor(param, requires_grad=True) + out = circuit(param) + out.backward() # pylint: disable=no-member + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + actual = param.grad + assert np.allclose(actual, expected, atol=tol) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + @pytest.mark.parametrize( + "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] + ) + def test_subsystem_overlap_error(self, device, interface, params): + """Test that an error is raised when the subsystems overlap""" + dev = qml.device(device, wires=3) + + params = qml.math.asarray(params, like=interface) + + @qml.qnode(dev, interface=interface) + def circuit(params): + qml.RY(params[0], wires=0) + qml.RY(params[1], wires=1) + qml.CNOT(wires=[0, 1]) + qml.CNOT(wires=[0, 2]) + return qml.mutual_info(wires0=[0, 1], wires1=[1, 2]) + + msg = "Subsystems for computing mutual information must not overlap" + with pytest.raises(qml.QuantumFunctionError, match=msg): + circuit(params) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) + @pytest.mark.parametrize( + "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] + ) + def test_custom_wire_labels_error(self, device, interface, params): + """Tests that an error is raised when mutual information is measured + with custom wire labels""" + dev = qml.device(device, wires=["a", "b"]) + + params = qml.math.asarray(params, like=interface) + + @qml.qnode(dev, interface=interface) + def circuit(params): + qml.RY(params[0], wires="a") + qml.RY(params[1], wires="b") + qml.CNOT(wires=["a", "b"]) + return qml.mutual_info(wires0=["a"], wires1=["b"]) + + msg = "Returning the mutual information is not supported when using custom wire labels" + with pytest.raises(qml.QuantumFunctionError, match=msg): + circuit(params) diff --git a/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py new file mode 100644 index 00000000000..a07fd3da1b9 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py @@ -0,0 +1,710 @@ +# Copyright 2018-2020 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 probs module""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane import numpy as pnp +from pennylane.measurements import ( + MeasurementProcess, + Probability, + ProbabilityMP, + Shots, +) +from pennylane.queuing import AnnotatedQueue + + +# TODO: Remove this when new CustomMP are the default +def custom_measurement_process(device, spy): + assert len(spy.call_args_list) > 0 # make sure method is mocked properly + + samples = device._samples # pylint: disable=protected-access + state = device._state # pylint: disable=protected-access + call_args_list = list(spy.call_args_list) + for call_args in call_args_list: + wires, shot_range, bin_size = ( + call_args.kwargs["wires"], + call_args.kwargs["shot_range"], + call_args.kwargs["bin_size"], + ) + # no need to use op, because the observable has already been applied to ``dev._state`` + meas = qml.probs(wires=wires) + old_res = device.probability(wires=wires, shot_range=shot_range, bin_size=bin_size) + if device.shots is None: + new_res = meas.process_state(state=state, wire_order=device.wires) + else: + new_res = meas.process_samples( + samples=samples, + wire_order=device.wires, + shot_range=shot_range, + bin_size=bin_size, + ) + assert qml.math.allequal(old_res, new_res) + + +# make the test deterministic +np.random.seed(42) + + +@pytest.fixture(name="init_state") +def fixture_init_state(): + """Fixture that creates an initial state""" + + def _init_state(n): + """An initial state over n wires""" + state = np.random.random([2**n]) + np.random.random([2**n]) * 1j + state /= np.linalg.norm(state) + return state + + return _init_state + + +class TestProbs: + """Tests for the probs function""" + + # pylint:disable=too-many-public-methods + + def test_queue(self): + """Test that the right measurement class is queued.""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + return qml.probs(wires=0) + + circuit() + + assert isinstance(circuit.tape[0], ProbabilityMP) + + def test_numeric_type(self): + """Test that the numeric type is correct.""" + res = qml.probs(wires=0) + assert res.numeric_type is float + + @pytest.mark.parametrize("wires", [[0], [2, 1], ["a", "c", 3]]) + @pytest.mark.parametrize("shots", [None, 10]) + def test_shape(self, wires, shots): + """Test that the shape is correct.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + res = qml.probs(wires=wires) + assert res.shape(dev, Shots(shots)) == (2 ** len(wires),) + + @pytest.mark.parametrize("wires", [[0], [2, 1], ["a", "c", 3]]) + def test_shape_shot_vector(self, wires): + """Test that the shape is correct with the shot vector too.""" + res = qml.probs(wires=wires) + shot_vector = (1, 2, 3) + dev = qml.device("default.qubit", wires=3, shots=shot_vector) + assert res.shape(dev, Shots(shot_vector)) == ( + (2 ** len(wires),), + (2 ** len(wires),), + (2 ** len(wires),), + ) + + @pytest.mark.parametrize("wires", [[0], [0, 1], [1, 0, 2]]) + def test_annotating_probs(self, wires): + """Test annotating probs""" + with AnnotatedQueue() as q: + qml.probs(wires) + + assert len(q.queue) == 1 + + meas_proc = q.queue[0] + assert isinstance(meas_proc, MeasurementProcess) + assert meas_proc.return_type == Probability + + def test_probs_empty_wires(self): + """Test that using ``qml.probs`` with an empty wire list raises an error.""" + with pytest.raises(ValueError, match="Cannot set an empty list of wires."): + qml.probs(wires=[]) + + @pytest.mark.parametrize("shots", [None, 100]) + def test_probs_no_arguments(self, shots): + """Test that using ``qml.probs`` with no arguments returns the probabilities of all wires.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + + @qml.qnode(dev) + def circuit(): + return qml.probs() + + res = circuit() + + assert qml.math.allequal(res, [1, 0, 0, 0, 0, 0, 0, 0]) + + def test_full_prob(self, init_state, tol, mocker): + """Test that the correct probability is returned.""" + dev = qml.device("default.qubit", wires=4) + spy = mocker.spy(qml.QubitDevice, "probability") + + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + return qml.probs(wires=range(4)) + + res = circuit() + expected = np.abs(state) ** 2 + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + def test_marginal_prob(self, init_state, tol, mocker): + """Test that the correct marginal probability is returned.""" + dev = qml.device("default.qubit", wires=4) + spy = mocker.spy(qml.QubitDevice, "probability") + + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + return qml.probs(wires=[1, 3]) + + res = circuit() + expected = np.reshape(np.abs(state) ** 2, [2] * 4) + expected = np.einsum("ijkl->jl", expected).flatten() + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + def test_marginal_prob_more_wires(self, init_state, mocker, tol): + """Test that the correct marginal probability is returned, when the + states_to_binary method is used for probability computations.""" + dev = qml.device("default.qubit", wires=4) + spy_probs = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + return qml.probs(wires=[1, 0, 3]) + + res = circuit() + + expected = np.reshape(np.abs(state) ** 2, [2] * 4) + expected = np.einsum("ijkl->jil", expected).flatten() + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy_probs) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["numpy", "jax", "torch", "tensorflow"]) + @pytest.mark.parametrize( + "subset_wires,expected", + [ + ([0, 1], [0.25, 0.25, 0.25, 0.25]), + ([1, 2], [0.5, 0, 0.5, 0]), + ([0, 2], [0.5, 0, 0.5, 0]), + ([2, 0], [0.5, 0.5, 0, 0]), + ([2, 1], [0.5, 0.5, 0, 0]), + ([1, 2, 0], [0.25, 0.25, 0, 0, 0.25, 0.25, 0, 0]), + ], + ) + def test_process_state(self, interface, subset_wires, expected): + """Tests that process_state functions as expected with all interfaces.""" + state = qml.math.array([1 / 2, 0] * 4, like=interface) + wires = qml.wires.Wires(range(3)) + subset_probs = qml.probs(wires=subset_wires).process_state(state, wires) + assert subset_probs.shape == (len(expected),) + assert qml.math.allclose(subset_probs, expected) + + @pytest.mark.all_interfaces + @pytest.mark.parametrize("interface", ["numpy", "jax", "torch", "tensorflow"]) + @pytest.mark.parametrize( + "subset_wires,expected", + [ + ([1, 2], [[0.5, 0, 0.5, 0], [0, 0.5, 0, 0.5]]), + ([2, 0], [[0.5, 0.5, 0, 0], [0, 0, 0.5, 0.5]]), + ( + [1, 2, 0], + [[0.25, 0.25, 0, 0, 0.25, 0.25, 0, 0], [0, 0, 0.25, 0.25, 0, 0, 0.25, 0.25]], + ), + ], + ) + def test_process_state_batched(self, interface, subset_wires, expected): + """Tests that process_state functions as expected with all interfaces with batching.""" + states = qml.math.array([[1 / 2, 0] * 4, [0, 1 / 2] * 4], like=interface) + wires = qml.wires.Wires(range(3)) + subset_probs = qml.probs(wires=subset_wires).process_state(states, wires) + assert subset_probs.shape == qml.math.shape(expected) + assert qml.math.allclose(subset_probs, expected) + + def test_integration(self, tol, mocker): + """Test the probability is correct for a known state preparation.""" + dev = qml.device("default.qubit", wires=2) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=1) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[0, 1]) + + # expected probability, using [00, 01, 10, 11] + # ordering, is [0.5, 0.5, 0, 0] + + res = circuit() + expected = np.array([0.5, 0.5, 0, 0]) + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("shots", [100, [1, 10, 100]]) + def test_integration_analytic_false(self, tol, mocker, shots): + """Test the probability is correct for a known state preparation when the + analytic attribute is set to False.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(): + qml.PauliX(0) + return qml.probs(wires=dev.wires) + + res = circuit() + expected = np.array([0, 0, 0, 0, 1, 0, 0, 0]) + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("shots", [None, 100]) + def test_batch_size(self, mocker, shots): + """Test the probability is correct for a batched input.""" + dev = qml.device("default.qubit", wires=1, shots=shots) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(x): + qml.RX(x, 0) + return qml.probs(wires=dev.wires) # TODO: Use ``qml.probs()`` when supported + + x = np.array([0, np.pi / 2]) + res = circuit(x) + expected = [[1.0, 0.0], [0.5, 0.5]] + assert np.allclose(res, expected, atol=0.1, rtol=0.1) + + custom_measurement_process(dev, spy) + + @pytest.mark.autograd + def test_numerical_analytic_diff_agree(self, tol, mocker): + """Test that the finite difference and parameter shift rule + provide the same Jacobian.""" + w = 4 + dev = qml.device("default.qubit", wires=w) + spy = mocker.spy(qml.QubitDevice, "probability") + + def circuit(x, y, z): + for i in range(w): + qml.RX(x, wires=i) + qml.PhaseShift(z, wires=i) + qml.RY(y, wires=i) + + qml.CNOT(wires=[0, 1]) + qml.CNOT(wires=[1, 2]) + qml.CNOT(wires=[2, 3]) + + return qml.probs(wires=[1, 3]) + + params = pnp.array([0.543, -0.765, -0.3], requires_grad=True) + + circuit_F = qml.QNode(circuit, dev, diff_method="finite-diff") + circuit_A = qml.QNode(circuit, dev, diff_method="parameter-shift") + res_F = qml.jacobian(circuit_F)(*params) + res_A = qml.jacobian(circuit_A)(*params) + + # Both jacobians should be of shape (2**prob.wires, num_params) + assert isinstance(res_F, tuple) and len(res_F) == 3 + assert all(_r.shape == (2**2,) for _r in res_F) + assert isinstance(res_A, tuple) and len(res_A) == 3 + assert all(_r.shape == (2**2,) for _r in res_A) + + # Check that they agree up to numeric tolerance + assert all(np.allclose(_rF, _rA, atol=tol, rtol=0) for _rF, _rA in zip(res_F, res_A)) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) + def test_prob_generalize_param_one_qubit(self, hermitian, tol, mocker): + """Test that the correct probability is returned.""" + dev = qml.device("default.qubit", wires=1) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(x): + qml.RZ(x, wires=0) + return qml.probs(op=qml.Hermitian(hermitian, wires=0)) + + res = circuit(0.56) + + def circuit_rotated(x): + qml.RZ(x, wires=0) + qml.Hermitian(hermitian, wires=0).diagonalizing_gates() + + state = np.array([1, 0]) + matrix = qml.matrix(circuit_rotated)(0.56) + state = np.dot(matrix, state) + expected = np.reshape(np.abs(state) ** 2, [2] * 1) + expected = expected.flatten() + + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) + def test_prob_generalize_param(self, hermitian, tol, mocker): + """Test that the correct probability is returned.""" + dev = qml.device("default.qubit", wires=3) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(x, y): + qml.RZ(x, wires=0) + qml.CNOT(wires=[0, 1]) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 2]) + return qml.probs(op=qml.Hermitian(hermitian, wires=0)) + + res = circuit(0.56, 0.1) + + def circuit_rotated(x, y): + qml.RZ(x, wires=0) + qml.CNOT(wires=[0, 1]) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 2]) + qml.Hermitian(hermitian, wires=0).diagonalizing_gates() + + state = np.array([1, 0, 0, 0, 0, 0, 0, 0]) + matrix = qml.matrix(circuit_rotated)(0.56, 0.1) + state = np.dot(matrix, state) + expected = np.reshape(np.abs(state) ** 2, [2] * 3) + expected = np.einsum("ijk->i", expected).flatten() + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) + def test_prob_generalize_param_multiple(self, hermitian, tol, mocker): + """Test that the correct probability is returned.""" + dev = qml.device("default.qubit", wires=3) + spy = mocker.spy(qml.QubitDevice, "probability") + + @qml.qnode(dev) + def circuit(x, y): + qml.RZ(x, wires=0) + qml.CNOT(wires=[0, 1]) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 2]) + return ( + qml.probs(op=qml.Hermitian(hermitian, wires=0)), + qml.probs(wires=[1]), + qml.probs(wires=[2]), + ) + + res = circuit(0.56, 0.1) + res = np.reshape(res, (3, 2)) + + def circuit_rotated(x, y): + qml.RZ(x, wires=0) + qml.CNOT(wires=[0, 1]) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 2]) + qml.Hermitian(hermitian, wires=0).diagonalizing_gates() + + state = np.array([1, 0, 0, 0, 0, 0, 0, 0]) + matrix = qml.matrix(circuit_rotated)(0.56, 0.1) + state = np.dot(matrix, state) + + expected = np.reshape(np.abs(state) ** 2, [2] * 3) + expected_0 = np.einsum("ijk->i", expected).flatten() + expected_1 = np.einsum("ijk->j", expected).flatten() + expected_2 = np.einsum("ijk->k", expected).flatten() + + assert np.allclose(res[0], expected_0, atol=tol, rtol=0) + assert np.allclose(res[1], expected_1, atol=tol, rtol=0) + assert np.allclose(res[2], expected_2, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) + @pytest.mark.parametrize("wire", [0, 1, 2, 3]) + def test_prob_generalize_initial_state(self, hermitian, wire, init_state, tol, mocker): + """Test that the correct probability is returned.""" + # pylint:disable=too-many-arguments + dev = qml.device("default.qubit", wires=4) + spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + qml.PauliX(wires=0) + qml.PauliX(wires=1) + qml.PauliX(wires=2) + qml.PauliX(wires=3) + return qml.probs(op=qml.Hermitian(hermitian, wires=wire)) + + res = circuit() + + def circuit_rotated(): + qml.PauliX(wires=0) + qml.PauliX(wires=1) + qml.PauliX(wires=2) + qml.PauliX(wires=3) + qml.Hermitian(hermitian, wires=wire).diagonalizing_gates() + + matrix = qml.matrix(circuit_rotated)() + state = np.dot(matrix, state) + expected = np.reshape(np.abs(state) ** 2, [2] * 4) + + if wire == 0: + expected = np.einsum("ijkl->i", expected).flatten() + elif wire == 1: + expected = np.einsum("ijkl->j", expected).flatten() + elif wire == 2: + expected = np.einsum("ijkl->k", expected).flatten() + elif wire == 3: + expected = np.einsum("ijkl->l", expected).flatten() + + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("operation", [qml.PauliX, qml.PauliY, qml.Hadamard]) + @pytest.mark.parametrize("wire", [0, 1, 2, 3]) + def test_operation_prob(self, operation, wire, init_state, tol, mocker): + "Test the rotated probability with different wires and rotating operations." + # pylint:disable=too-many-arguments + dev = qml.device("default.qubit", wires=4) + spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + qml.PauliY(wires=2) + qml.PauliZ(wires=3) + return qml.probs(op=operation(wires=wire)) + + res = circuit() + + def circuit_rotated(): + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + qml.PauliY(wires=2) + qml.PauliZ(wires=3) + operation(wires=wire).diagonalizing_gates() + + matrix = qml.matrix(circuit_rotated)() + state = np.dot(matrix, state) + expected = np.reshape(np.abs(state) ** 2, [2] * 4) + + if wire == 0: + expected = np.einsum("ijkl->i", expected).flatten() + elif wire == 1: + expected = np.einsum("ijkl->j", expected).flatten() + elif wire == 2: + expected = np.einsum("ijkl->k", expected).flatten() + elif wire == 3: + expected = np.einsum("ijkl->l", expected).flatten() + + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("observable", [(qml.PauliX, qml.PauliY)]) + def test_observable_tensor_prob(self, observable, init_state, tol, mocker): + "Test the rotated probability with a tensor observable." + dev = qml.device("default.qubit", wires=4) + spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + qml.PauliY(wires=2) + qml.PauliZ(wires=3) + return qml.probs(op=observable[0](wires=0) @ observable[1](wires=1)) + + res = circuit() + + def circuit_rotated(): + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + qml.PauliY(wires=2) + qml.PauliZ(wires=3) + observable[0](wires=0).diagonalizing_gates() + observable[1](wires=1).diagonalizing_gates() + + matrix = qml.matrix(circuit_rotated)() + state = np.dot(matrix, state) + expected = np.reshape(np.abs(state) ** 2, [2] * 4) + + expected = np.einsum("ijkl->ij", expected).flatten() + + assert np.allclose(res, expected, atol=tol, rtol=0) + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize("coeffs, obs", [([1, 1], [qml.PauliX(wires=0), qml.PauliX(wires=1)])]) + def test_hamiltonian_error(self, coeffs, obs, init_state): + "Test that an error is returned for hamiltonians." + H = qml.Hamiltonian(coeffs, obs) + + dev = qml.device("default.qubit", wires=4) + state = init_state(4) + + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(4))) + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + qml.PauliY(wires=2) + qml.PauliZ(wires=3) + return qml.probs(op=H) + + with pytest.raises( + qml.QuantumFunctionError, + match="Hamiltonians are not supported for rotating probabilities.", + ): + circuit() + + @pytest.mark.parametrize( + "operation", [qml.SingleExcitation, qml.SingleExcitationPlus, qml.SingleExcitationMinus] + ) + def test_generalize_prob_not_hermitian(self, operation): + """Test that Operators that do not have a diagonalizing_gates representation cannot + be used in probability measurements.""" + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.PauliX(wires=0) + qml.PauliZ(wires=1) + return qml.probs(op=operation(0.56, wires=[0, 1])) + + with pytest.raises( + qml.QuantumFunctionError, + match="does not define diagonalizing gates : cannot be used to rotate the probability", + ): + circuit() + + @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) + def test_prob_wires_and_hermitian(self, hermitian): + """Test that we can cannot give simultaneously wires and a hermitian.""" + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.PauliX(wires=0) + return qml.probs(op=qml.Hermitian(hermitian, wires=0), wires=1) + + with pytest.raises( + qml.QuantumFunctionError, + match="Cannot specify the wires to probs if an observable is " + "provided. The wires for probs will be determined directly from the observable.", + ): + circuit() + + @pytest.mark.parametrize( + "wires, expected", + [ + ( + [0], + [ + [[0, 0, 0.5], [1, 1, 0.5]], + [[0.5, 0.5, 0], [0.5, 0.5, 1]], + [[0, 0.5, 1], [1, 0.5, 0]], + ], + ), + ( + [0, 1], + [ + [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], + [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], + [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], + ], + ), + ], + ) + def test_estimate_probability_with_binsize_with_broadcasting(self, wires, expected): + """Tests the estimate_probability method with a bin size and parameter broadcasting""" + samples = np.array( + [ + [[1, 0], [1, 1], [1, 1], [1, 1], [1, 1], [0, 1]], + [[0, 0], [1, 1], [1, 1], [0, 0], [1, 1], [1, 1]], + [[1, 0], [1, 1], [1, 1], [0, 0], [0, 1], [0, 0]], + ] + ) + + res = qml.probs(wires=wires).process_samples( + samples=samples, wire_order=wires, shot_range=None, bin_size=2 + ) + + assert np.allclose(res, expected) + + def test_non_commuting_probs_raises_error(self): + dev = qml.device("default.qubit", wires=5) + + @qml.qnode(dev) + def circuit(x, y): + qml.RX(x, wires=[0]) + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliX(0)), qml.probs(wires=[0, 1]) + + with pytest.raises( + qml.QuantumFunctionError, match="Only observables that are qubit-wise commuting" + ): + circuit(1, 2) + + def test_commuting_probs_in_computational_basis(self): + """Test that `qml.probs` can be used in the computational basis with other commuting observables.""" + dev = qml.device("default.qubit", wires=5) + + @qml.qnode(dev) + def circuit(x, y): + qml.RX(x, wires=[0]) + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)), qml.probs(wires=[0, 1]) + + res = circuit(1, 2) + + @qml.qnode(dev) + def circuit2(x, y): + qml.RX(x, wires=[0]) + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliZ(0)) + + @qml.qnode(dev) + def circuit3(x, y): + qml.RX(x, wires=[0]) + qml.RY(y, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.probs(wires=[0, 1]) + + res2 = circuit2(1, 2) + res3 = circuit3(1, 2) + + assert res[0] == res2 + assert qml.math.allequal(res[1:], res3) diff --git a/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py new file mode 100644 index 00000000000..ccaab4fb5bc --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py @@ -0,0 +1,380 @@ +# Copyright 2018-2023 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. +"""Tests for the purity measurement process""" + +import pytest + +import numpy as np +import pennylane as qml + +from pennylane.measurements import PurityMP, Shots + +# pylint: disable=too-many-arguments + + +def expected_purity_ising_xx(param): + """Returns the analytical purity for subsystems of the IsingXX""" + + eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + return eig_1**2 + eig_2**2 + + +def expected_purity_grad_ising_xx(param): + """The analytic gradient purity for the IsingXX""" + + eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + grad_expected_purity = ( + 2 + * eig_1 + * (np.sin(param / 2) ** 3 * np.cos(param / 2) - np.sin(param / 2) * np.cos(param / 2) ** 3) + / np.sqrt(1 - 4 * np.sin(param / 2) ** 2 * np.cos(param / 2) ** 2) + ) + ( + 2 + * eig_2 + * ( + np.sin(param / 2) + * np.cos(param / 2) + * (np.cos(param / 2) ** 2 - np.sin(param / 2) ** 2) + ) + / np.sqrt(1 - 4 * np.sin(param / 2) ** 2 * np.cos(param / 2) ** 2) + ) + return grad_expected_purity + + +class TestPurityUnitTest: + """Tests for purity measurements""" + + def test_return_type(self): + """Test that the return type is defined and the purity enum.""" + m = PurityMP(wires=qml.wires.Wires((0, 1))) + assert m.return_type is qml.measurements.Purity + + def test_numeric_type(self): + """Test that the numeric type of PurityMP is float.""" + m = PurityMP(wires=qml.wires.Wires(0)) + assert m.numeric_type is float + + @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ((1, 10), ((), ()))]) + def test_shape_new(self, shots, shape): + """Test the ``shape_new`` method.""" + meas = qml.purity(wires=0) + dev = qml.device("default.qubit", wires=1, shots=shots) + assert meas.shape(dev, Shots(shots)) == shape + + +class TestPurityIntegration: + """Test the purity meausrement with qnodes and devices.""" + + devices = ["default.qubit", "lightning.qubit", "default.mixed"] + grad_supported_devices = ["default.qubit", "default.mixed"] + mix_supported_devices = ["default.mixed"] + + diff_methods = ["backprop", "finite-diff"] + + parameters = np.linspace(0, 2 * np.pi, 3) + probs = np.array([0.001, 0.01, 0.1, 0.2]) + + wires_list = [([0], True), ([1], True), ([0, 1], False)] + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + def test_IsingXX_qnode_purity(self, device, param, wires, is_partial): + """Tests purity for a qnode""" + + dev = qml.device(device, wires=2) + + @qml.qnode(dev) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + purity = circuit(param) + expected_purity = expected_purity_ising_xx(param) if is_partial else 1 + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.parametrize("device", mix_supported_devices) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("param", probs) + def test_bit_flip_qnode_purity(self, device, wires, param, is_partial): + """Tests purity for a qnode on a noisy device with bit flips""" + + dev = qml.device(device, wires=2) + + @qml.qnode(dev) + def circuit(p): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.BitFlip(p, wires=0) + qml.BitFlip(p, wires=1) + return qml.purity(wires=wires) + + purity = circuit(param) + expected_purity = ( + 0.5 + if is_partial + else 4 * (0.5 - (1 - param) * param) ** 2 + 4 * (1 - param) ** 2 * param**2 + ) + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.parametrize("device", grad_supported_devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("diff_method", diff_methods) + def test_IsingXX_qnode_purity_grad(self, device, param, wires, is_partial, diff_method): + """Tests purity for a qnode""" + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, diff_method=diff_method) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + grad_purity = qml.grad(circuit)(param) + expected_grad = expected_purity_grad_ising_xx(param) if is_partial else 0 + assert qml.math.allclose(grad_purity, expected_grad, rtol=1e-04, atol=1e-05) + + @pytest.mark.parametrize("device", mix_supported_devices) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("param", probs) + @pytest.mark.parametrize("diff_method", diff_methods) + def test_bit_flip_qnode_purity_grad(self, device, wires, param, is_partial, diff_method): + """Tests gradient of purity for a qnode on a noisy device with bit flips""" + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, diff_method=diff_method) + def circuit(p): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.BitFlip(p, wires=0) + qml.BitFlip(p, wires=1) + return qml.purity(wires=wires) + + purity_grad = qml.grad(circuit)(param) + expected_purity_grad = 0 if is_partial else 32 * (param - 0.5) ** 3 + assert qml.math.allclose(purity_grad, expected_purity_grad, rtol=1e-04, atol=1e-05) + + @pytest.mark.jax + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("interface", ["jax"]) + def test_IsingXX_qnode_purity_jax(self, device, param, wires, is_partial, interface): + """Test purity for a QNode with jax interface.""" + + import jax.numpy as jnp + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + purity = circuit(jnp.array(param)) + expected_purity = expected_purity_ising_xx(param) if is_partial else 1 + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.jax + @pytest.mark.parametrize("device", grad_supported_devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax"]) + def test_IsingXX_qnode_purity_grad_jax( + self, device, param, wires, is_partial, diff_method, interface + ): + """Test purity for a QNode gradient with Jax.""" + + import jax + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + grad_purity = jax.grad(circuit)(jax.numpy.array(param)) + grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 + + assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) + + @pytest.mark.jax + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("interface", ["jax-jit"]) + def test_IsingXX_qnode_purity_jax_jit(self, device, param, wires, is_partial, interface): + """Test purity for a QNode with jax interface.""" + + import jax + import jax.numpy as jnp + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + purity = jax.jit(circuit)(jnp.array(param)) + expected_purity = expected_purity_ising_xx(param) if is_partial else 1 + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.jax + @pytest.mark.parametrize("device", grad_supported_devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax-jit"]) + def test_IsingXX_qnode_purity_grad_jax_jit( + self, device, param, wires, is_partial, diff_method, interface + ): + """Test purity for a QNode gradient with Jax.""" + + import jax + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + grad_purity = jax.jit(jax.grad(circuit))(jax.numpy.array(param)) + grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 + + assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) + + @pytest.mark.torch + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("interface", ["torch"]) + def test_IsingXX_qnode_purity_torch(self, device, param, wires, is_partial, interface): + """Tests purity for a qnode""" + + import torch + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + purity = circuit(torch.tensor(param)) + expected_purity = expected_purity_ising_xx(param) if is_partial else 1 + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.torch + @pytest.mark.parametrize("device", grad_supported_devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["torch"]) + def test_IsingXX_qnode_purity_grad_torch( + self, device, param, wires, is_partial, diff_method, interface + ): + """Test purity for a QNode gradient with torch.""" + + import torch + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + expected_grad = expected_purity_grad_ising_xx(param) if is_partial else 0 + + param = torch.tensor(param, dtype=torch.float64, requires_grad=True) + purity = circuit(param) + purity.backward() # pylint: disable=no-member + grad_purity = param.grad + + assert qml.math.allclose(grad_purity, expected_grad, rtol=1e-04, atol=1e-05) + + @pytest.mark.tf + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("interface", ["tf"]) + def test_IsingXX_qnode_purity_tf(self, device, param, wires, is_partial, interface): + """Tests purity for a qnode""" + + import tensorflow as tf + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + purity = circuit(tf.Variable(param)) + expected_purity = expected_purity_ising_xx(param) if is_partial else 1 + assert qml.math.allclose(purity, expected_purity) + + @pytest.mark.tf + @pytest.mark.parametrize("device", grad_supported_devices) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("wires,is_partial", wires_list) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["tf"]) + def test_IsingXX_qnode_purity_grad_tf( + self, device, param, wires, is_partial, diff_method, interface + ): + """Test purity for a QNode gradient with tf.""" + + import tensorflow as tf + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.purity(wires=wires) + + grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 + + param = tf.Variable(param) + with tf.GradientTape() as tape: + purity = circuit(param) + + grad_purity = tape.gradient(purity, param) + + assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) + + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("param", parameters) + def test_qnode_entropy_custom_wires(self, device, param): + """Test that purity can be returned with custom wires.""" + + dev = qml.device(device, wires=["a", 1]) + + @qml.qnode(dev) + def circuit(x): + qml.IsingXX(x, wires=["a", 1]) + return qml.purity(wires=["a"]) + + purity = circuit(param) + expected_purity = expected_purity_ising_xx(param) + assert qml.math.allclose(purity, expected_purity) diff --git a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py new file mode 100644 index 00000000000..18b9d3f5ad3 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py @@ -0,0 +1,441 @@ +# Copyright 2018-2020 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 sample module""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import MeasurementShapeError, Sample, Shots +from pennylane.operation import EigvalsUndefinedError, Operator + +# pylint: disable=protected-access, no-member + + +# TODO: Remove this when new CustomMP are the default +def custom_measurement_process(device, spy): + assert len(spy.call_args_list) > 0 # make sure method is mocked properly + + samples = device._samples + call_args_list = list(spy.call_args_list) + for call_args in call_args_list: + meas = call_args.args[1] + shot_range, bin_size = (call_args.kwargs["shot_range"], call_args.kwargs["bin_size"]) + if isinstance(meas, Operator): + meas = qml.sample(op=meas) + assert qml.math.allequal( + device.sample(call_args.args[1], **call_args.kwargs), + meas.process_samples( + samples=samples, + wire_order=device.wires, + shot_range=shot_range, + bin_size=bin_size, + ), + ) + + +class TestSample: + """Tests for the sample function""" + + @pytest.mark.parametrize("n_sample", (1, 10)) + def test_sample_dimension(self, mocker, n_sample): + """Test that the sample function outputs samples of the right size""" + + dev = qml.device("default.qubit", wires=2, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.54, wires=0) + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliX(1)) + + output = circuit() + + assert len(output) == 2 + assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == ( + (n_sample,) if not n_sample == 1 else () + ) + assert circuit._qfunc_output[1].shape(dev, Shots(n_sample)) == ( + (n_sample,) if not n_sample == 1 else () + ) + + custom_measurement_process(dev, spy) + + @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") + def test_sample_combination(self, mocker): + """Test the output of combining expval, var and sample""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=3, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + qml.RX(0.54, wires=0) + + return qml.sample(qml.PauliZ(0)), qml.expval(qml.PauliX(1)), qml.var(qml.PauliY(2)) + + result = circuit() + + assert len(result) == 3 + assert np.array_equal(result[0].shape, (n_sample,)) + assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == (n_sample,) + assert isinstance(result[1], np.ndarray) + assert isinstance(result[2], np.ndarray) + + custom_measurement_process(dev, spy) + + def test_single_wire_sample(self, mocker): + """Test the return type and shape of sampling a single wire""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=1, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.54, wires=0) + return qml.sample(qml.PauliZ(0)) + + result = circuit() + + assert isinstance(result, np.ndarray) + assert np.array_equal(result.shape, (n_sample,)) + assert circuit._qfunc_output.shape(dev, Shots(n_sample)) == (n_sample,) + + custom_measurement_process(dev, spy) + + def test_multi_wire_sample_regular_shape(self, mocker): + """Test the return type and shape of sampling multiple wires + where a rectangular array is expected""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=3, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)), qml.sample(qml.PauliZ(2)) + + result = circuit() + + assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == (n_sample,) + assert circuit._qfunc_output[1].shape(dev, Shots(n_sample)) == (n_sample,) + assert circuit._qfunc_output[2].shape(dev, Shots(n_sample)) == (n_sample,) + + # If all the dimensions are equal the result will end up to be a proper rectangular array + assert isinstance(result, tuple) + assert len(result) == 3 + assert result[0].dtype == np.dtype("int") + + custom_measurement_process(dev, spy) + + @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") + def test_sample_output_type_in_combination(self, mocker): + """Test the return type and shape of sampling multiple works + in combination with expvals and vars""" + n_sample = 10 + + dev = qml.device("default.qubit", wires=3, shots=n_sample) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(): + return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)), qml.sample(qml.PauliZ(2)) + + result = circuit() + + # If all the dimensions are equal the result will end up to be a proper rectangular array + assert len(result) == 3 + assert isinstance(result[0], np.ndarray) + assert isinstance(result[1], np.ndarray) + assert result[2].dtype == np.dtype("int") + assert np.array_equal(result[2].shape, (n_sample,)) + + custom_measurement_process(dev, spy) + + def test_not_an_observable(self, mocker): + """Test that a UserWarning is raised if the provided + argument might not be hermitian.""" + dev = qml.device("default.qubit", wires=2, shots=10) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.52, wires=0) + return qml.sample(qml.prod(qml.PauliX(0), qml.PauliZ(0))) + + with pytest.warns(UserWarning, match="Prod might not be hermitian."): + _ = circuit() + + custom_measurement_process(dev, spy) + + def test_observable_return_type_is_sample(self, mocker): + """Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`""" + n_shots = 10 + dev = qml.device("default.qubit", wires=1, shots=n_shots) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + res = qml.sample(qml.PauliZ(0)) + assert res.return_type is Sample + return res + + circuit() + + custom_measurement_process(dev, spy) + + def test_providing_observable_and_wires(self): + """Test that a ValueError is raised if both an observable is provided and wires are specified""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + return qml.sample(qml.PauliZ(0), wires=[0, 1]) + + with pytest.raises( + ValueError, + match="Cannot specify the wires to sample if an observable is provided." + " The wires to sample will be determined directly from the observable.", + ): + _ = circuit() + + def test_providing_no_observable_and_no_wires(self, mocker): + """Test that we can provide no observable and no wires to sample function""" + dev = qml.device("default.qubit", wires=2, shots=1000) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + res = qml.sample() + assert res.obs is None + assert res.wires == qml.wires.Wires([]) + return res + + circuit() + + custom_measurement_process(dev, spy) + + def test_providing_no_observable_and_no_wires_shot_vector(self, mocker): + """Test that we can provide no observable and no wires to sample + function when using a shot vector""" + num_wires = 2 + + shots1 = 1 + shots2 = 10 + shots3 = 1000 + dev = qml.device("default.qubit", wires=num_wires, shots=[shots1, shots2, shots3]) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + return qml.sample() + + res = circuit() + + assert isinstance(res, tuple) + + expected_shapes = [(num_wires,), (shots2, num_wires), (shots3, num_wires)] + assert len(res) == len(expected_shapes) + assert all(r.shape == exp_shape for r, exp_shape in zip(res, expected_shapes)) + + # assert first wire is always the same as second + # pylint: disable=unsubscriptable-object + assert np.all(res[0][0] == res[0][1]) + assert np.all(res[1][:, 0] == res[1][:, 1]) + assert np.all(res[2][:, 0] == res[2][:, 1]) + + custom_measurement_process(dev, spy) + + def test_providing_no_observable_and_wires(self, mocker): + """Test that we can provide no observable but specify wires to the sample function""" + wires = [0, 2] + wires_obj = qml.wires.Wires(wires) + dev = qml.device("default.qubit", wires=3, shots=1000) + spy = mocker.spy(qml.QubitDevice, "sample") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + res = qml.sample(wires=wires) + + assert res.obs is None + assert res.wires == wires_obj + return res + + circuit() + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize( + "obs,exp", + [ + # Single observables + (None, int), # comp basis samples + (qml.PauliX(0), int), + (qml.PauliY(0), int), + (qml.PauliZ(0), int), + (qml.Hadamard(0), int), + (qml.Identity(0), int), + (qml.Hermitian(np.diag([1, 2]), 0), float), + (qml.Hermitian(np.diag([1.0, 2.0]), 0), float), + # Tensor product observables + ( + qml.PauliX("c") + @ qml.PauliY("a") + @ qml.PauliZ(1) + @ qml.Hadamard("wire1") + @ qml.Identity("b"), + int, + ), + (qml.Projector([0, 1], wires=[0, 1]) @ qml.PauliZ(2), float), + (qml.Hermitian(np.array(np.eye(2)), wires=[0]) @ qml.PauliZ(2), float), + ( + qml.Projector([0, 1], wires=[0, 1]) @ qml.Hermitian(np.array(np.eye(2)), wires=[2]), + float, + ), + ], + ) + def test_numeric_type(self, obs, exp): + """Test that the numeric type is correct.""" + res = qml.sample(obs) if obs is not None else qml.sample() + assert res.numeric_type is exp + + def test_shape_no_shots_error(self): + """Test that the appropriate error is raised with no shots are specified""" + dev = qml.device("default.qubit", wires=2, shots=None) + shots = Shots(None) + mp = qml.sample() + + with pytest.raises( + MeasurementShapeError, match="Shots are required to obtain the shape of the measurement" + ): + _ = mp.shape(dev, shots) + + @pytest.mark.parametrize( + "obs", + [ + None, + qml.PauliZ(0), + qml.Hermitian(np.diag([1, 2]), 0), + qml.Hermitian(np.diag([1.0, 2.0]), 0), + ], + ) + def test_shape(self, obs): + """Test that the shape is correct.""" + shots = 10 + dev = qml.device("default.qubit", wires=3, shots=shots) + res = qml.sample(obs) if obs is not None else qml.sample() + expected = (shots,) if obs is not None else (shots, 3) + assert res.shape(dev, Shots(shots)) == expected + + @pytest.mark.parametrize("n_samples", (1, 10)) + def test_shape_wires(self, n_samples): + """Test that the shape is correct when wires are provided.""" + dev = qml.device("default.qubit", wires=3, shots=n_samples) + mp = qml.sample(wires=(0, 1)) + assert mp.shape(dev, Shots(n_samples)) == (n_samples, 2) if n_samples != 1 else (2,) + + @pytest.mark.parametrize( + "obs", + [ + None, + qml.PauliZ(0), + qml.Hermitian(np.diag([1, 2]), 0), + qml.Hermitian(np.diag([1.0, 2.0]), 0), + ], + ) + def test_shape_shot_vector(self, obs): + """Test that the shape is correct with the shot vector too.""" + shot_vector = (1, 2, 3) + dev = qml.device("default.qubit", wires=3, shots=shot_vector) + res = qml.sample(obs) if obs is not None else qml.sample() + expected = ((), (2,), (3,)) if obs is not None else ((3,), (2, 3), (3, 3)) + assert res.shape(dev, Shots(shot_vector)) == expected + + def test_shape_shot_vector_obs(self): + """Test that the shape is correct with the shot vector and a observable too.""" + shot_vec = (2, 2) + dev = qml.device("default.qubit", wires=3, shots=shot_vec) + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(wires=0) + qml.PauliZ(0) + return qml.sample(qml.PauliZ(0)) + + binned_samples = circuit() + + assert isinstance(binned_samples, tuple) + assert len(binned_samples) == len(shot_vec) + # pylint: disable=unsubscriptable-object + assert binned_samples[0].shape == (shot_vec[0],) + + def test_sample_empty_wires(self): + """Test that using ``qml.sample`` with an empty wire list raises an error.""" + with pytest.raises(ValueError, match="Cannot set an empty list of wires."): + qml.sample(wires=[]) + + @pytest.mark.parametrize("shots", [2, 100]) + def test_sample_no_arguments(self, shots): + """Test that using ``qml.sample`` with no arguments returns the samples of all wires.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + + @qml.qnode(dev) + def circuit(): + return qml.sample() + + res = circuit() + + # pylint: disable=comparison-with-callable + assert res.shape == (shots, 3) + + def test_new_sample_with_operator_with_no_eigvals(self): + """Test that calling process with an operator that has no eigvals defined raises an error.""" + + class DummyOp(Operator): # pylint: disable=too-few-public-methods + num_wires = 1 + + with pytest.raises(EigvalsUndefinedError, match="Cannot compute samples of"): + qml.sample(op=DummyOp(0)).process_samples(samples=np.array([[1, 0]]), wire_order=[0]) + + +@pytest.mark.jax +@pytest.mark.parametrize("samples", (1, 10)) +def test_jitting_with_sampling_on_subset_of_wires(samples): + """Test case covering bug in Issue #3904. Sampling should be jit-able + when sampling occurs on a subset of wires. The bug was occuring due an improperly + set shape method.""" + import jax + + jax.config.update("jax_enable_x64", True) + + dev = qml.device("default.qubit", wires=3, shots=samples) + + @qml.qnode(dev, interface="jax") + def circuit(x): + qml.RX(x, wires=0) + return qml.sample(wires=(0, 1)) + + results = jax.jit(circuit)(jax.numpy.array(0.123, dtype=jax.numpy.float64)) + + expected = (2,) if samples == 1 else (samples, 2) + assert results.shape == expected + assert ( + circuit._qfunc_output.shape(dev, Shots(samples)) == (samples, 2) if samples != 1 else (2,) + ) diff --git a/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py new file mode 100644 index 00000000000..abc709071e1 --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py @@ -0,0 +1,252 @@ +# Copyright 2018-2023 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 :mod:`pennylane.shots`. +""" + +import copy +import pytest + +from pennylane.measurements import Shots, ShotCopies + +ERROR_MSG = "Shots must be a single positive integer, a tuple" + + +class TestShotCopies: + """Test that the ShotCopies class displays well.""" + + sc_data = (ShotCopies(1, 1), ShotCopies(100, 1), ShotCopies(100, 2), ShotCopies(10, 100)) + + str_data = ( + "1 shots", + "100 shots", + "100 shots x 2", + "10 shots x 100", + ) + + @pytest.mark.parametrize("expected_str, sc", zip(str_data, sc_data)) + def test_str(self, expected_str, sc): + """Test the str method works well""" + assert expected_str == str(sc) + + repr_data = ( + "ShotCopies(1 shots x 1)", + "ShotCopies(100 shots x 1)", + "ShotCopies(100 shots x 2)", + "ShotCopies(10 shots x 100)", + ) + + @pytest.mark.parametrize("expected_str, sc", zip(repr_data, sc_data)) + def test_repr(self, expected_str, sc): + """Test the repr method works well""" + assert expected_str == repr(sc) + + +class TestShotsConstruction: + """Tests the Shots class.""" + + def test_copy(self): + """Tests that creating a Shots from another Shots instance returns the same instance.""" + x = Shots(123) + y = Shots(x) + assert y is x + assert y._frozen # pylint:disable=protected-access + + z = copy.copy(x) + assert z is x + assert z._frozen # pylint:disable=protected-access + + def test_deepcopy(self): + x = Shots([1, 1, 2, 3]) + y = copy.deepcopy(x) + assert y is x + assert y._frozen # pylint:disable=protected-access + + def test_None(self): + """Tests the constructor when shots is None.""" + shots1 = Shots(None) + shots2 = Shots() # this also defaults to None + assert shots1.shot_vector == () + assert shots2.shot_vector == () + assert shots1.total_shots is None + assert shots2.total_shots is None + + def test_int(self): + """Tests the constructor when shots is an int.""" + shots = Shots(100) + assert shots.shot_vector == (ShotCopies(100, 1),) + assert shots.total_shots == 100 + + def test_tuple(self): + """Tests the constructor when shots is a tuple.""" + shots = Shots((5, 6)) + assert shots.shot_vector == (ShotCopies(5, 1), ShotCopies(6, 1)) + assert shots.total_shots == 11 + assert isinstance(shots.shot_vector, tuple) + + shot_data = ( + Shots(None), + Shots(10), + Shots((1, 10, 100)), + Shots((1, 10, 10, 100, 100, 100)), + ) + + str_data = ( + "Shots(total=None)", + "Shots(total=10)", + "Shots(total=111, vector=[1 shots, 10 shots, 100 shots])", + "Shots(total=321, vector=[1 shots, 10 shots x 2, 100 shots x 3])", + ) + + @pytest.mark.parametrize("expected_str, shots_obj", zip(str_data, shot_data)) + def test_str(self, expected_str, shots_obj): + """Test that the string representation is correct.""" + assert expected_str == str(shots_obj) + + repr_data = ( + "Shots(total_shots=None, shot_vector=())", + "Shots(total_shots=10, shot_vector=(ShotCopies(10 shots x 1),))", + "Shots(total_shots=111, shot_vector=(ShotCopies(1 shots x 1), " + "ShotCopies(10 shots x 1), ShotCopies(100 shots x 1)))", + "Shots(total_shots=321, shot_vector=(ShotCopies(1 shots x 1), " + "ShotCopies(10 shots x 2), ShotCopies(100 shots x 3)))", + ) + + @pytest.mark.parametrize("expected_str, shots_obj", zip(repr_data, shot_data)) + def test_repr(self, expected_str, shots_obj): + """Test that the repr is correct""" + assert expected_str == repr(shots_obj) + + def test_eq(self): + """Test that the equality function behaves correctly""" + for s in self.shot_data: + assert s == copy.copy(s) + assert s == Shots(s.shot_vector if s.shot_vector else None) + + def test_eq_edge_case(self): + """Test edge cases for equality function are correct""" + assert Shots((1, 2)) != Shots((2, 1)) + assert Shots((1, 10, 1)) != Shots((1, 1, 10)) + assert Shots((5, 5)) != Shots(10) + assert Shots((1, 2, (10, 2))) == Shots((1, 2, 10, 10)) + + def test_hash(self): + """Test that the hash function behaves correctly""" + for s in self.shot_data: + hash_s = hash(s) + assert hash_s == hash(copy.copy(s)) + assert hash_s == hash(Shots(s.shot_vector if s.shot_vector else None)) + + @pytest.mark.parametrize( + "shots, expected", + [ + (100, [100]), + ([(100, 1)], [100]), + ([(100, 2)], [100, 100]), + ([100, 200], [100, 200]), + ([(100, 2), 200], [100, 100, 200]), + ([(100, 3), 200, (300, 2)], [100, 100, 100, 200, 300, 300]), + ], + ) + def test_iter(self, shots, expected): + """Test that iteration over Shots works correctly""" + actual = list(Shots(shots)) + assert actual == expected + + def test_sequence_all_tuple(self): + """Tests that a sequence of tuples is allowed.""" + shots = Shots([(1, 2), (1, 5), (3, 4)]) + assert shots.shot_vector == (ShotCopies(1, 7), ShotCopies(3, 4)) + assert shots.total_shots == 19 + assert isinstance(shots.shot_vector, tuple) + + @pytest.mark.parametrize( + "shot_list,expected,total", + [ + ( + [1, 3, 3, 4, 4, 4, 3], + (ShotCopies(1, 1), ShotCopies(3, 2), ShotCopies(4, 3), ShotCopies(3, 1)), + 22, + ), + ([5, 5, 5], (ShotCopies(5, 3),), 15), + ([1, (4, 2)], (ShotCopies(1, 1), ShotCopies(4, 2)), 9), + ((5,), (ShotCopies(5, 1),), 5), + ((5, 6, 7), (ShotCopies(5, 1), ShotCopies(6, 1), ShotCopies(7, 1)), 18), + (((5, 6)), (ShotCopies(5, 1), ShotCopies(6, 1)), 11), + (((5, 6),), (ShotCopies(5, 6),), 30), + (((5, 6), 7), (ShotCopies(5, 6), ShotCopies(7, 1)), 37), + ((5, (6, 7)), (ShotCopies(5, 1), ShotCopies(6, 7)), 47), + (((5, 6), (7, 8)), (ShotCopies(5, 6), ShotCopies(7, 8)), 86), + ], + ) + def test_sequence(self, shot_list, expected, total): + """Tests the constructor when shots is a Sequence[int].""" + shots = Shots(shot_list) + assert shots.shot_vector == expected + assert shots.total_shots == total + + @pytest.mark.parametrize("shot_arg", ["123", [1.1, 2], [-1, 2], 1.5, (1.1, 2)]) + def test_other_fails(self, shot_arg): + """Tests that all other values for shots is not allowed.""" + with pytest.raises(ValueError, match=ERROR_MSG): + _ = Shots(shot_arg) + + def test_zero_shots_fails(self): + with pytest.raises(ValueError, match=ERROR_MSG): + _ = Shots(0) + + +class TestProperties: + """Tests various properties of the Shots class.""" + + @pytest.mark.parametrize( + "shots,expected", + [ + (None, False), + (1, True), + ([1, 2], True), + ([1, (2, 3)], True), + ], + ) + def test_bool_dunder(self, shots, expected): + """Tests the Truthy/Falsy values of various Shots objects.""" + assert bool(Shots(shots)) is expected + + def test_Shots_frozen_after_init(self): + """Tests that Shots instances are frozen after creation.""" + shots = Shots(10) + with pytest.raises(AttributeError, match="Shots is an immutable class"): + shots.total_shots = 20 + + @pytest.mark.parametrize( + "shots,expected", [(None, False), (100, False), ([1, 2], True), [[100], False]] + ) + def test_has_partitioned_shots(self, shots, expected): + """Tests the has_partitioned_shots property.""" + assert Shots(shots).has_partitioned_shots is expected + + @pytest.mark.parametrize( + "shots, expected", + [ + (None, 0), + (10, 1), + ([10, 10], 2), + ([10, 10, 20], 3), + ([100, (10, 3)], 4), + ([(10, 3), (20, 2)], 5), + ], + ) + def test_num_copies(self, shots, expected): + """Tests the num_copies property.""" + assert Shots(shots).num_copies == expected diff --git a/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py new file mode 100644 index 00000000000..5198c77ecaa --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py @@ -0,0 +1,888 @@ +# Copyright 2018-2020 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 state module""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane import numpy as pnp +from pennylane.devices import DefaultQubit +from pennylane.measurements import State, StateMP, Shots, density_matrix, expval, state +from pennylane.math.quantum import reduce_statevector, reduce_dm +from pennylane.math.matrix_manipulation import _permute_dense_matrix + +# pylint: disable=no-member, comparison-with-callable, import-outside-toplevel + + +class TestStateMP: + """Tests for the State measurement process.""" + + @pytest.mark.parametrize( + "vec", + [ + np.array([0.6, 0.8j]), + np.eye(4)[3], + np.array([0.48j, 0.48, -0.64j, 0.36]), + ], + ) + def test_process_state_vector(self, vec): + """Test the processing of a state vector.""" + + mp = StateMP(wires=None) + assert mp.return_type == State + assert mp.numeric_type is complex + + processed = mp.process_state(vec, None) + assert qml.math.allclose(processed, vec) + + @pytest.mark.parametrize( + "vec, wires", + [ + (np.array([0.6, 0.8j]), [0]), + (np.eye(4, dtype=np.complex64)[3], [0]), + (np.array([0.48j, 0.48, -0.64j, 0.36]), [0, 1]), + (np.array([0.48j, 0.48, -0.64j, 0.36]), [0]), + ], + ) + def test_process_state_matrix_from_vec(self, vec, wires): + """Test the processing of a state vector into a matrix.""" + + mp = StateMP(wires=wires) + assert mp.return_type == State + assert mp.numeric_type is complex + + num_wires = int(np.log2(len(vec))) + processed = mp.process_state(vec, list(range(num_wires))) + assert qml.math.shape(processed) == (2 ** len(wires), 2 ** len(wires)) + if len(wires) == num_wires: + exp = np.outer(vec, vec.conj()) + else: + exp = reduce_statevector(vec, wires) + assert qml.math.allclose(processed, exp) + + @pytest.mark.xfail(reason="StateMP.process_state no longer supports density matrix parameters") + @pytest.mark.parametrize( + "mat, wires", + [ + (np.eye(4, dtype=np.complex64) / 4, [0]), + (np.eye(4, dtype=np.complex64) / 4, [1, 0]), + (np.outer([0.6, 0.8j], [0.6, -0.8j]), [0]), + (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [0, 1]), + (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [0]), + (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [1]), + ], + ) + def test_process_state_matrix_from_matrix(self, mat, wires): + """Test the processing of a density matrix into a matrix.""" + + mp = StateMP(wires=wires) + assert mp.return_type == State + assert mp.numeric_type is complex + + num_wires = int(np.log2(len(mat))) + order = list(range(num_wires)) + processed = mp.process_state(mat, order) + assert qml.math.shape(processed) == (2 ** len(wires), 2 ** len(wires)) + if len(wires) == num_wires: + exp = _permute_dense_matrix(mat, wires, order, None) + else: + exp = reduce_dm(mat, wires) + assert qml.math.allclose(processed, exp) + + +class TestState: + """Tests for the state function""" + + @pytest.mark.parametrize("wires", range(2, 5)) + 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(): + return state() + + state_val = func() + assert state_val.shape == (2**wires,) + assert state_val.dtype == np.complex128 + + def test_return_type_is_state(self): + """Test that the return type of the observable is State""" + + dev = qml.device("default.qubit", wires=1) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + return state() + + func() + obs = func.qtape.observables + assert len(obs) == 1 + assert obs[0].return_type is State + + @pytest.mark.parametrize("wires", range(2, 5)) + def test_state_correct_ghz(self, wires): + """Test that the correct state is returned when the circuit prepares a GHZ state""" + + dev = qml.device("default.qubit", wires=wires) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=0) + for i in range(wires - 1): + qml.CNOT(wires=[i, i + 1]) + return state() + + state_val = func() + assert np.allclose(np.sum(np.abs(state_val) ** 2), 1) + # pylint: disable=unsubscriptable-object + assert np.allclose(state_val[0], 1 / np.sqrt(2)) + assert np.allclose(state_val[-1], 1 / np.sqrt(2)) + + assert np.allclose(state().process_state(state=dev.state, wire_order=dev.wires), state_val) + + def test_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) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=0) + return state(), expval(qml.PauliZ(1)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The state or density matrix cannot be returned in combination with other return types", + ): + func() + + @pytest.mark.parametrize("wires", range(2, 5)) + def test_state_equal_to_dev_state(self, wires): + """Test that the returned state is equal to the one stored in dev.state for a template + circuit""" + + dev = qml.device("default.qubit", wires=wires) + + weights = np.random.random( + qml.templates.StronglyEntanglingLayers.shape(n_layers=3, n_wires=wires) + ) + + @qml.qnode(dev) + def func(): + qml.templates.StronglyEntanglingLayers(weights, wires=range(wires)) + return state() + + state_val = func() + assert np.allclose(state_val, func.device.state) + + @pytest.mark.tf + def test_interface_tf(self): + """Test that the state correctly outputs in the tensorflow interface""" + import tensorflow as tf + + dev = qml.device("default.qubit", wires=4) + + @qml.qnode(dev, interface="tf") + def func(): + for i in range(4): + qml.Hadamard(i) + return state() + + state_expected = 0.25 * tf.ones(16) + state_val = func() + + assert isinstance(state_val, tf.Tensor) + assert state_val.dtype == tf.complex128 + assert np.allclose(state_expected, state_val.numpy()) + assert state_val.shape == (16,) + + @pytest.mark.torch + def test_interface_torch(self): + """Test that the state correctly outputs in the torch interface""" + import torch + + dev = qml.device("default.qubit", wires=4) + + @qml.qnode(dev, interface="torch") + def func(): + for i in range(4): + qml.Hadamard(i) + return state() + + state_expected = 0.25 * torch.ones(16, dtype=torch.complex128) + state_val = func() + + assert isinstance(state_val, torch.Tensor) + assert state_val.dtype == torch.complex128 + assert torch.allclose(state_expected, state_val) + assert state_val.shape == (16,) + + @pytest.mark.autograd + def test_jacobian_not_supported(self): + """Test if an error is raised if the jacobian method is called via qml.grad""" + dev = qml.device("default.qubit", wires=4) + + @qml.qnode(dev, diff_method="parameter-shift") + def func(x): + for i in range(4): + qml.RX(x, wires=i) + return state() + + d_func = qml.jacobian(func) + + with pytest.raises( + ValueError, + match=( + "Computing the gradient of circuits that return the state with the " + "parameter-shift rule gradient transform is not supported" + ), + ): + d_func(pnp.array(0.1, requires_grad=True)) + + def test_no_state_capability(self, monkeypatch): + """Test if an error is raised for devices that are not capable of returning the state. + This is tested by changing the capability of default.qubit""" + dev = qml.device("default.qubit", wires=1) + capabilities = dev.capabilities().copy() + capabilities["returns_state"] = False + + @qml.qnode(dev) + def func(): + return state() + + with monkeypatch.context() as m: + m.setattr(DefaultQubit, "capabilities", lambda *args, **kwargs: capabilities) + with pytest.raises(qml.QuantumFunctionError, match="The current device is not capable"): + func() + + def test_state_not_supported(self): + """Test if an error is raised for devices inheriting from the base Device class, + which do not currently support returning the state""" + dev = qml.device("default.gaussian", wires=1) + + @qml.qnode(dev) + def func(): + return state() + + with pytest.raises(qml.QuantumFunctionError, match="Returning the state is not supported"): + func() + + @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) + def test_default_qubit(self, diff_method): + """Test that the returned state is equal to the expected returned state for all of + PennyLane's built in statevector devices""" + + dev = qml.device("default.qubit", wires=4) + + @qml.qnode(dev, diff_method=diff_method) + def func(): + for i in range(4): + qml.Hadamard(i) + return state() + + state_val = func() + state_expected = 0.25 * np.ones(16) + + assert np.allclose(state_val, state_expected) + assert np.allclose(state_val, dev.state) + + @pytest.mark.tf + @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) + def test_default_qubit_tf(self, diff_method): + """Test that the returned state is equal to the expected returned state for all of + PennyLane's built in statevector devices""" + + dev = qml.device("default.qubit.tf", wires=4) + + @qml.qnode(dev, diff_method=diff_method) + def func(): + for i in range(4): + qml.Hadamard(i) + return state() + + state_val = func() + state_expected = 0.25 * np.ones(16) + + assert np.allclose(state_val, state_expected) + assert np.allclose(state_val, dev.state) + + @pytest.mark.autograd + @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) + def test_default_qubit_autograd(self, diff_method): + """Test that the returned state is equal to the expected returned state for all of + PennyLane's built in statevector devices""" + + dev = qml.device("default.qubit.autograd", wires=4) + + @qml.qnode(dev, diff_method=diff_method) + def func(): + for i in range(4): + qml.Hadamard(i) + return state() + + state_val = func() + state_expected = 0.25 * np.ones(16) + + assert np.allclose(state_val, state_expected) + assert np.allclose(state_val, dev.state) + + @pytest.mark.tf + def test_gradient_with_passthru_tf(self): + """Test that the gradient of the state is accessible when using default.qubit.tf with the + backprop diff_method.""" + import tensorflow as tf + + dev = qml.device("default.qubit.tf", wires=1) + + @qml.qnode(dev, interface="tf", diff_method="backprop") + def func(x): + qml.RY(x, wires=0) + return state() + + x = tf.Variable(0.1, dtype=tf.float64) + + with tf.GradientTape() as tape: + result = func(x) + + grad = tape.jacobian(result, x) + expected = tf.stack([-0.5 * tf.sin(x / 2), 0.5 * tf.cos(x / 2)]) + assert np.allclose(grad, expected) + + @pytest.mark.autograd + def test_gradient_with_passthru_autograd(self): + """Test that the gradient of the state is accessible when using default.qubit.autograd + with the backprop diff_method.""" + + dev = qml.device("default.qubit.autograd", wires=1) + + @qml.qnode(dev, interface="autograd", diff_method="backprop") + def func(x): + qml.RY(x, wires=0) + return state() + + x = pnp.array(0.1, requires_grad=True) + + def loss_fn(x): + res = func(x) + return pnp.real(res) # This errors without the real. Likely an issue with complex + # numbers in autograd + + d_loss_fn = qml.jacobian(loss_fn) + + grad = d_loss_fn(x) + expected = np.array([-0.5 * np.sin(x / 2), 0.5 * np.cos(x / 2)]) + assert np.allclose(grad, expected) + + @pytest.mark.parametrize("wires", [[0, 2, 3, 1], ["a", -1, "b", 1000]]) + def test_custom_wire_labels(self, wires): + """Test the state when custom wire labels are used""" + dev = qml.device("default.qubit", wires=wires) + + @qml.qnode(dev, diff_method="parameter-shift") + def func(): + for i in range(4): + qml.Hadamard(wires[i]) + return state() + + state_expected = 0.25 * np.ones(16) + state_val = func() + + assert np.allclose(state_expected, state_val) + + @pytest.mark.parametrize("shots", [None, 1, 10]) + def test_shape(self, shots): + """Test that the shape is correct for qml.state.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + res = qml.state() + assert res.shape(dev, Shots(shots)) == (2**3,) + + @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) + def test_shape_shot_vector(self, s_vec): + """Test that the shape is correct for qml.state with the shot vector too.""" + dev = qml.device("default.qubit", wires=3, shots=s_vec) + res = qml.state() + assert res.shape(dev, Shots(s_vec)) == ((2**3,), (2**3,), (2**3,)) + + def test_numeric_type(self): + """Test that the numeric type of state measurements.""" + assert qml.state().numeric_type == complex + assert qml.density_matrix(wires=[0, 1]).numeric_type == complex + + +class TestDensityMatrix: + """Tests for the density matrix function""" + + # pylint: disable=too-many-public-methods + + @pytest.mark.parametrize("wires", range(2, 5)) + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + 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""" + + dev = qml.device(dev_name, wires=wires) + + @qml.qnode(dev) + def circuit(): + return density_matrix([0]) + + state_val = circuit() + + assert state_val.shape == (2, 2) + assert state_val.dtype == np.complex128 + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_return_type_is_state(self, dev_name): + """Test that the return type of the observable is State""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + return density_matrix(0) + + func() + obs = func.qtape.observables + assert len(obs) == 1 + assert obs[0].return_type is State + + @pytest.mark.torch + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("diff_method", [None, "backprop"]) + def test_correct_density_matrix_torch(self, dev_name, diff_method): + """Test that the correct density matrix is returned using torch interface.""" + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev, interface="torch", diff_method=diff_method) + def func(): + qml.Hadamard(wires=0) + return qml.density_matrix(wires=0) + + density_mat = 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_mat) + + dev = func.device + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), + ) + + @pytest.mark.jax + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("diff_method", [None, "backprop"]) + def test_correct_density_matrix_jax(self, dev_name, diff_method): + """Test that the correct density matrix is returned using JAX interface.""" + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev, interface="jax", diff_method=diff_method) + def func(): + qml.Hadamard(wires=0) + return qml.density_matrix(wires=0) + + density_mat = 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_mat) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), + ) + + @pytest.mark.tf + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("diff_method", [None, "backprop"]) + def test_correct_density_matrix_tf(self, dev_name, diff_method): + """Test that the correct density matrix is returned using the TensorFlow interface.""" + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev, interface="tf", diff_method=diff_method) + def func(): + qml.Hadamard(wires=0) + return qml.density_matrix(wires=0) + + density_mat = 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_mat) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_product_state_first(self, dev_name): + """Test that the correct density matrix is returned when + tracing out a product state""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=1) + qml.PauliY(wires=0) + return density_matrix(0) + + density_first = func() + expected = np.array([[0.0 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 1.0 + 0.0j]]) + + assert np.allclose(expected, density_first) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_product_state_second(self, dev_name): + """Test that the correct density matrix is returned when + tracing out a product state""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=1) + qml.PauliY(wires=0) + return density_matrix(1) + + density_second = 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) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=1).process_state(state=dev.state, wire_order=dev.wires), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("return_wire_order", ([0, 1], [1, 0])) + def test_correct_density_matrix_product_state_both(self, dev_name, return_wire_order): + """Test that the correct density matrix is returned + for a full product state on two wires.""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=1) + qml.PauliY(wires=0) + return density_matrix(return_wire_order) + + density_both = func() + single_statevectors = [[0, 1j], [1 / np.sqrt(2), 1 / np.sqrt(2)]] + expected_statevector = np.kron(*[single_statevectors[w] for w in return_wire_order]) + expected = np.outer(expected_statevector.conj(), expected_statevector) + + assert np.allclose(expected, density_both) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=return_wire_order).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_three_wires_first_two(self, dev_name): + """Test that the correct density matrix is returned for an example with three wires, + and tracing out the third wire.""" + + dev = qml.device(dev_name, wires=3) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=1) + qml.PauliY(wires=0) + return density_matrix([0, 1]) + + density_full = func() + expected = np.array( + [ + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j, 0.5 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j, 0.5 + 0.0j], + ] + ) + assert np.allclose(expected, density_full) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=[0, 1]).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_three_wires_last_two(self, dev_name): + """Test that the correct density matrix is returned for an example with three wires, + and tracing out the first wire.""" + + dev = qml.device(dev_name, wires=3) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + qml.Hadamard(1) + qml.CNOT(wires=[1, 2]) + return qml.density_matrix(wires=[1, 2]) + + density = func() + expected = np.array( + [ + [ + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + ] + ] + ) + + assert np.allclose(expected, density) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=[1, 2]).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize( + "return_wire_order", ([0], [1], [2], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2, 0], [2, 1, 0]) + ) + def test_correct_density_matrix_three_wires_product(self, dev_name, return_wire_order): + """Test that the correct density matrix is returned for an example with + three wires and a product state, tracing out various combinations.""" + + dev = qml.device(dev_name, wires=3) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + qml.PauliX(1) + qml.PauliZ(2) + return density_matrix(return_wire_order) + + density_full = func() + + single_states = [[1 / np.sqrt(2), 1 / np.sqrt(2)], [0, 1], [1, 0]] + if len(return_wire_order) == 1: + exp_statevector = np.array(single_states[return_wire_order[0]]) + elif len(return_wire_order) == 2: + i, j = return_wire_order + exp_statevector = np.kron(single_states[i], single_states[j]) + elif len(return_wire_order) == 3: + i, j, k = return_wire_order + exp_statevector = np.kron(np.kron(single_states[i], single_states[j]), single_states[k]) + + expected = np.outer(exp_statevector.conj(), exp_statevector) + assert np.allclose(expected, density_full) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=return_wire_order).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_mixed_state(self, dev_name): + """Test that the correct density matrix for an example with a mixed state""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + qml.CNOT(wires=[0, 1]) + return qml.density_matrix(wires=[1]) + + density = func() + + assert np.allclose(np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]), density) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_correct_density_matrix_all_wires(self, dev_name): + """Test that the correct density matrix is returned when all wires are given""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(0) + qml.CNOT(wires=[0, 1]) + return qml.density_matrix(wires=[0, 1]) + + density = func() + expected = np.array( + [ + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + ] + ) + + assert np.allclose(expected, density) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=[0, 1]).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_return_with_other_types(self, dev_name): + """Test that an exception is raised when a state is returned along with another return + type""" + + dev = qml.device(dev_name, wires=2) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires=0) + return density_matrix(0), expval(qml.PauliZ(1)) + + with pytest.raises( + qml.QuantumFunctionError, + match="The state or density matrix" + " cannot be returned in combination" + " with other return types", + ): + func() + + def test_no_state_capability(self, monkeypatch): + """Test if an error is raised for devices that are not capable of returning + the density matrix. This is tested by changing the capability of default.qubit""" + dev = qml.device("default.qubit", wires=2) + capabilities = dev.capabilities().copy() + capabilities["returns_state"] = False + + @qml.qnode(dev) + def func(): + return density_matrix(0) + + with monkeypatch.context() as m: + m.setattr(DefaultQubit, "capabilities", lambda *args, **kwargs: capabilities) + with pytest.raises( + qml.QuantumFunctionError, + match="The current device is not capable" " of returning the state", + ): + func() + + def test_density_matrix_not_supported(self): + """Test if an error is raised for devices inheriting from the base Device class, + which do not currently support returning the state""" + dev = qml.device("default.gaussian", wires=2) + + @qml.qnode(dev) + def func(): + return density_matrix(0) + + with pytest.raises(qml.QuantumFunctionError, match="Returning the state is not supported"): + func() + + @pytest.mark.parametrize("wires", [[0, 2], ["a", -1]]) + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_custom_wire_labels(self, wires, dev_name): + """Test that the correct density matrix for an example with a mixed + state when using custom wires""" + + dev = qml.device(dev_name, wires=wires) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires[0]) + qml.CNOT(wires=[wires[0], wires[1]]) + return qml.density_matrix(wires=wires[1]) + + density = func() + expected = np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]) + + assert np.allclose(expected, density) + + if dev_name != "default.mixed": + assert np.allclose( + expected, + qml.density_matrix(wires=wires[1]).process_state( + state=dev.state, wire_order=dev.wires + ), + ) + + @pytest.mark.parametrize("wires", [[3, 1], ["b", 1000]]) + @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + def test_custom_wire_labels_all_wires(self, wires, dev_name): + """Test that the correct density matrix for an example with a mixed + state when using custom wires""" + dev = qml.device(dev_name, wires=wires) + + @qml.qnode(dev) + def func(): + qml.Hadamard(wires[0]) + qml.CNOT(wires=[wires[0], wires[1]]) + return qml.density_matrix(wires=[wires[0], wires[1]]) + + density = func() + + assert np.allclose( + np.array( + [ + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], + [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], + ] + ), + density, + ) + + @pytest.mark.parametrize("shots", [None, 1, 10]) + def test_shape(self, shots): + """Test that the shape is correct for qml.density_matrix.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + res = qml.density_matrix(wires=[0, 1]) + assert res.shape(dev, Shots(shots)) == (2**2, 2**2) + + @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) + def test_shape_shot_vector(self, s_vec): + """Test that the shape is correct for qml.density_matrix with the shot vector too.""" + dev = qml.device("default.qubit", wires=3, shots=s_vec) + res = qml.density_matrix(wires=[0, 1]) + assert res.shape(dev, Shots(s_vec)) == ( + (2**2, 2**2), + (2**2, 2**2), + (2**2, 2**2), + ) diff --git a/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py new file mode 100644 index 00000000000..191e6937cfa --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py @@ -0,0 +1,184 @@ +# Copyright 2018-2020 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 var module""" +import numpy as np +import pytest + +import pennylane as qml +from pennylane.measurements import Variance, Shots + + +# TODO: Remove this when new CustomMP are the default +def custom_measurement_process(device, spy): + assert len(spy.call_args_list) > 0 # make sure method is mocked properly + + # pylint: disable=protected-access + samples = device._samples + state = device._state + call_args_list = list(spy.call_args_list) + for call_args in call_args_list: + obs = call_args.args[1] + shot_range, bin_size = ( + call_args.kwargs["shot_range"], + call_args.kwargs["bin_size"], + ) + meas = qml.var(op=obs) + old_res = device.var(obs, shot_range, bin_size) + if samples is not None: + new_res = meas.process_samples( + samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size + ) + else: + new_res = meas.process_state(state=state, wire_order=device.wires) + assert qml.math.allclose(old_res, new_res) + + +class TestVar: + """Tests for the var function""" + + @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) + @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) + def test_value(self, tol, r_dtype, mocker, shots): + """Test that the var function works""" + dev = qml.device("default.qubit", wires=2, shots=shots) + spy = mocker.spy(qml.QubitDevice, "var") + dev.R_DTYPE = r_dtype + + @qml.qnode(dev, diff_method="parameter-shift") + def circuit(x): + qml.RX(x, wires=0) + return qml.var(qml.PauliZ(0)) + + x = 0.54 + res = circuit(x) + expected = [np.sin(x) ** 2, np.sin(x) ** 2] if isinstance(shots, list) else np.sin(x) ** 2 + atol = tol if shots is None else 0.05 + rtol = 0 if shots is None else 0.05 + + assert np.allclose(res, expected, atol=atol, rtol=rtol) + # pylint: disable=no-member, unsubscriptable-object + if isinstance(res, tuple): + assert res[0].dtype == r_dtype + assert res[1].dtype == r_dtype + else: + assert res.dtype == r_dtype + + custom_measurement_process(dev, spy) + + def test_not_an_observable(self, mocker): + """Test that a UserWarning is raised if the provided + argument might not be hermitian.""" + dev = qml.device("default.qubit", wires=2) + spy = mocker.spy(qml.QubitDevice, "var") + + @qml.qnode(dev) + def circuit(): + qml.RX(0.52, wires=0) + return qml.var(qml.prod(qml.PauliX(0), qml.PauliZ(0))) + + with pytest.warns(UserWarning, match="Prod might not be hermitian."): + _ = circuit() + + custom_measurement_process(dev, spy) + + def test_observable_return_type_is_variance(self, mocker): + """Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`""" + dev = qml.device("default.qubit", wires=2) + spy = mocker.spy(qml.QubitDevice, "var") + + @qml.qnode(dev) + def circuit(): + res = qml.var(qml.PauliZ(0)) + assert res.return_type is Variance + return res + + circuit() + + custom_measurement_process(dev, spy) + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_numeric_type(self, obs): + """Test that the numeric type is correct.""" + res = qml.var(obs) + assert res.numeric_type is float + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_shape(self, obs): + """Test that the shape is correct.""" + dev = qml.device("default.qubit", wires=1) + res = qml.var(obs) + # pylint: disable=use-implicit-booleaness-not-comparison + assert res.shape(dev, Shots(None)) == () + assert res.shape(dev, Shots(100)) == () + + @pytest.mark.parametrize( + "obs", + [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], + ) + def test_shape_shot_vector(self, obs): + """Test that the shape is correct with the shot vector too.""" + res = qml.var(obs) + shot_vector = (1, 2, 3) + dev = qml.device("default.qubit", wires=3, shots=shot_vector) + assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) + + @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) + @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) + def test_projector_var(self, state, shots, mocker): + """Tests that the variance of a ``Projector`` object is computed correctly.""" + dev = qml.device("default.qubit", wires=3, shots=shots) + spy = mocker.spy(qml.QubitDevice, "var") + + @qml.qnode(dev) + def circuit(): + qml.Hadamard(0) + return qml.var(qml.Projector(state, wires=range(3))) + + res = circuit() + expected = [0.25, 0.25] if isinstance(shots, list) else 0.25 + + assert np.allclose(res, expected, atol=0.02, rtol=0.02) + + custom_measurement_process(dev, spy) + + def test_permuted_wires(self, mocker): + """Test that the variance of an operator with permuted wires is the same.""" + obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) + obs_2 = qml.prod( + qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) + ) + + dev = qml.device("default.qubit", wires=["h", 8, 10]) + spy = mocker.spy(qml.QubitDevice, "var") + + @qml.qnode(dev) + def circuit(): + qml.RX(1.23, wires=["h"]) + qml.RY(2.34, wires=[8]) + return qml.var(obs) + + @qml.qnode(dev) + def circuit2(): + qml.RX(1.23, wires=["h"]) + qml.RY(2.34, wires=[8]) + return qml.var(obs_2) + + assert circuit() == circuit2() + custom_measurement_process(dev, spy) diff --git a/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py new file mode 100644 index 00000000000..d9551f3b34a --- /dev/null +++ b/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py @@ -0,0 +1,419 @@ +# Copyright 2018-2020 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 vn_entropy module""" +import copy + +import numpy as np +import pytest + +import pennylane as qml +from pennylane.interfaces import INTERFACE_MAP +from pennylane.measurements import VnEntropy, Shots +from pennylane.measurements.vn_entropy import VnEntropyMP +from pennylane.wires import Wires + +# pylint: disable=too-many-arguments, no-member + + +def expected_entropy_ising_xx(param): + """ + Return the analytical entropy for the IsingXX. + """ + eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eigs = [eig_1, eig_2] + eigs = [eig for eig in eigs if eig > 0] + + expected_entropy = eigs * np.log(eigs) + + expected_entropy = -np.sum(expected_entropy) + return expected_entropy + + +def expected_entropy_grad_ising_xx(param): + """ + Return the analytical gradient entropy for the IsingXX. + """ + eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 + eigs = [eig_1, eig_2] + eigs = np.maximum(eigs, 1e-08) + + return -( + (np.log(eigs[0]) + 1) + * (np.sin(param / 2) ** 3 * np.cos(param / 2) - np.sin(param / 2) * np.cos(param / 2) ** 3) + / np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2) + ) - ( + (np.log(eigs[1]) + 1) + * ( + np.sin(param / 2) + * np.cos(param / 2) + * (np.cos(param / 2) ** 2 - np.sin(param / 2) ** 2) + ) + / np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2) + ) + + +class TestInitialization: + """Unit tests for the ``qml.vn_entropy`` function.""" + + @pytest.mark.all_interfaces + @pytest.mark.parametrize( + "state_vector,expected", + [([1.0, 0.0, 0.0, 1.0] / qml.math.sqrt(2), qml.math.log(2)), ([1.0, 0.0, 0.0, 0.0], 0)], + ) + @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) + def test_vn_entropy(self, interface, state_vector, expected): + """Tests the output of qml.vn_entropy""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface) + def circuit(): + qml.StatePrep(state_vector, wires=[0, 1]) + return qml.vn_entropy(wires=0) + + res = circuit() + new_res = qml.vn_entropy(wires=0).process_state( + state=circuit.device.state, wire_order=circuit.device.wires + ) + assert qml.math.allclose(res, expected) + assert qml.math.allclose(new_res, expected) + assert INTERFACE_MAP.get(qml.math.get_interface(new_res)) == interface + assert res.dtype == new_res.dtype + + def test_queue(self): + """Test that the right measurement class is queued.""" + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev) + def circuit(): + return qml.vn_entropy(wires=0, log_base=2) + + circuit() + + assert isinstance(circuit.tape[0], VnEntropyMP) + + def test_copy(self): + """Test that the ``__copy__`` method also copies the ``log_base`` information.""" + meas = qml.vn_entropy(wires=0, log_base=2) + meas_copy = copy.copy(meas) + assert meas_copy.log_base == 2 + assert meas_copy.wires == Wires(0) + + def test_properties(self): + """Test that the properties are correct.""" + meas = qml.vn_entropy(wires=0) + assert meas.numeric_type == float + assert meas.return_type == VnEntropy + + @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ((1, 10), ((), ()))]) + def test_shape(self, shots, shape): + """Test the ``shape`` method.""" + meas = qml.vn_entropy(wires=0) + dev = qml.device("default.qubit", wires=1, shots=shots) + + assert meas.shape(dev, Shots(shots)) == shape + + +class TestIntegration: + """Integration tests for the vn_entropy measurement function.""" + + parameters = np.linspace(0, 2 * np.pi, 10) + + devices = ["default.qubit", "default.mixed", "lightning.qubit"] + + single_wires_list = [ + [0], + [1], + ] + + base = [2, np.exp(1), 10] + + check_state = [True, False] + + devices = ["default.qubit", "default.mixed"] + diff_methods = ["backprop", "finite-diff"] + + def test_shot_vec_error(self): + """Test an error is raised when using shot vectors with vn_entropy.""" + dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + + @qml.qnode(device=dev) + def circuit(x): + qml.Hadamard(wires=[0]) + qml.CRX(x, wires=[0, 1]) + return qml.vn_entropy(wires=[0]) + + with pytest.raises( + NotImplementedError, match="Von Neumann entropy is not supported with shot vectors" + ): + circuit(0.5) + + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("base", base) + def test_IsingXX_qnode_entropy(self, param, wires, device, base): + """Test entropy for a QNode numpy.""" + + dev = qml.device(device, wires=2) + + @qml.qnode(dev) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + entropy = circuit_entropy(param) + + expected_entropy = expected_entropy_ising_xx(param) / np.log(base) + assert qml.math.allclose(entropy, expected_entropy) + + @pytest.mark.autograd + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("diff_method", diff_methods) + def test_IsingXX_qnode_entropy_grad(self, param, wires, base, diff_method): + """Test entropy for a QNode gradient with autograd.""" + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, diff_method=diff_method) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + grad_entropy = qml.grad(circuit_entropy)(param) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) + assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) + + @pytest.mark.torch + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("interface", ["torch"]) + def test_IsingXX_qnode_torch_entropy(self, param, wires, device, base, interface): + """Test entropy for a QNode with torch interface.""" + import torch + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + entropy = circuit_entropy(torch.tensor(param)) + + expected_entropy = expected_entropy_ising_xx(param) / np.log(base) + + assert qml.math.allclose(entropy, expected_entropy) + + @pytest.mark.torch + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("diff_method", diff_methods) + def test_IsingXX_qnode_entropy_grad_torch(self, param, wires, base, diff_method): + """Test entropy for a QNode gradient with torch.""" + import torch + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface="torch", diff_method=diff_method) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) + + param = torch.tensor(param, dtype=torch.float64, requires_grad=True) + entropy = circuit_entropy(param) + entropy.backward() + grad_entropy = param.grad + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) + + @pytest.mark.tf + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("interface", ["tf"]) + def test_IsingXX_qnode_tf_entropy(self, param, wires, device, base, interface): + """Test entropy for a QNode with tf interface.""" + import tensorflow as tf + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + entropy = circuit_entropy(tf.Variable(param)) + + expected_entropy = expected_entropy_ising_xx(param) / np.log(base) + + assert qml.math.allclose(entropy, expected_entropy) + + @pytest.mark.tf + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["tf"]) + def test_IsingXX_qnode_entropy_grad_tf(self, param, wires, base, diff_method, interface): + """Test entropy for a QNode gradient with tf.""" + import tensorflow as tf + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + param = tf.Variable(param) + with tf.GradientTape() as tape: + entropy = circuit_entropy(param) + + grad_entropy = tape.gradient(entropy, param) + + grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) + + @pytest.mark.jax + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("interface", ["jax"]) + def test_IsingXX_qnode_jax_entropy(self, param, wires, device, base, interface): + """Test entropy for a QNode with jax interface.""" + import jax.numpy as jnp + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + entropy = circuit_entropy(jnp.array(param)) + + expected_entropy = expected_entropy_ising_xx(param) / np.log(base) + + assert qml.math.allclose(entropy, expected_entropy) + + @pytest.mark.jax + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax"]) + def test_IsingXX_qnode_entropy_grad_jax(self, param, wires, base, diff_method, interface): + """Test entropy for a QNode gradient with Jax.""" + import jax + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + grad_entropy = jax.grad(circuit_entropy)(jax.numpy.array(param)) + grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) + + # higher tolerance for finite-diff method + tol = 1e-8 if diff_method == "backprop" else 1e-5 + + assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=tol) + + @pytest.mark.jax + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("device", devices) + @pytest.mark.parametrize("interface", ["jax"]) + def test_IsingXX_qnode_jax_jit_entropy(self, param, wires, base, device, interface): + """Test entropy for a QNode with jax-jit interface.""" + import jax + import jax.numpy as jnp + + dev = qml.device(device, wires=2) + + @qml.qnode(dev, interface=interface) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + entropy = jax.jit(circuit_entropy)(jnp.array(param)) + + expected_entropy = expected_entropy_ising_xx(param) / np.log(base) + + assert qml.math.allclose(entropy, expected_entropy) + + @pytest.mark.jax + @pytest.mark.parametrize("wires", single_wires_list) + @pytest.mark.parametrize("param", parameters) + @pytest.mark.parametrize("base", base) + @pytest.mark.parametrize("diff_method", diff_methods) + @pytest.mark.parametrize("interface", ["jax-jit"]) + def test_IsingXX_qnode_entropy_grad_jax_jit(self, param, wires, base, diff_method, interface): + """Test entropy for a QNode gradient with Jax-jit.""" + import jax + + dev = qml.device("default.qubit", wires=2) + + @qml.qnode(dev, interface=interface, diff_method=diff_method) + def circuit_entropy(x): + qml.IsingXX(x, wires=[0, 1]) + return qml.vn_entropy(wires=wires, log_base=base) + + grad_entropy = jax.jit(jax.grad(circuit_entropy))(jax.numpy.array(param)) + + grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) + + assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=1e-05) + + @pytest.mark.parametrize("device", devices) + def test_qnode_entropy_no_custom_wires(self, device): + """Test that entropy cannot be returned with custom wires.""" + + dev = qml.device(device, wires=["a", 1]) + + @qml.qnode(dev) + def circuit_entropy(x): + qml.IsingXX(x, wires=["a", 1]) + return qml.vn_entropy(wires=["a"]) + + with pytest.raises( + qml.QuantumFunctionError, + match="Returning the Von Neumann entropy is not supported when using custom wire labels", + ): + circuit_entropy(0.1) diff --git a/tests/measurements/test_classical_shadow.py b/tests/measurements/test_classical_shadow.py index 8b523526b40..06f0b3a7ca2 100644 --- a/tests/measurements/test_classical_shadow.py +++ b/tests/measurements/test_classical_shadow.py @@ -26,7 +26,7 @@ # pylint: disable=dangerous-default-value, too-many-arguments, comparison-with-callable, no-member -def get_circuit(wires, shots, seed_recipes, interface="autograd", device="default.qubit"): +def get_circuit(wires, shots, seed_recipes, interface="autograd", device="default.qubit.legacy"): """ Return a QNode that prepares the state (|00...0> + |11...1>) / sqrt(2) and performs the classical shadow measurement @@ -34,7 +34,7 @@ def get_circuit(wires, shots, seed_recipes, interface="autograd", device="defaul if device is not None: dev = qml.device(device, wires=wires, shots=shots) else: - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) dev.classical_shadow = super(type(dev), dev).classical_shadow @@ -51,14 +51,14 @@ def circuit(): return circuit -def get_x_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_x_basis_circuit(wires, shots, interface="autograd", device="default.qubit.legacy"): """ Return a QNode that prepares the |++..+> state and performs a classical shadow measurement """ if device is not None: dev = qml.device(device, wires=wires, shots=shots) else: - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) dev.classical_shadow = super(type(dev), dev).classical_shadow @@ -72,14 +72,14 @@ def circuit(): return circuit -def get_y_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_y_basis_circuit(wires, shots, interface="autograd", device="default.qubit.legacy"): """ Return a QNode that prepares the |+i>|+i>...|+i> state and performs a classical shadow measurement """ if device is not None: dev = qml.device(device, wires=wires, shots=shots) else: - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) dev.classical_shadow = super(type(dev), dev).classical_shadow @@ -94,14 +94,14 @@ def circuit(): return circuit -def get_z_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_z_basis_circuit(wires, shots, interface="autograd", device="default.qubit.legacy"): """ Return a QNode that prepares the |00..0> state and performs a classical shadow measurement """ if device is not None: dev = qml.device(device, wires=wires, shots=shots) else: - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) dev.classical_shadow = super(type(dev), dev).classical_shadow @@ -263,7 +263,7 @@ def test_measurement_process_numeric_type(self, wires, seed): @pytest.mark.parametrize("seed", seed_recipes_list) def test_measurement_process_shape(self, wires, shots, seed): """Test that the shape of the MeasurementProcess instance is correct""" - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) shots_obj = Shots(shots) res = qml.classical_shadow(wires=range(wires), seed=seed) assert res.shape(dev, shots_obj) == (2, shots, wires) @@ -304,7 +304,7 @@ def test_measurement_process_copy(self, wires, seed): @pytest.mark.parametrize("shots", shots_list) @pytest.mark.parametrize("seed", seed_recipes_list) @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", None]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", None]) def test_format(self, wires, shots, seed, interface, device): """Test that the format of the returned classical shadow measurement is correct""" @@ -334,7 +334,7 @@ def test_format(self, wires, shots, seed, interface, device): @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize("device", ["default.qubit", None]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", None]) @pytest.mark.parametrize( "circuit_fn, basis_recipe", [(get_x_basis_circuit, 0), (get_y_basis_circuit, 1), (get_z_basis_circuit, 2)], @@ -390,7 +390,7 @@ def test_shots_none_error(self, wires, seed): def test_multi_measurement_error(self, wires, shots): """Test that an error is raised when classical shadows is returned with other measurement processes""" - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) @qml.qnode(dev) def circuit(): @@ -407,7 +407,7 @@ def circuit(): def hadamard_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(obs, k=1): @@ -419,7 +419,7 @@ def circuit(obs, k=1): def max_entangled_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(obs, k=1): @@ -432,7 +432,7 @@ def circuit(obs, k=1): def qft_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) one_state = np.zeros(wires) one_state[-1] = 1 @@ -458,7 +458,7 @@ def test_measurement_process_numeric_type(self): @pytest.mark.parametrize("shots", [1, 10]) def test_measurement_process_shape(self, wires, shots): """Test that the shape of the MeasurementProcess instance is correct""" - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) H = qml.PauliZ(0) res = qml.shadow_expval(H) assert len(res.shape(dev, Shots(shots))) == 0 @@ -504,7 +504,7 @@ def test_shots_none_error(self): def test_multi_measurement_error(self): """Test that an error is raised when classical shadows is returned with other measurement processes""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) @qml.qnode(dev) def circuit(): @@ -647,7 +647,7 @@ def test_qft_expval(self, interface, k=1, obs=obs_qft, expected=expected_qft): def strongly_entangling_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(x, obs, k): @@ -658,7 +658,7 @@ def circuit(x, obs, k): def strongly_entangling_circuit_exact(wires, interface="autograd"): - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev, interface=interface) def circuit(x, obs): diff --git a/tests/measurements/test_counts.py b/tests/measurements/test_counts.py index eeee4a24e5f..3485d6c8cf7 100644 --- a/tests/measurements/test_counts.py +++ b/tests/measurements/test_counts.py @@ -215,7 +215,7 @@ def test_counts_dimension(self, mocker): """Test that the counts function outputs counts of the right size""" n_sample = 10 - dev = qml.device("default.qubit", wires=2, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -234,7 +234,7 @@ def test_batched_counts_dimension(self, mocker): """Test that the counts function outputs counts of the right size with batching""" n_sample = 10 - dev = qml.device("default.qubit", wires=2, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -254,7 +254,7 @@ def test_counts_combination(self, mocker): """Test the output of combining expval, var and counts""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") @@ -278,7 +278,7 @@ def test_single_wire_counts(self, mocker): """Test the return type and shape of sampling counts from a single wire""" n_sample = 10 - dev = qml.device("default.qubit", wires=1, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -299,7 +299,7 @@ def test_multi_wire_counts_regular_shape(self, mocker): where a rectangular array is expected""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -323,7 +323,7 @@ def circuit(): def test_observable_return_type_is_counts(self): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Counts`""" n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_shots) @qml.qnode(dev) def circuit(): @@ -335,7 +335,7 @@ def circuit(): def test_providing_no_observable_and_no_wires_counts(self, mocker): """Test that we can provide no observable and no wires to sample function""" - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -354,7 +354,7 @@ def test_providing_no_observable_and_wires_counts(self, mocker): """Test that we can provide no observable but specify wires to the sample function""" wires = [0, 2] wires_obj = qml.wires.Wires(wires) - dev = qml.device("default.qubit", wires=3, shots=1000) + dev = qml.device("default.qubit.legacy", wires=3, shots=1000) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -373,7 +373,7 @@ def circuit(): def test_batched_counts_work_individually(self, mocker): """Test that each counts call operates independently""" n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -391,7 +391,7 @@ def test_counts_no_op_finite_shots(self, interface, wires, basis_state, mocker): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -411,7 +411,7 @@ def test_counts_operator_finite_shots(self, interface, mocker): """Check all interfaces with observable measurement counts and finite shot""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -432,7 +432,7 @@ def test_counts_binned( ): # pylint:disable=too-many-arguments """Check all interfaces with computational basis state counts and different shot vectors""" - dev = qml.device("default.qubit", wires=3, shots=shot_vec) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vec) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -457,7 +457,7 @@ def circuit(): def test_counts_operator_binned(self, shot_vec, interface, mocker): """Check all interfaces with observable measurement counts and different shot vectors""" - dev = qml.device("default.qubit", wires=3, shots=shot_vec) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vec) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -479,7 +479,7 @@ def circuit(): def test_counts_binned_4_wires(self, shot_vec, mocker): """Check the autograd interface with computational basis state counts and different shot vectors on a device with 4 wires""" - dev = qml.device("default.qubit", wires=4, shots=shot_vec) + dev = qml.device("default.qubit.legacy", wires=4, shots=shot_vec) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface="autograd") @@ -505,7 +505,7 @@ def circuit(): def test_counts_operator_binned_4_wires(self, shot_vec, mocker): """Check the autograd interface with observable samples to obtain counts from and different shot vectors on a device with 4 wires""" - dev = qml.device("default.qubit", wires=4, shots=shot_vec) + dev = qml.device("default.qubit.legacy", wires=4, shots=shot_vec) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface="autograd") @@ -541,7 +541,7 @@ def circuit(): def test_counts_observable_finite_shots(self, interface, meas2, shots, mocker): """Check all interfaces with observable measurement counts and finite shot""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) spy = mocker.spy(qml.QubitDevice, "sample") if isinstance(shots, tuple) and interface == "torch": @@ -576,7 +576,7 @@ def test_all_outcomes_kwarg_providing_observable(self, mocker): including 0 count values, if observable is given and all_outcomes=True""" n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -596,7 +596,7 @@ def test_all_outcomes_kwarg_no_observable_no_wires(self, mocker): count and no observable are given and all_outcomes=True""" n_shots = 10 - dev = qml.device("default.qubit", wires=2, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -615,7 +615,7 @@ def test_all_outcomes_kwarg_providing_wires_and_no_observable(self, mocker): if wire count is given and all_outcomes=True""" n_shots = 10 - dev = qml.device("default.qubit", wires=4, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=4, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -633,7 +633,7 @@ def test_all_outcomes_hermitian(self, mocker): qml.Hermitian observable""" n_shots = 10 - dev = qml.device("default.qubit", wires=2, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") A = np.array([[1, 0], [0, -1]]) @@ -652,7 +652,7 @@ def test_all_outcomes_multiple_measurements(self, mocker): """Tests that the all_outcomes=True option for counts works when multiple measurements are performed""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -669,7 +669,7 @@ def circuit(): def test_batched_all_outcomes(self, mocker): """Tests that all_outcomes=True works with broadcasting.""" n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -689,7 +689,7 @@ def test_counts_empty_wires(self): @pytest.mark.parametrize("shots", [1, 100]) def test_counts_no_arguments(self, shots): """Test that using ``qml.counts`` with no arguments returns the counts of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) @qml.qnode(dev) def circuit(): @@ -706,7 +706,7 @@ def circuit(): def test_counts_no_op_finite_shots(interface, wires, basis_state, mocker): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -728,7 +728,7 @@ def test_batched_counts_no_op_finite_shots(interface, wires, basis_states, mocke """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -748,7 +748,7 @@ def test_batched_counts_and_expval_no_op_finite_shots(interface, wires, basis_st """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -769,7 +769,7 @@ def circuit(): def test_batched_counts_operator_finite_shots(interface, mocker): """Check all interfaces with observable measurement counts, batching and finite shots""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) @@ -787,7 +787,7 @@ def circuit(): def test_batched_counts_and_expval_operator_finite_shots(interface, mocker): """Check all interfaces with observable measurement counts, batching and finite shots""" n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) diff --git a/tests/measurements/test_expval.py b/tests/measurements/test_expval.py index 3d0e5c009b2..26ad746a287 100644 --- a/tests/measurements/test_expval.py +++ b/tests/measurements/test_expval.py @@ -53,7 +53,7 @@ class TestExpval: @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) def test_value(self, tol, r_dtype, mocker, shots): """Test that the expval interface works""" - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="parameter-shift") @@ -84,7 +84,7 @@ def circuit(x): def test_not_an_observable(self, mocker): """Test that a warning is raised if the provided argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -101,7 +101,7 @@ def circuit(): def test_observable_return_type_is_expectation(self, mocker): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -131,7 +131,7 @@ def test_numeric_type(self, obs): ) def test_shape(self, obs): """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) res = qml.expval(obs) # pylint: disable=use-implicit-booleaness-not-comparison @@ -146,7 +146,7 @@ def test_shape_shot_vector(self, obs): """Test that the shape is correct with the shot vector too.""" res = qml.expval(obs) shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vector) assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) @@ -154,7 +154,7 @@ def test_shape_shot_vector(self, obs): def test_projector_expval(self, state, shots, mocker): """Tests that the expectation of a ``Projector`` object is computed correctly for both of its subclasses.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) np.random.seed(42) @qml.qnode(dev) @@ -178,7 +178,7 @@ def test_permuted_wires(self, mocker): qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) ) - dev = qml.device("default.qubit", wires=["h", 8, 10]) + dev = qml.device("default.qubit.legacy", wires=["h", 8, 10]) spy = mocker.spy(qml.QubitDevice, "expval") @qml.qnode(dev) diff --git a/tests/measurements/test_measurements.py b/tests/measurements/test_measurements.py index 3b8160419a5..6f9455bebdf 100644 --- a/tests/measurements/test_measurements.py +++ b/tests/measurements/test_measurements.py @@ -78,7 +78,7 @@ def test_ObservableReturnTypes(return_type, value): def test_no_measure(): """Test that failing to specify a measurement raises an exception""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x): @@ -104,7 +104,7 @@ def test_numeric_type_unrecognized_error(): def test_shape_unrecognized_error(): """Test that querying the shape of a measurement process with an unrecognized return type raises an error.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) mp = NotValidMeasurement() with pytest.raises( qml.QuantumFunctionError, @@ -245,7 +245,7 @@ def test_not_an_observable(self, stat_func, return_type): # pylint: disable=unu if stat_func is sample: pytest.skip("Sampling is not yet supported with symbolic operators.") - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -484,7 +484,7 @@ class MyMeasurement(SampleMeasurement): def process_samples(self, samples, wire_order, shot_range, bin_size): return qml.math.sum(samples[..., self.wires]) - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev) def circuit(): @@ -501,7 +501,7 @@ class MyMeasurement(SampleMeasurement): def process_samples(self, samples, wire_order, shot_range, bin_size): return qml.math.sum(samples[..., self.wires]) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -516,7 +516,7 @@ def circuit(): def test_method_overriden_by_device(self): """Test that the device can override a measurement process.""" - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev) def circuit(): @@ -539,7 +539,7 @@ class MyMeasurement(StateMeasurement): def process_state(self, state, wire_order): return qml.math.sum(state) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -554,7 +554,7 @@ class MyMeasurement(StateMeasurement): def process_state(self, state, wire_order): return qml.math.sum(state) - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev) def circuit(): @@ -569,7 +569,7 @@ def circuit(): def test_method_overriden_by_device(self): """Test that the device can override a measurement process.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface="autograd") def circuit(): @@ -591,7 +591,7 @@ class MyMeasurement(MeasurementTransform): def process(self, tape, device): return {device.shots: len(tape)} - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev) def circuit(): @@ -602,7 +602,7 @@ def circuit(): def test_method_overriden_by_device(self): """Test that the device can override a measurement process.""" - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) @qml.qnode(dev) def circuit(): diff --git a/tests/measurements/test_mutual_info.py b/tests/measurements/test_mutual_info.py index 79eedc1d44e..d75ce6de280 100644 --- a/tests/measurements/test_mutual_info.py +++ b/tests/measurements/test_mutual_info.py @@ -39,7 +39,7 @@ def test_queue(self): @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ([1, 10], ((), ()))]) def test_shape(self, shots, shape): """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) res = qml.mutual_info(wires0=[0], wires1=[1]) assert res.shape(dev, Shots(shots)) == shape @@ -88,7 +88,7 @@ class TestIntegration: ) def test_mutual_info_output(self, interface, state, expected): """Test the output of qml.mutual_info""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, interface=interface) def circuit(): @@ -106,7 +106,7 @@ def circuit(): def test_shot_vec_error(self): """Test an error is raised when using shot vectors with mutual_info.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -122,7 +122,7 @@ def circuit(x): diff_methods = ["backprop", "finite-diff"] @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", "lightning.qubit"]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize("params", np.linspace(0, 2 * np.pi, 8)) def test_qnode_state(self, device, interface, params): @@ -148,7 +148,7 @@ def circuit(params): assert np.allclose(actual, expected) @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", "lightning.qubit"]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize("params", zip(np.linspace(0, np.pi, 8), np.linspace(0, 2 * np.pi, 8))) def test_qnode_mutual_info(self, device, interface, params): @@ -179,7 +179,7 @@ def circuit_state(params): assert np.allclose(actual, expected) - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", "lightning.qubit"]) def test_mutual_info_wire_labels(self, device): """Test that mutual_info is correct with custom wire labels""" param = np.array([0.678, 1.234]) @@ -209,7 +209,7 @@ def test_qnode_state_jax_jit(self, params): import jax import jax.numpy as jnp - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jnp.array(params) @@ -237,7 +237,7 @@ def test_qnode_mutual_info_jax_jit(self, params, interface): import jax import jax.numpy as jnp - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) params = jnp.array(params) @@ -269,7 +269,7 @@ def circuit_state(params): def test_qnode_grad(self, param, diff_method, interface): """Test that the gradient of mutual information works for QNodes with the autograd interface""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method=diff_method) def circuit(param): @@ -301,7 +301,7 @@ def test_qnode_grad_jax(self, param, diff_method, interface): import jax import jax.numpy as jnp - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) param = jnp.array(param) @@ -335,7 +335,7 @@ def test_qnode_grad_jax_jit(self, param, diff_method, interface): import jax import jax.numpy as jnp - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) param = jnp.array(param) @@ -368,7 +368,7 @@ def test_qnode_grad_tf(self, param, diff_method, interface): with the tensorflow interface""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) param = tf.Variable(param) @@ -404,7 +404,7 @@ def test_qnode_grad_torch(self, param, diff_method, interface): with the torch interface""" import torch - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method=diff_method) def circuit(param): @@ -431,7 +431,7 @@ def circuit(param): assert np.allclose(actual, expected, atol=tol) @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", "lightning.qubit"]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize( "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] @@ -455,7 +455,7 @@ def circuit(params): circuit(params) @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) + @pytest.mark.parametrize("device", ["default.qubit.legacy", "default.mixed", "lightning.qubit"]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize( "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] diff --git a/tests/measurements/test_probs.py b/tests/measurements/test_probs.py index a07fd3da1b9..de8b3d9bf62 100644 --- a/tests/measurements/test_probs.py +++ b/tests/measurements/test_probs.py @@ -78,7 +78,7 @@ class TestProbs: def test_queue(self): """Test that the right measurement class is queued.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -97,7 +97,7 @@ def test_numeric_type(self): @pytest.mark.parametrize("shots", [None, 10]) def test_shape(self, wires, shots): """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) res = qml.probs(wires=wires) assert res.shape(dev, Shots(shots)) == (2 ** len(wires),) @@ -106,7 +106,7 @@ def test_shape_shot_vector(self, wires): """Test that the shape is correct with the shot vector too.""" res = qml.probs(wires=wires) shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vector) assert res.shape(dev, Shots(shot_vector)) == ( (2 ** len(wires),), (2 ** len(wires),), @@ -133,7 +133,7 @@ def test_probs_empty_wires(self): @pytest.mark.parametrize("shots", [None, 100]) def test_probs_no_arguments(self, shots): """Test that using ``qml.probs`` with no arguments returns the probabilities of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) @qml.qnode(dev) def circuit(): @@ -145,7 +145,7 @@ def circuit(): def test_full_prob(self, init_state, tol, mocker): """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -163,7 +163,7 @@ def circuit(): def test_marginal_prob(self, init_state, tol, mocker): """Test that the correct marginal probability is returned.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -183,7 +183,7 @@ def circuit(): def test_marginal_prob_more_wires(self, init_state, mocker, tol): """Test that the correct marginal probability is returned, when the states_to_binary method is used for probability computations.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy_probs = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -244,7 +244,7 @@ def test_process_state_batched(self, interface, subset_wires, expected): def test_integration(self, tol, mocker): """Test the probability is correct for a known state preparation.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -266,7 +266,7 @@ def circuit(): def test_integration_analytic_false(self, tol, mocker, shots): """Test the probability is correct for a known state preparation when the analytic attribute is set to False.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -283,7 +283,7 @@ def circuit(): @pytest.mark.parametrize("shots", [None, 100]) def test_batch_size(self, mocker, shots): """Test the probability is correct for a batched input.""" - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -303,7 +303,7 @@ def test_numerical_analytic_diff_agree(self, tol, mocker): """Test that the finite difference and parameter shift rule provide the same Jacobian.""" w = 4 - dev = qml.device("default.qubit", wires=w) + dev = qml.device("default.qubit.legacy", wires=w) spy = mocker.spy(qml.QubitDevice, "probability") def circuit(x, y, z): @@ -339,7 +339,7 @@ def circuit(x, y, z): @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) def test_prob_generalize_param_one_qubit(self, hermitian, tol, mocker): """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -366,7 +366,7 @@ def circuit_rotated(x): @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) def test_prob_generalize_param(self, hermitian, tol, mocker): """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -398,7 +398,7 @@ def circuit_rotated(x, y): @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) def test_prob_generalize_param_multiple(self, hermitian, tol, mocker): """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) @@ -443,7 +443,7 @@ def circuit_rotated(x, y): def test_prob_generalize_initial_state(self, hermitian, wire, init_state, tol, mocker): """Test that the correct probability is returned.""" # pylint:disable=too-many-arguments - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -487,7 +487,7 @@ def circuit_rotated(): def test_operation_prob(self, operation, wire, init_state, tol, mocker): "Test the rotated probability with different wires and rotating operations." # pylint:disable=too-many-arguments - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -529,7 +529,7 @@ def circuit_rotated(): @pytest.mark.parametrize("observable", [(qml.PauliX, qml.PauliY)]) def test_observable_tensor_prob(self, observable, init_state, tol, mocker): "Test the rotated probability with a tensor observable." - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -567,7 +567,7 @@ def test_hamiltonian_error(self, coeffs, obs, init_state): "Test that an error is returned for hamiltonians." H = qml.Hamiltonian(coeffs, obs) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) state = init_state(4) @qml.qnode(dev) @@ -592,7 +592,7 @@ def test_generalize_prob_not_hermitian(self, operation): """Test that Operators that do not have a diagonalizing_gates representation cannot be used in probability measurements.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -610,7 +610,7 @@ def circuit(): def test_prob_wires_and_hermitian(self, hermitian): """Test that we can cannot give simultaneously wires and a hermitian.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -662,7 +662,7 @@ def test_estimate_probability_with_binsize_with_broadcasting(self, wires, expect assert np.allclose(res, expected) def test_non_commuting_probs_raises_error(self): - dev = qml.device("default.qubit", wires=5) + dev = qml.device("default.qubit.legacy", wires=5) @qml.qnode(dev) def circuit(x, y): @@ -678,7 +678,7 @@ def circuit(x, y): def test_commuting_probs_in_computational_basis(self): """Test that `qml.probs` can be used in the computational basis with other commuting observables.""" - dev = qml.device("default.qubit", wires=5) + dev = qml.device("default.qubit.legacy", wires=5) @qml.qnode(dev) def circuit(x, y): diff --git a/tests/measurements/test_purity_measurement.py b/tests/measurements/test_purity_measurement.py index ccaab4fb5bc..969f9a16c14 100644 --- a/tests/measurements/test_purity_measurement.py +++ b/tests/measurements/test_purity_measurement.py @@ -71,15 +71,15 @@ def test_numeric_type(self): def test_shape_new(self, shots, shape): """Test the ``shape_new`` method.""" meas = qml.purity(wires=0) - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) assert meas.shape(dev, Shots(shots)) == shape class TestPurityIntegration: """Test the purity meausrement with qnodes and devices.""" - devices = ["default.qubit", "lightning.qubit", "default.mixed"] - grad_supported_devices = ["default.qubit", "default.mixed"] + devices = ["default.qubit.legacy", "lightning.qubit", "default.mixed"] + grad_supported_devices = ["default.qubit.legacy", "default.mixed"] mix_supported_devices = ["default.mixed"] diff_methods = ["backprop", "finite-diff"] diff --git a/tests/measurements/test_sample.py b/tests/measurements/test_sample.py index 18b9d3f5ad3..5f38ef29ec8 100644 --- a/tests/measurements/test_sample.py +++ b/tests/measurements/test_sample.py @@ -51,7 +51,7 @@ class TestSample: def test_sample_dimension(self, mocker, n_sample): """Test that the sample function outputs samples of the right size""" - dev = qml.device("default.qubit", wires=2, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=2, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -76,7 +76,7 @@ def test_sample_combination(self, mocker): """Test the output of combining expval, var and sample""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") @@ -99,7 +99,7 @@ def test_single_wire_sample(self, mocker): """Test the return type and shape of sampling a single wire""" n_sample = 10 - dev = qml.device("default.qubit", wires=1, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -120,7 +120,7 @@ def test_multi_wire_sample_regular_shape(self, mocker): where a rectangular array is expected""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -146,7 +146,7 @@ def test_sample_output_type_in_combination(self, mocker): in combination with expvals and vars""" n_sample = 10 - dev = qml.device("default.qubit", wires=3, shots=n_sample) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_sample) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") @@ -167,7 +167,7 @@ def circuit(): def test_not_an_observable(self, mocker): """Test that a UserWarning is raised if the provided argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2, shots=10) + dev = qml.device("default.qubit.legacy", wires=2, shots=10) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -183,7 +183,7 @@ def circuit(): def test_observable_return_type_is_sample(self, mocker): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`""" n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=n_shots) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -198,7 +198,7 @@ def circuit(): def test_providing_observable_and_wires(self): """Test that a ValueError is raised if both an observable is provided and wires are specified""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -214,7 +214,7 @@ def circuit(): def test_providing_no_observable_and_no_wires(self, mocker): """Test that we can provide no observable and no wires to sample function""" - dev = qml.device("default.qubit", wires=2, shots=1000) + dev = qml.device("default.qubit.legacy", wires=2, shots=1000) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -237,7 +237,7 @@ def test_providing_no_observable_and_no_wires_shot_vector(self, mocker): shots1 = 1 shots2 = 10 shots3 = 1000 - dev = qml.device("default.qubit", wires=num_wires, shots=[shots1, shots2, shots3]) + dev = qml.device("default.qubit.legacy", wires=num_wires, shots=[shots1, shots2, shots3]) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -266,7 +266,7 @@ def test_providing_no_observable_and_wires(self, mocker): """Test that we can provide no observable but specify wires to the sample function""" wires = [0, 2] wires_obj = qml.wires.Wires(wires) - dev = qml.device("default.qubit", wires=3, shots=1000) + dev = qml.device("default.qubit.legacy", wires=3, shots=1000) spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) @@ -318,7 +318,7 @@ def test_numeric_type(self, obs, exp): def test_shape_no_shots_error(self): """Test that the appropriate error is raised with no shots are specified""" - dev = qml.device("default.qubit", wires=2, shots=None) + dev = qml.device("default.qubit.legacy", wires=2, shots=None) shots = Shots(None) mp = qml.sample() @@ -339,7 +339,7 @@ def test_shape_no_shots_error(self): def test_shape(self, obs): """Test that the shape is correct.""" shots = 10 - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) res = qml.sample(obs) if obs is not None else qml.sample() expected = (shots,) if obs is not None else (shots, 3) assert res.shape(dev, Shots(shots)) == expected @@ -347,7 +347,7 @@ def test_shape(self, obs): @pytest.mark.parametrize("n_samples", (1, 10)) def test_shape_wires(self, n_samples): """Test that the shape is correct when wires are provided.""" - dev = qml.device("default.qubit", wires=3, shots=n_samples) + dev = qml.device("default.qubit.legacy", wires=3, shots=n_samples) mp = qml.sample(wires=(0, 1)) assert mp.shape(dev, Shots(n_samples)) == (n_samples, 2) if n_samples != 1 else (2,) @@ -363,7 +363,7 @@ def test_shape_wires(self, n_samples): def test_shape_shot_vector(self, obs): """Test that the shape is correct with the shot vector too.""" shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vector) res = qml.sample(obs) if obs is not None else qml.sample() expected = ((), (2,), (3,)) if obs is not None else ((3,), (2, 3), (3, 3)) assert res.shape(dev, Shots(shot_vector)) == expected @@ -371,7 +371,7 @@ def test_shape_shot_vector(self, obs): def test_shape_shot_vector_obs(self): """Test that the shape is correct with the shot vector and a observable too.""" shot_vec = (2, 2) - dev = qml.device("default.qubit", wires=3, shots=shot_vec) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vec) @qml.qnode(dev) def circuit(): @@ -394,7 +394,7 @@ def test_sample_empty_wires(self): @pytest.mark.parametrize("shots", [2, 100]) def test_sample_no_arguments(self, shots): """Test that using ``qml.sample`` with no arguments returns the samples of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) @qml.qnode(dev) def circuit(): @@ -425,7 +425,7 @@ def test_jitting_with_sampling_on_subset_of_wires(samples): jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit", wires=3, shots=samples) + dev = qml.device("default.qubit.legacy", wires=3, shots=samples) @qml.qnode(dev, interface="jax") def circuit(x): diff --git a/tests/measurements/test_state.py b/tests/measurements/test_state.py index 5198c77ecaa..f8a0420c924 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -108,7 +108,7 @@ class TestState: 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) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def func(): @@ -121,7 +121,7 @@ def func(): def test_return_type_is_state(self): """Test that the return type of the observable is State""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def func(): @@ -137,7 +137,7 @@ def func(): def test_state_correct_ghz(self, wires): """Test that the correct state is returned when the circuit prepares a GHZ state""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def func(): @@ -158,7 +158,7 @@ def test_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) @qml.qnode(dev) def func(): @@ -176,7 +176,7 @@ def test_state_equal_to_dev_state(self, wires): """Test that the returned state is equal to the one stored in dev.state for a template circuit""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) weights = np.random.random( qml.templates.StronglyEntanglingLayers.shape(n_layers=3, n_wires=wires) @@ -195,7 +195,7 @@ def test_interface_tf(self): """Test that the state correctly outputs in the tensorflow interface""" import tensorflow as tf - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, interface="tf") def func(): @@ -216,7 +216,7 @@ def test_interface_torch(self): """Test that the state correctly outputs in the torch interface""" import torch - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, interface="torch") def func(): @@ -235,7 +235,7 @@ def func(): @pytest.mark.autograd def test_jacobian_not_supported(self): """Test if an error is raised if the jacobian method is called via qml.grad""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, diff_method="parameter-shift") def func(x): @@ -257,7 +257,7 @@ def func(x): def test_no_state_capability(self, monkeypatch): """Test if an error is raised for devices that are not capable of returning the state. This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) capabilities = dev.capabilities().copy() capabilities["returns_state"] = False @@ -287,7 +287,7 @@ def test_default_qubit(self, diff_method): """Test that the returned state is equal to the expected returned state for all of PennyLane's built in statevector devices""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, diff_method=diff_method) def func(): @@ -391,7 +391,7 @@ def loss_fn(x): @pytest.mark.parametrize("wires", [[0, 2, 3, 1], ["a", -1, "b", 1000]]) def test_custom_wire_labels(self, wires): """Test the state when custom wire labels are used""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev, diff_method="parameter-shift") def func(): @@ -407,14 +407,14 @@ def func(): @pytest.mark.parametrize("shots", [None, 1, 10]) def test_shape(self, shots): """Test that the shape is correct for qml.state.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) res = qml.state() assert res.shape(dev, Shots(shots)) == (2**3,) @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) def test_shape_shot_vector(self, s_vec): """Test that the shape is correct for qml.state with the shot vector too.""" - dev = qml.device("default.qubit", wires=3, shots=s_vec) + dev = qml.device("default.qubit.legacy", wires=3, shots=s_vec) res = qml.state() assert res.shape(dev, Shots(s_vec)) == ((2**3,), (2**3,), (2**3,)) @@ -430,7 +430,7 @@ class TestDensityMatrix: # pylint: disable=too-many-public-methods @pytest.mark.parametrize("wires", range(2, 5)) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) 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""" @@ -446,7 +446,7 @@ def circuit(): assert state_val.shape == (2, 2) assert state_val.dtype == np.complex128 - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_return_type_is_state(self, dev_name): """Test that the return type of the observable is State""" @@ -463,7 +463,7 @@ def func(): assert obs[0].return_type is State @pytest.mark.torch - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) def test_correct_density_matrix_torch(self, dev_name, diff_method): """Test that the correct density matrix is returned using torch interface.""" @@ -487,7 +487,7 @@ def func(): ) @pytest.mark.jax - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) def test_correct_density_matrix_jax(self, dev_name, diff_method): """Test that the correct density matrix is returned using JAX interface.""" @@ -510,7 +510,7 @@ def func(): ) @pytest.mark.tf - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) def test_correct_density_matrix_tf(self, dev_name, diff_method): """Test that the correct density matrix is returned using the TensorFlow interface.""" @@ -532,7 +532,7 @@ def func(): qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_product_state_first(self, dev_name): """Test that the correct density matrix is returned when tracing out a product state""" @@ -556,7 +556,7 @@ def func(): qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_product_state_second(self, dev_name): """Test that the correct density matrix is returned when tracing out a product state""" @@ -579,7 +579,7 @@ def func(): qml.density_matrix(wires=1).process_state(state=dev.state, wire_order=dev.wires), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) @pytest.mark.parametrize("return_wire_order", ([0, 1], [1, 0])) def test_correct_density_matrix_product_state_both(self, dev_name, return_wire_order): """Test that the correct density matrix is returned @@ -608,7 +608,7 @@ def func(): ), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_three_wires_first_two(self, dev_name): """Test that the correct density matrix is returned for an example with three wires, and tracing out the third wire.""" @@ -640,7 +640,7 @@ def func(): ), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_three_wires_last_two(self, dev_name): """Test that the correct density matrix is returned for an example with three wires, and tracing out the first wire.""" @@ -676,7 +676,7 @@ def func(): ), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) @pytest.mark.parametrize( "return_wire_order", ([0], [1], [2], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2, 0], [2, 1, 0]) ) @@ -716,7 +716,7 @@ def func(): ), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_mixed_state(self, dev_name): """Test that the correct density matrix for an example with a mixed state""" @@ -732,7 +732,7 @@ def func(): assert np.allclose(np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]), density) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_correct_density_matrix_all_wires(self, dev_name): """Test that the correct density matrix is returned when all wires are given""" @@ -764,7 +764,7 @@ def func(): ), ) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_return_with_other_types(self, dev_name): """Test that an exception is raised when a state is returned along with another return type""" @@ -787,7 +787,7 @@ def func(): def test_no_state_capability(self, monkeypatch): """Test if an error is raised for devices that are not capable of returning the density matrix. This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) capabilities = dev.capabilities().copy() capabilities["returns_state"] = False @@ -816,7 +816,7 @@ def func(): func() @pytest.mark.parametrize("wires", [[0, 2], ["a", -1]]) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_custom_wire_labels(self, wires, dev_name): """Test that the correct density matrix for an example with a mixed state when using custom wires""" @@ -843,7 +843,7 @@ def func(): ) @pytest.mark.parametrize("wires", [[3, 1], ["b", 1000]]) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) + @pytest.mark.parametrize("dev_name", ["default.qubit.legacy", "default.mixed"]) def test_custom_wire_labels_all_wires(self, wires, dev_name): """Test that the correct density matrix for an example with a mixed state when using custom wires""" @@ -872,14 +872,14 @@ def func(): @pytest.mark.parametrize("shots", [None, 1, 10]) def test_shape(self, shots): """Test that the shape is correct for qml.density_matrix.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) res = qml.density_matrix(wires=[0, 1]) assert res.shape(dev, Shots(shots)) == (2**2, 2**2) @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) def test_shape_shot_vector(self, s_vec): """Test that the shape is correct for qml.density_matrix with the shot vector too.""" - dev = qml.device("default.qubit", wires=3, shots=s_vec) + dev = qml.device("default.qubit.legacy", wires=3, shots=s_vec) res = qml.density_matrix(wires=[0, 1]) assert res.shape(dev, Shots(s_vec)) == ( (2**2, 2**2), diff --git a/tests/measurements/test_var.py b/tests/measurements/test_var.py index 191e6937cfa..74fdfb513ad 100644 --- a/tests/measurements/test_var.py +++ b/tests/measurements/test_var.py @@ -51,7 +51,7 @@ class TestVar: @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) def test_value(self, tol, r_dtype, mocker, shots): """Test that the var function works""" - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) spy = mocker.spy(qml.QubitDevice, "var") dev.R_DTYPE = r_dtype @@ -79,7 +79,7 @@ def circuit(x): def test_not_an_observable(self, mocker): """Test that a UserWarning is raised if the provided argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) @@ -94,7 +94,7 @@ def circuit(): def test_observable_return_type_is_variance(self, mocker): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) @@ -122,7 +122,7 @@ def test_numeric_type(self, obs): ) def test_shape(self, obs): """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) res = qml.var(obs) # pylint: disable=use-implicit-booleaness-not-comparison assert res.shape(dev, Shots(None)) == () @@ -136,14 +136,14 @@ def test_shape_shot_vector(self, obs): """Test that the shape is correct with the shot vector too.""" res = qml.var(obs) shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) + dev = qml.device("default.qubit.legacy", wires=3, shots=shot_vector) assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) def test_projector_var(self, state, shots, mocker): """Tests that the variance of a ``Projector`` object is computed correctly.""" - dev = qml.device("default.qubit", wires=3, shots=shots) + dev = qml.device("default.qubit.legacy", wires=3, shots=shots) spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) @@ -165,7 +165,7 @@ def test_permuted_wires(self, mocker): qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) ) - dev = qml.device("default.qubit", wires=["h", 8, 10]) + dev = qml.device("default.qubit.legacy", wires=["h", 8, 10]) spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) diff --git a/tests/measurements/test_vn_entropy.py b/tests/measurements/test_vn_entropy.py index d9551f3b34a..e69e88e5256 100644 --- a/tests/measurements/test_vn_entropy.py +++ b/tests/measurements/test_vn_entropy.py @@ -76,7 +76,7 @@ class TestInitialization: @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) def test_vn_entropy(self, interface, state_vector, expected): """Tests the output of qml.vn_entropy""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface) def circuit(): @@ -94,7 +94,7 @@ def circuit(): def test_queue(self): """Test that the right measurement class is queued.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -121,7 +121,7 @@ def test_properties(self): def test_shape(self, shots, shape): """Test the ``shape`` method.""" meas = qml.vn_entropy(wires=0) - dev = qml.device("default.qubit", wires=1, shots=shots) + dev = qml.device("default.qubit.legacy", wires=1, shots=shots) assert meas.shape(dev, Shots(shots)) == shape @@ -131,7 +131,7 @@ class TestIntegration: parameters = np.linspace(0, 2 * np.pi, 10) - devices = ["default.qubit", "default.mixed", "lightning.qubit"] + devices = ["default.qubit.legacy", "default.mixed", "lightning.qubit"] single_wires_list = [ [0], @@ -142,12 +142,12 @@ class TestIntegration: check_state = [True, False] - devices = ["default.qubit", "default.mixed"] + devices = ["default.qubit.legacy", "default.mixed"] diff_methods = ["backprop", "finite-diff"] def test_shot_vec_error(self): """Test an error is raised when using shot vectors with vn_entropy.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -187,7 +187,7 @@ def circuit_entropy(x): def test_IsingXX_qnode_entropy_grad(self, param, wires, base, diff_method): """Test entropy for a QNode gradient with autograd.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, diff_method=diff_method) def circuit_entropy(x): @@ -234,7 +234,7 @@ def test_IsingXX_qnode_entropy_grad_torch(self, param, wires, base, diff_method) """Test entropy for a QNode gradient with torch.""" import torch - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface="torch", diff_method=diff_method) def circuit_entropy(x): @@ -286,7 +286,7 @@ def test_IsingXX_qnode_entropy_grad_tf(self, param, wires, base, diff_method, in """Test entropy for a QNode gradient with tf.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method=diff_method) def circuit_entropy(x): @@ -339,7 +339,7 @@ def test_IsingXX_qnode_entropy_grad_jax(self, param, wires, base, diff_method, i """Test entropy for a QNode gradient with Jax.""" import jax - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method=diff_method) def circuit_entropy(x): @@ -388,7 +388,7 @@ def test_IsingXX_qnode_entropy_grad_jax_jit(self, param, wires, base, diff_metho """Test entropy for a QNode gradient with Jax-jit.""" import jax - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev, interface=interface, diff_method=diff_method) def circuit_entropy(x): From 025c8e4baf36768f5b13abc50d9ed4fa7ccacbf5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 21 Aug 2023 17:50:50 -0400 Subject: [PATCH 22/78] fix measurement tests expect classical shadow --- pennylane/devices/qubit/sampling.py | 4 +- pennylane/interfaces/jax_jit.py | 12 +- pennylane/interfaces/jax_jit_tuple.py | 4 +- pennylane/measurements/mutual_info.py | 8 + pennylane/measurements/probs.py | 5 +- pennylane/measurements/sample.py | 2 +- .../test_counts_default_qubit_2.py | 169 +++---------- .../test_expval_default_qubit_2.py | 61 +---- .../test_measurements_default_qubit_2.py | 75 ++---- .../test_mutual_info_default_qubit_2.py | 38 ++- .../test_probs_default_qubit_2.py | 108 ++------ .../test_sample_default_qubit_2.py | 79 ++---- .../test_state_default_qubit_2.py | 234 ++++++------------ .../test_var_default_qubit_2.py | 53 +--- .../test_vn_entropy_default_qubit_2.py | 32 +-- 15 files changed, 231 insertions(+), 653 deletions(-) diff --git a/pennylane/devices/qubit/sampling.py b/pennylane/devices/qubit/sampling.py index 2bb170ec5ad..16926ac7461 100644 --- a/pennylane/devices/qubit/sampling.py +++ b/pennylane/devices/qubit/sampling.py @@ -23,6 +23,7 @@ ExpectationMP, ClassicalShadowMP, ShadowExpvalMP, + CountsMP, ) from pennylane.typing import TensorLike from .apply_operation import apply_operation @@ -194,7 +195,8 @@ def _measure_with_samples_diagonalizing_gates( def _process_single_shot(samples): processed = [] for mp in mps: - if not isinstance(res := mp.process_samples(samples, wires), dict): + res = mp.process_samples(samples, wires) + if not isinstance(mp, CountsMP): res = qml.math.squeeze(res) processed.append(res) diff --git a/pennylane/interfaces/jax_jit.py b/pennylane/interfaces/jax_jit.py index 551004143aa..0d13f4b5c68 100644 --- a/pennylane/interfaces/jax_jit.py +++ b/pennylane/interfaces/jax_jit.py @@ -98,11 +98,17 @@ def execute_legacy( ) -def _numeric_type_to_dtype(numeric_type): +def _numeric_type_to_dtype(numeric_type, device): """Auxiliary function for converting from Python numeric types to JAX dtypes based on the precision defined for the interface.""" single_precision = dtype is jnp.float32 + if numeric_type is bool: + if isinstance(device, qml.Device): + numeric_type = int + else: + return jnp.bool_ + if numeric_type is int: return jnp.int32 if single_precision else jnp.int64 @@ -125,7 +131,7 @@ def _extract_shape_dtype_structs(tapes, device): for t in tapes: shape = t.shape(device) - tape_dtype = _numeric_type_to_dtype(t.numeric_type) + tape_dtype = _numeric_type_to_dtype(t.numeric_type, device) shape_and_dtype = jax.ShapeDtypeStruct(tuple(shape), tape_dtype) shape_dtypes.append(shape_and_dtype) @@ -290,7 +296,7 @@ def wrapper(p): jacobian_shape = [] for t, p in zip(tapes, params): shape = t.shape(device) + (len(p),) - _dtype = _numeric_type_to_dtype(t.numeric_type) + _dtype = _numeric_type_to_dtype(t.numeric_type, device) shape = [shape] if isinstance(shape, int) else shape o = jax.ShapeDtypeStruct(tuple(shape), _dtype) jacobian_shape.append(o) diff --git a/pennylane/interfaces/jax_jit_tuple.py b/pennylane/interfaces/jax_jit_tuple.py index 856f7dba59a..c00693d821a 100644 --- a/pennylane/interfaces/jax_jit_tuple.py +++ b/pennylane/interfaces/jax_jit_tuple.py @@ -50,10 +50,10 @@ def _create_shape_dtype_struct(tape: "qml.tape.QuantumScript", device: "qml.Devi shape = tape.shape(device) if len(tape.measurements) == 1: - tape_dtype = _numeric_type_to_dtype(tape.numeric_type) + tape_dtype = _numeric_type_to_dtype(tape.numeric_type, device) return jax.ShapeDtypeStruct(tuple(shape), tape_dtype) - tape_dtype = tuple(_numeric_type_to_dtype(elem) for elem in tape.numeric_type) + tape_dtype = tuple(_numeric_type_to_dtype(elem, device) for elem in tape.numeric_type) return tuple(jax.ShapeDtypeStruct(tuple(s), d) for s, d in zip(shape, tape_dtype)) diff --git a/pennylane/measurements/mutual_info.py b/pennylane/measurements/mutual_info.py index 991d56a7554..9694a8a4e10 100644 --- a/pennylane/measurements/mutual_info.py +++ b/pennylane/measurements/mutual_info.py @@ -15,6 +15,7 @@ """ This module contains the qml.mutual_info measurement. """ +from copy import copy from typing import Sequence, Optional import pennylane as qml @@ -131,6 +132,13 @@ def return_type(self): def numeric_type(self): return float + def map_wires(self, wire_map: dict): + new_measurement = copy(self) + new_measurement._wires = [ + Wires([wire_map.get(wire, wire)]) for wires in self.wires for wire in wires + ] + return new_measurement + def _shape_legacy(self, device, shots): # pylint: disable=unused-argument if not shots.has_partitioned_shots: return (1,) diff --git a/pennylane/measurements/probs.py b/pennylane/measurements/probs.py index 0fa8c9a32e7..2158559229a 100644 --- a/pennylane/measurements/probs.py +++ b/pennylane/measurements/probs.py @@ -279,11 +279,12 @@ def marginal_prob(self, prob, wire_order, batch_size): # return prob # determine which subsystems are to be summed over - inactive_wires = Wires.unique_wires([wire_order, self.wires]) + self_wires = self.wires or qml.wires.Wires(wire_order) + inactive_wires = Wires.unique_wires([wire_order, self_wires]) # translate to wire labels used by device wire_map = dict(zip(wire_order, range(len(wire_order)))) - mapped_wires = [wire_map[w] for w in self.wires] + mapped_wires = [wire_map[w] for w in self_wires] inactive_wires = [wire_map[w] for w in inactive_wires] # reshape the probability so that each axis corresponds to a wire diff --git a/pennylane/measurements/sample.py b/pennylane/measurements/sample.py index 89f40c78cf8..1cc36409bbb 100644 --- a/pennylane/measurements/sample.py +++ b/pennylane/measurements/sample.py @@ -144,7 +144,7 @@ def numeric_type(self): # built-in observable with integer eigenvalues or a tensor product thereof if self.obs is None: # Computational basis samples - return int + return bool int_eigval_obs = {qml.PauliX, qml.PauliY, qml.PauliZ, qml.Hadamard, qml.Identity} tensor_terms = self.obs.obs if hasattr(self.obs, "obs") else [self.obs] every_term_standard = all(o.__class__ in int_eigval_obs for o in tensor_terms) diff --git a/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py index eeee4a24e5f..3ac4ce72070 100644 --- a/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py @@ -18,36 +18,9 @@ import pennylane as qml from pennylane.measurements import AllCounts, Counts, CountsMP -from pennylane.operation import Operator from pennylane.wires import Wires -# TODO: Remove this when new CustomMP are the default -def custom_measurement_process(device, spy): - assert len(spy.call_args_list) > 0 # make sure method is mocked properly - - samples = device._samples # pylint:disable=protected-access - call_args_list = list(spy.call_args_list) - for call_args in call_args_list: - if not call_args.kwargs.get("counts", False): - continue - meas = call_args.args[1] - shot_range, bin_size = (call_args.kwargs["shot_range"], call_args.kwargs["bin_size"]) - if isinstance(meas, Operator): - all_outcomes = meas.return_type is AllCounts - meas = qml.counts(op=meas, all_outcomes=all_outcomes) - old_res = device.sample(call_args.args[1], **call_args.kwargs) - new_res = meas.process_samples( - samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size - ) - if isinstance(old_res, dict): - old_res = [old_res] - new_res = [new_res] - for old, new in zip(old_res, new_res): - assert old.keys() == new.keys() - assert qml.math.allequal(list(old.values()), list(new.values())) - - class TestCounts: """Tests for the counts function""" @@ -211,12 +184,11 @@ def test_counts_all_outcomes_obs(self): class TestCountsIntegration: # pylint:disable=too-many-public-methods,not-an-iterable - def test_counts_dimension(self, mocker): + def test_counts_dimension(self): """Test that the counts function outputs counts of the right size""" n_sample = 10 dev = qml.device("default.qubit", wires=2, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -228,14 +200,11 @@ def circuit(): assert len(sample) == 2 assert np.all([sum(s.values()) == n_sample for s in sample]) - custom_measurement_process(dev, spy) - - def test_batched_counts_dimension(self, mocker): + def test_batched_counts_dimension(self): """Test that the counts function outputs counts of the right size with batching""" n_sample = 10 dev = qml.device("default.qubit", wires=2, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -248,14 +217,11 @@ def circuit(): assert len(sample) == 2 assert np.all([sum(s.values()) == n_sample for batch in sample for s in batch]) - custom_measurement_process(dev, spy) - - def test_counts_combination(self, mocker): + def test_counts_combination(self): """Test the output of combining expval, var and counts""" n_sample = 10 dev = qml.device("default.qubit", wires=3, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -272,14 +238,11 @@ def circuit(): assert len(result) == 3 assert sum(result[0].values()) == n_sample - custom_measurement_process(dev, spy) - - def test_single_wire_counts(self, mocker): + def test_single_wire_counts(self): """Test the return type and shape of sampling counts from a single wire""" n_sample = 10 dev = qml.device("default.qubit", wires=1, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -292,15 +255,12 @@ def circuit(): assert isinstance(result, dict) assert sum(result.values()) == n_sample - custom_measurement_process(dev, spy) - - def test_multi_wire_counts_regular_shape(self, mocker): + def test_multi_wire_counts_regular_shape(self): """Test the return type and shape of sampling multiple wires where a rectangular array is expected""" n_sample = 10 dev = qml.device("default.qubit", wires=3, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -318,8 +278,6 @@ def circuit(): assert all(sum(r.values()) == n_sample for r in result) assert all(all(v.dtype == np.dtype("int") for v in r.values()) for r in result) - custom_measurement_process(dev, spy) - def test_observable_return_type_is_counts(self): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Counts`""" n_shots = 10 @@ -333,10 +291,9 @@ def circuit(): circuit() assert circuit._qfunc_output.return_type is Counts # pylint: disable=protected-access - def test_providing_no_observable_and_no_wires_counts(self, mocker): + def test_providing_no_observable_and_no_wires_counts(self): """Test that we can provide no observable and no wires to sample function""" dev = qml.device("default.qubit", wires=2, shots=1000) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -348,14 +305,11 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - - def test_providing_no_observable_and_wires_counts(self, mocker): + def test_providing_no_observable_and_wires_counts(self): """Test that we can provide no observable but specify wires to the sample function""" wires = [0, 2] wires_obj = qml.wires.Wires(wires) dev = qml.device("default.qubit", wires=3, shots=1000) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -368,13 +322,10 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - - def test_batched_counts_work_individually(self, mocker): + def test_batched_counts_work_individually(self): """Test that each counts call operates independently""" n_shots = 10 dev = qml.device("default.qubit", wires=1, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -382,20 +333,19 @@ def circuit(): return qml.counts() assert circuit() == [{"1": 10}, {"0": 10}] - custom_measurement_process(dev, spy) @pytest.mark.all_interfaces @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_no_op_finite_shots(self, interface, wires, basis_state, mocker): + def test_counts_no_op_finite_shots(self, interface, wires, basis_state): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): + qml.Identity(wires=[0, 1, 2]) qml.PauliX(1) return qml.counts(wires=wires) @@ -403,16 +353,13 @@ def circuit(): assert res == {basis_state: n_shots} assert qml.math.get_interface(res[basis_state]) == interface - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_operator_finite_shots(self, interface, mocker): + def test_counts_operator_finite_shots(self, interface): """Check all interfaces with observable measurement counts and finite shot""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): @@ -421,22 +368,20 @@ def circuit(): res = circuit() assert res == {1: n_shots} - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) def test_counts_binned( - self, shot_vec, interface, wires, basis_state, mocker + self, shot_vec, interface, wires, basis_state ): # pylint:disable=too-many-arguments """Check all interfaces with computational basis state counts and different shot vectors""" dev = qml.device("default.qubit", wires=3, shots=shot_vec) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): + qml.Identity(wires=[0, 1, 2]) qml.PauliX(1) return qml.counts(wires=wires) @@ -449,16 +394,13 @@ def circuit(): assert len(res) == len(shot_vec) assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_operator_binned(self, shot_vec, interface, mocker): + def test_counts_operator_binned(self, shot_vec, interface): """Check all interfaces with observable measurement counts and different shot vectors""" dev = qml.device("default.qubit", wires=3, shots=shot_vec) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): @@ -473,17 +415,15 @@ def circuit(): assert len(res) == len(shot_vec) assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - def test_counts_binned_4_wires(self, shot_vec, mocker): + def test_counts_binned_4_wires(self, shot_vec): """Check the autograd interface with computational basis state counts and different shot vectors on a device with 4 wires""" dev = qml.device("default.qubit", wires=4, shots=shot_vec) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface="autograd") def circuit(): + qml.Identity(0) qml.PauliX(1) qml.PauliX(2) qml.PauliX(3) @@ -499,14 +439,11 @@ def circuit(): assert len(res) == len(shot_vec) assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - def test_counts_operator_binned_4_wires(self, shot_vec, mocker): + def test_counts_operator_binned_4_wires(self, shot_vec): """Check the autograd interface with observable samples to obtain counts from and different shot vectors on a device with 4 wires""" dev = qml.device("default.qubit", wires=4, shots=shot_vec) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface="autograd") def circuit(): @@ -525,8 +462,6 @@ def circuit(): assert len(res) == len(shot_vec) assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - custom_measurement_process(dev, spy) - meas2 = [ qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(0)), @@ -538,11 +473,10 @@ def circuit(): @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) @pytest.mark.parametrize("meas2", meas2) @pytest.mark.parametrize("shots", [1000, (1, 10)]) - def test_counts_observable_finite_shots(self, interface, meas2, shots, mocker): + def test_counts_observable_finite_shots(self, interface, meas2, shots): """Check all interfaces with observable measurement counts and finite shot""" dev = qml.device("default.qubit", wires=3, shots=shots) - spy = mocker.spy(qml.QubitDevice, "sample") if isinstance(shots, tuple) and interface == "torch": pytest.skip("Torch needs to be updated for shot vectors.") @@ -569,15 +503,12 @@ def circuit(): assert isinstance(res[1], tuple) assert isinstance(res[1][0], dict) - custom_measurement_process(dev, spy) - - def test_all_outcomes_kwarg_providing_observable(self, mocker): + def test_all_outcomes_kwarg_providing_observable(self): """Test that the dictionary keys *all* eigenvalues of the observable, including 0 count values, if observable is given and all_outcomes=True""" n_shots = 10 dev = qml.device("default.qubit", wires=1, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -588,35 +519,30 @@ def circuit(): assert res == {1: n_shots, -1: 0} - custom_measurement_process(dev, spy) - - def test_all_outcomes_kwarg_no_observable_no_wires(self, mocker): + def test_all_outcomes_kwarg_no_observable_no_wires(self): """Test that the dictionary keys are *all* the possible combinations of basis states for the device, including 0 count values, if no wire count and no observable are given and all_outcomes=True""" n_shots = 10 dev = qml.device("default.qubit", wires=2, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): + qml.Identity(wires=[0, 1]) return qml.counts(all_outcomes=True) res = circuit() assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} - custom_measurement_process(dev, spy) - - def test_all_outcomes_kwarg_providing_wires_and_no_observable(self, mocker): + def test_all_outcomes_kwarg_providing_wires_and_no_observable(self): """Test that the dictionary keys are *all* possible combinations of basis states for the specified wires, including 0 count values, if wire count is given and all_outcomes=True""" n_shots = 10 dev = qml.device("default.qubit", wires=4, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -626,15 +552,12 @@ def circuit(): assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} - custom_measurement_process(dev, spy) - - def test_all_outcomes_hermitian(self, mocker): + def test_all_outcomes_hermitian(self): """Tests that the all_outcomes=True option for counts works with the qml.Hermitian observable""" n_shots = 10 dev = qml.device("default.qubit", wires=2, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") A = np.array([[1, 0], [0, -1]]) @@ -646,17 +569,15 @@ def circuit(x): assert res == {-1.0: 0, 1.0: n_shots} - custom_measurement_process(dev, spy) - - def test_all_outcomes_multiple_measurements(self, mocker): + def test_all_outcomes_multiple_measurements(self): """Tests that the all_outcomes=True option for counts works when multiple measurements are performed""" dev = qml.device("default.qubit", wires=2, shots=10) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): + qml.Identity(wires=[0, 1]) return qml.sample(qml.PauliZ(0)), qml.counts(), qml.counts(all_outcomes=True) res = circuit() @@ -664,13 +585,11 @@ def circuit(): assert len(res[0]) == 10 assert res[1] == {"00": 10} assert res[2] == {"00": 10, "01": 0, "10": 0, "11": 0} - custom_measurement_process(dev, spy) - def test_batched_all_outcomes(self, mocker): + def test_batched_all_outcomes(self): """Tests that all_outcomes=True works with broadcasting.""" n_shots = 10 dev = qml.device("default.qubit", wires=1, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -679,8 +598,6 @@ def circuit(): assert circuit() == [{1: 0, -1: n_shots}, {1: n_shots, -1: 0}] - custom_measurement_process(dev, spy) - def test_counts_empty_wires(self): """Test that using ``qml.counts`` with an empty wire list raises an error.""" with pytest.raises(ValueError, match="Cannot set an empty list of wires."): @@ -693,6 +610,7 @@ def test_counts_no_arguments(self, shots): @qml.qnode(dev) def circuit(): + qml.Identity(wires=[0, 1, 2]) return qml.counts() res = circuit() @@ -703,14 +621,14 @@ def circuit(): @pytest.mark.all_interfaces @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_counts_no_op_finite_shots(interface, wires, basis_state, mocker): +def test_counts_no_op_finite_shots(interface, wires, basis_state): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): + qml.Identity(wires=[0, 1, 2]) qml.PauliX(1) return qml.counts(wires=wires) @@ -718,59 +636,55 @@ def circuit(): assert res == {basis_state: n_shots} assert qml.math.get_interface(res[basis_state]) == interface - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_no_op_finite_shots(interface, wires, basis_states, mocker): +def test_batched_counts_no_op_finite_shots(interface, wires, basis_states): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): + qml.Identity(wires=[0, 1, 2]) qml.pow(qml.PauliX(1), z=[1, 2]) return qml.counts(wires=wires) assert circuit() == [{basis_state: n_shots} for basis_state in basis_states] - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_and_expval_no_op_finite_shots(interface, wires, basis_states, mocker): +def test_batched_counts_and_expval_no_op_finite_shots(interface, wires, basis_states): """Check all interfaces with computational basis state counts and finite shot""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): + qml.Identity(2) qml.pow(qml.PauliX(1), z=[1, 2]) return qml.counts(wires=wires), qml.expval(qml.PauliZ(0)) res = circuit() assert isinstance(res, tuple) and len(res) == 2 - assert res[0] == [{basis_state: n_shots} for basis_state in basis_states] + for i, basis_state in enumerate(basis_states): + assert list(res[0][i].keys()) == [basis_state] + assert qml.math.allequal(list(res[0][i].values()), n_shots) + # assert res[0] == [{basis_state: expected_n_shots} for basis_state in basis_states] assert len(res[1]) == 2 and qml.math.allequal(res[1], 1) - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_operator_finite_shots(interface, mocker): +def test_batched_counts_operator_finite_shots(interface): """Check all interfaces with observable measurement counts, batching and finite shots""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): @@ -779,16 +693,13 @@ def circuit(): assert circuit() == [{-1: n_shots}, {1: n_shots}] - custom_measurement_process(dev, spy) - @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_and_expval_operator_finite_shots(interface, mocker): +def test_batched_counts_and_expval_operator_finite_shots(interface): """Check all interfaces with observable measurement counts, batching and finite shots""" n_shots = 10 dev = qml.device("default.qubit", wires=3, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, interface=interface) def circuit(): @@ -799,5 +710,3 @@ def circuit(): assert isinstance(res, tuple) and len(res) == 2 assert res[0] == [{-1: n_shots}, {1: n_shots}] assert len(res[1]) == 2 and qml.math.allequal(res[1], [-1, 1]) - - custom_measurement_process(dev, spy) diff --git a/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py index 3d0e5c009b2..26b3caaf3be 100644 --- a/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py @@ -21,49 +21,19 @@ from pennylane.measurements.expval import ExpectationMP -# TODO: Remove this when new CustomMP are the default -def custom_measurement_process(device, spy): - assert len(spy.call_args_list) > 0 # make sure method is mocked properly - - samples = device._samples # pylint: disable=protected-access - state = device._state # pylint: disable=protected-access - call_args_list = list(spy.call_args_list) - for call_args in call_args_list: - obs = call_args.args[1] - shot_range, bin_size = ( - call_args.kwargs["shot_range"], - call_args.kwargs["bin_size"], - ) - # no need to use op, because the observable has already been applied to ``self.dev._state`` - meas = qml.expval(op=obs) - old_res = device.expval(obs, shot_range=shot_range, bin_size=bin_size) - if device.shots is None: - new_res = meas.process_state(state=state, wire_order=device.wires) - else: - new_res = meas.process_samples( - samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size - ) - assert qml.math.allclose(old_res, new_res) - - class TestExpval: """Tests for the expval function""" @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - def test_value(self, tol, r_dtype, mocker, shots): + def test_value(self, tol, shots): """Test that the expval interface works""" dev = qml.device("default.qubit", wires=2, shots=shots) - dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): qml.RX(x, wires=0) return qml.expval(qml.PauliY(0)) - new_dev = circuit.device - spy = mocker.spy(qml.QubitDevice, "expval") - x = 0.54 res = circuit(x) expected = -np.sin(x) @@ -72,16 +42,14 @@ def circuit(x): rtol = 0 if shots is None else 0.05 assert np.allclose(res, expected, atol=atol, rtol=rtol) - # pylint: disable=no-member, unsubscriptable-object + r_dtype = np.float64 if isinstance(res, tuple): assert res[0].dtype == r_dtype assert res[1].dtype == r_dtype else: assert res.dtype == r_dtype - custom_measurement_process(new_dev, spy) - - def test_not_an_observable(self, mocker): + def test_not_an_observable(self): """Test that a warning is raised if the provided argument might not be hermitian.""" dev = qml.device("default.qubit", wires=2) @@ -91,15 +59,10 @@ def circuit(): qml.RX(0.52, wires=0) return qml.expval(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - new_dev = circuit.device - spy = mocker.spy(qml.QubitDevice, "expval") - with pytest.warns(UserWarning, match="Prod might not be hermitian."): _ = circuit() - custom_measurement_process(new_dev, spy) - - def test_observable_return_type_is_expectation(self, mocker): + def test_observable_return_type_is_expectation(self): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`""" dev = qml.device("default.qubit", wires=2) @@ -109,13 +72,8 @@ def circuit(): assert res.return_type is Expectation return res - new_dev = circuit.device - spy = mocker.spy(qml.QubitDevice, "expval") - circuit() - custom_measurement_process(new_dev, spy) - @pytest.mark.parametrize( "obs", [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], @@ -151,7 +109,7 @@ def test_shape_shot_vector(self, obs): @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) - def test_projector_expval(self, state, shots, mocker): + def test_projector_expval(self, state, shots): """Tests that the expectation of a ``Projector`` object is computed correctly for both of its subclasses.""" dev = qml.device("default.qubit", wires=3, shots=shots) @@ -162,16 +120,11 @@ def circuit(): qml.Hadamard(0) return qml.expval(qml.Projector(state, wires=range(3))) - new_dev = circuit.device - spy = mocker.spy(qml.QubitDevice, "expval") - res = circuit() expected = [0.5, 0.5] if isinstance(shots, list) else 0.5 assert np.allclose(res, expected, atol=0.02, rtol=0.02) - custom_measurement_process(new_dev, spy) - - def test_permuted_wires(self, mocker): + def test_permuted_wires(self): """Test that the expectation value of an operator with permuted wires is the same.""" obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) obs_2 = qml.prod( @@ -179,7 +132,6 @@ def test_permuted_wires(self, mocker): ) dev = qml.device("default.qubit", wires=["h", 8, 10]) - spy = mocker.spy(qml.QubitDevice, "expval") @qml.qnode(dev) def circuit(): @@ -194,7 +146,6 @@ def circuit2(): return qml.expval(obs_2) assert circuit() == circuit2() - custom_measurement_process(dev, spy) def test_copy_observable(self): """Test that the observable is copied if present.""" diff --git a/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py index 3b8160419a5..3b29552cf4d 100644 --- a/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py @@ -481,7 +481,7 @@ def test_custom_sample_measurement(self): class MyMeasurement(SampleMeasurement): # pylint: disable=signature-differs - def process_samples(self, samples, wire_order, shot_range, bin_size): + def process_samples(self, samples, wire_order, shot_range=None, bin_size=None): return qml.math.sum(samples[..., self.wires]) dev = qml.device("default.qubit", wires=2, shots=1000) @@ -501,6 +501,10 @@ class MyMeasurement(SampleMeasurement): def process_samples(self, samples, wire_order, shot_range, bin_size): return qml.math.sum(samples[..., self.wires]) + @property + def return_type(self): + return Sample + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) @@ -509,25 +513,11 @@ def circuit(): return MyMeasurement(wires=[0]), MyMeasurement(wires=[1]) with pytest.raises( - ValueError, match="Shots must be specified in the device to compute the measurement " + qml.DeviceError, + match="Analytic circuits must only contain StateMeasurements; got sample", ): circuit() - def test_method_overriden_by_device(self): - """Test that the device can override a measurement process.""" - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(0) - return qml.sample(wires=[0]), qml.sample(wires=[1]) - - circuit.device.measurement_map[SampleMP] = "test_method" - circuit.device.test_method = lambda obs, shot_range=None, bin_size=None: 2 - - assert qml.math.allequal(circuit(), [2, 2]) - class TestStateMeasurement: """Tests for the SampleMeasurement class.""" @@ -547,39 +537,26 @@ def circuit(): assert circuit() == 1 - def test_sample_measurement_with_shots(self): - """Test that executing a state measurement with shots raises a warning.""" + def test_state_measurement_with_shots(self): + """Test that executing a state measurement with shots raises an error.""" class MyMeasurement(StateMeasurement): def process_state(self, state, wire_order): return qml.math.sum(state) + @property + def return_type(self): + return State + dev = qml.device("default.qubit", wires=2, shots=1000) @qml.qnode(dev) def circuit(): return MyMeasurement() - with pytest.warns( - UserWarning, - match="Requested measurement MyMeasurement with finite shots", - ): + with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): circuit() - def test_method_overriden_by_device(self): - """Test that the device can override a measurement process.""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface="autograd") - def circuit(): - return qml.state() - - circuit.device.measurement_map[StateMP] = "test_method" - circuit.device.test_method = lambda obs, shot_range=None, bin_size=None: 2 - - assert circuit() == 2 - class TestMeasurementTransform: """Tests for the MeasurementTransform class.""" @@ -587,28 +564,18 @@ class TestMeasurementTransform: def test_custom_measurement(self): """Test the execution of a custom measurement.""" - class MyMeasurement(MeasurementTransform): + class CountTapesMP(MeasurementTransform, SampleMeasurement): def process(self, tape, device): - return {device.shots: len(tape)} + tapes, _, _ = device.preprocess(tape) + return len(tapes) - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - return MyMeasurement() - - assert circuit() == {dev.shots: len(circuit.tape)} - - def test_method_overriden_by_device(self): - """Test that the device can override a measurement process.""" + def process_samples(self, samples, wire_order, shot_range=None, bin_size=None): + return [True] dev = qml.device("default.qubit", wires=2, shots=1000) @qml.qnode(dev) def circuit(): - return qml.classical_shadow(wires=0) - - circuit.device.measurement_map[ClassicalShadowMP] = "test_method" - circuit.device.test_method = lambda tape: 2 + return CountTapesMP(wires=[0]) - assert circuit() == 2 + assert circuit() == 1 diff --git a/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py index 79eedc1d44e..0a12a8aab36 100644 --- a/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py @@ -18,7 +18,6 @@ import pytest import pennylane as qml -from pennylane.interfaces import INTERFACE_MAP from pennylane.measurements import MutualInfo, Shots from pennylane.measurements.mutual_info import MutualInfoMP from pennylane.wires import Wires @@ -96,17 +95,12 @@ def circuit(): return qml.mutual_info(wires0=[0, 2], wires1=[1, 3]) res = circuit() - new_res = qml.mutual_info(wires0=[0, 2], wires1=[1, 3]).process_state( - state=circuit.device.state, wire_order=circuit.device.wires - ) assert np.allclose(res, expected, atol=1e-6) - assert np.allclose(new_res, expected, atol=1e-6) - assert INTERFACE_MAP.get(qml.math.get_interface(new_res)) == interface - assert res.dtype == new_res.dtype # pylint: disable=no-member - def test_shot_vec_error(self): + @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.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit", wires=2, shots=shots) @qml.qnode(device=dev) def circuit(x): @@ -114,9 +108,7 @@ def circuit(x): qml.CRX(x, wires=[0, 1]) return qml.mutual_info(wires0=[0], wires1=[1]) - with pytest.raises( - NotImplementedError, match="mutual information is not supported with shot vectors" - ): + with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): circuit(0.5) diff_methods = ["backprop", "finite-diff"] @@ -455,15 +447,12 @@ def circuit(params): circuit(params) @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - @pytest.mark.parametrize( - "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] - ) - def test_custom_wire_labels_error(self, device, interface, params): + @pytest.mark.parametrize("params", [np.array([0.0, 0.0]), np.array([0.3, 0.4])]) + def test_custom_wire_labels_error(self, interface, params): """Tests that an error is raised when mutual information is measured with custom wire labels""" - dev = qml.device(device, wires=["a", "b"]) + dev = qml.device("default.qubit", wires=["a", "b"]) params = qml.math.asarray(params, like=interface) @@ -474,6 +463,13 @@ def circuit(params): qml.CNOT(wires=["a", "b"]) return qml.mutual_info(wires0=["a"], wires1=["b"]) - msg = "Returning the mutual information is not supported when using custom wire labels" - with pytest.raises(qml.QuantumFunctionError, match=msg): - circuit(params) + @qml.qnode(dev, interface=interface) + def circuit_expected(params): + qml.RY(params[0], wires="a") + qml.RY(params[1], wires="b") + qml.CNOT(wires=["a", "b"]) + return qml.state() + + actual = circuit(params) + expected = qml.qinfo.mutual_info(circuit_expected, wires0=["a"], wires1=["b"])(params) + assert np.allclose(actual, expected) diff --git a/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py index a07fd3da1b9..90eb587b9d8 100644 --- a/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py @@ -26,34 +26,6 @@ from pennylane.queuing import AnnotatedQueue -# TODO: Remove this when new CustomMP are the default -def custom_measurement_process(device, spy): - assert len(spy.call_args_list) > 0 # make sure method is mocked properly - - samples = device._samples # pylint: disable=protected-access - state = device._state # pylint: disable=protected-access - call_args_list = list(spy.call_args_list) - for call_args in call_args_list: - wires, shot_range, bin_size = ( - call_args.kwargs["wires"], - call_args.kwargs["shot_range"], - call_args.kwargs["bin_size"], - ) - # no need to use op, because the observable has already been applied to ``dev._state`` - meas = qml.probs(wires=wires) - old_res = device.probability(wires=wires, shot_range=shot_range, bin_size=bin_size) - if device.shots is None: - new_res = meas.process_state(state=state, wire_order=device.wires) - else: - new_res = meas.process_samples( - samples=samples, - wire_order=device.wires, - shot_range=shot_range, - bin_size=bin_size, - ) - assert qml.math.allequal(old_res, new_res) - - # make the test deterministic np.random.seed(42) @@ -137,16 +109,16 @@ def test_probs_no_arguments(self, shots): @qml.qnode(dev) def circuit(): + qml.Identity(wires=[0, 1, 2]) return qml.probs() res = circuit() assert qml.math.allequal(res, [1, 0, 0, 0, 0, 0, 0, 0]) - def test_full_prob(self, init_state, tol, mocker): + def test_full_prob(self, init_state, tol): """Test that the correct probability is returned.""" dev = qml.device("default.qubit", wires=4) - spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -159,12 +131,9 @@ def circuit(): expected = np.abs(state) ** 2 assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - - def test_marginal_prob(self, init_state, tol, mocker): + def test_marginal_prob(self, init_state, tol): """Test that the correct marginal probability is returned.""" dev = qml.device("default.qubit", wires=4) - spy = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @@ -178,13 +147,10 @@ def circuit(): expected = np.einsum("ijkl->jl", expected).flatten() assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - - def test_marginal_prob_more_wires(self, init_state, mocker, tol): + def test_marginal_prob_more_wires(self, init_state, tol): """Test that the correct marginal probability is returned, when the states_to_binary method is used for probability computations.""" dev = qml.device("default.qubit", wires=4) - spy_probs = mocker.spy(qml.QubitDevice, "probability") state = init_state(4) @qml.qnode(dev) @@ -198,8 +164,6 @@ def circuit(): expected = np.einsum("ijkl->jil", expected).flatten() assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy_probs) - @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["numpy", "jax", "torch", "tensorflow"]) @pytest.mark.parametrize( @@ -242,10 +206,9 @@ def test_process_state_batched(self, interface, subset_wires, expected): assert subset_probs.shape == qml.math.shape(expected) assert qml.math.allclose(subset_probs, expected) - def test_integration(self, tol, mocker): + def test_integration(self, tol): """Test the probability is correct for a known state preparation.""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(): @@ -260,14 +223,11 @@ def circuit(): expected = np.array([0.5, 0.5, 0, 0]) assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("shots", [100, [1, 10, 100]]) - def test_integration_analytic_false(self, tol, mocker, shots): + def test_integration_analytic_false(self, tol, shots): """Test the probability is correct for a known state preparation when the analytic attribute is set to False.""" dev = qml.device("default.qubit", wires=3, shots=shots) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(): @@ -278,13 +238,10 @@ def circuit(): expected = np.array([0, 0, 0, 0, 1, 0, 0, 0]) assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("shots", [None, 100]) - def test_batch_size(self, mocker, shots): + def test_batch_size(self, shots): """Test the probability is correct for a batched input.""" dev = qml.device("default.qubit", wires=1, shots=shots) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(x): @@ -296,15 +253,12 @@ def circuit(x): expected = [[1.0, 0.0], [0.5, 0.5]] assert np.allclose(res, expected, atol=0.1, rtol=0.1) - custom_measurement_process(dev, spy) - @pytest.mark.autograd - def test_numerical_analytic_diff_agree(self, tol, mocker): + def test_numerical_analytic_diff_agree(self, tol): """Test that the finite difference and parameter shift rule provide the same Jacobian.""" w = 4 dev = qml.device("default.qubit", wires=w) - spy = mocker.spy(qml.QubitDevice, "probability") def circuit(x, y, z): for i in range(w): @@ -334,13 +288,10 @@ def circuit(x, y, z): # Check that they agree up to numeric tolerance assert all(np.allclose(_rF, _rA, atol=tol, rtol=0) for _rF, _rA in zip(res_F, res_A)) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param_one_qubit(self, hermitian, tol, mocker): + def test_prob_generalize_param_one_qubit(self, hermitian, tol): """Test that the correct probability is returned.""" dev = qml.device("default.qubit", wires=1) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(x): @@ -361,13 +312,10 @@ def circuit_rotated(x): assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param(self, hermitian, tol, mocker): + def test_prob_generalize_param(self, hermitian, tol): """Test that the correct probability is returned.""" dev = qml.device("default.qubit", wires=3) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(x, y): @@ -393,13 +341,10 @@ def circuit_rotated(x, y): expected = np.einsum("ijk->i", expected).flatten() assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param_multiple(self, hermitian, tol, mocker): + def test_prob_generalize_param_multiple(self, hermitian, tol): """Test that the correct probability is returned.""" dev = qml.device("default.qubit", wires=3) - spy = mocker.spy(qml.QubitDevice, "probability") @qml.qnode(dev) def circuit(x, y): @@ -436,15 +381,13 @@ def circuit_rotated(x, y): assert np.allclose(res[1], expected_1, atol=tol, rtol=0) assert np.allclose(res[2], expected_2, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) @pytest.mark.parametrize("wire", [0, 1, 2, 3]) - def test_prob_generalize_initial_state(self, hermitian, wire, init_state, tol, mocker): + def test_prob_generalize_initial_state(self, hermitian, wire, init_state, tol): """Test that the correct probability is returned.""" # pylint:disable=too-many-arguments dev = qml.device("default.qubit", wires=4) - spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) @qml.qnode(dev) @@ -480,15 +423,13 @@ def circuit_rotated(): assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("operation", [qml.PauliX, qml.PauliY, qml.Hadamard]) @pytest.mark.parametrize("wire", [0, 1, 2, 3]) - def test_operation_prob(self, operation, wire, init_state, tol, mocker): + def test_operation_prob(self, operation, wire, init_state, tol): "Test the rotated probability with different wires and rotating operations." # pylint:disable=too-many-arguments dev = qml.device("default.qubit", wires=4) - spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) @qml.qnode(dev) @@ -524,13 +465,11 @@ def circuit_rotated(): assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("observable", [(qml.PauliX, qml.PauliY)]) - def test_observable_tensor_prob(self, observable, init_state, tol, mocker): + def test_observable_tensor_prob(self, observable, init_state, tol): "Test the rotated probability with a tensor observable." dev = qml.device("default.qubit", wires=4) - spy = mocker.spy(qml.QubitDevice, "probability") + state = init_state(4) @qml.qnode(dev) @@ -560,8 +499,6 @@ def circuit_rotated(): assert np.allclose(res, expected, atol=tol, rtol=0) - custom_measurement_process(dev, spy) - @pytest.mark.parametrize("coeffs, obs", [([1, 1], [qml.PauliX(wires=0), qml.PauliX(wires=1)])]) def test_hamiltonian_error(self, coeffs, obs, init_state): "Test that an error is returned for hamiltonians." @@ -661,7 +598,8 @@ def test_estimate_probability_with_binsize_with_broadcasting(self, wires, expect assert np.allclose(res, expected) - def test_non_commuting_probs_raises_error(self): + 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) @qml.qnode(dev) @@ -669,12 +607,10 @@ def circuit(x, y): qml.RX(x, wires=[0]) qml.RY(y, wires=[1]) qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliX(0)), qml.probs(wires=[0, 1]) + return qml.expval(qml.PauliX(1)), qml.probs(wires=[0, 1]) - with pytest.raises( - qml.QuantumFunctionError, match="Only observables that are qubit-wise commuting" - ): - circuit(1, 2) + res = circuit(1, 2) + assert isinstance(res, tuple) and len(res) == 2 def test_commuting_probs_in_computational_basis(self): """Test that `qml.probs` can be used in the computational basis with other commuting observables.""" diff --git a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py index 18b9d3f5ad3..dba5d5c640b 100644 --- a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py @@ -22,37 +22,14 @@ # pylint: disable=protected-access, no-member -# TODO: Remove this when new CustomMP are the default -def custom_measurement_process(device, spy): - assert len(spy.call_args_list) > 0 # make sure method is mocked properly - - samples = device._samples - call_args_list = list(spy.call_args_list) - for call_args in call_args_list: - meas = call_args.args[1] - shot_range, bin_size = (call_args.kwargs["shot_range"], call_args.kwargs["bin_size"]) - if isinstance(meas, Operator): - meas = qml.sample(op=meas) - assert qml.math.allequal( - device.sample(call_args.args[1], **call_args.kwargs), - meas.process_samples( - samples=samples, - wire_order=device.wires, - shot_range=shot_range, - bin_size=bin_size, - ), - ) - - class TestSample: """Tests for the sample function""" @pytest.mark.parametrize("n_sample", (1, 10)) - def test_sample_dimension(self, mocker, n_sample): + def test_sample_dimension(self, n_sample): """Test that the sample function outputs samples of the right size""" dev = qml.device("default.qubit", wires=2, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -69,15 +46,12 @@ def circuit(): (n_sample,) if not n_sample == 1 else () ) - custom_measurement_process(dev, spy) - @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") - def test_sample_combination(self, mocker): + def test_sample_combination(self): """Test the output of combining expval, var and sample""" n_sample = 10 dev = qml.device("default.qubit", wires=3, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -90,17 +64,14 @@ def circuit(): assert len(result) == 3 assert np.array_equal(result[0].shape, (n_sample,)) assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == (n_sample,) - assert isinstance(result[1], np.ndarray) - assert isinstance(result[2], np.ndarray) + assert isinstance(result[1], np.float64) + assert isinstance(result[2], np.float64) - custom_measurement_process(dev, spy) - - def test_single_wire_sample(self, mocker): + def test_single_wire_sample(self): """Test the return type and shape of sampling a single wire""" n_sample = 10 dev = qml.device("default.qubit", wires=1, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -113,15 +84,12 @@ def circuit(): assert np.array_equal(result.shape, (n_sample,)) assert circuit._qfunc_output.shape(dev, Shots(n_sample)) == (n_sample,) - custom_measurement_process(dev, spy) - - def test_multi_wire_sample_regular_shape(self, mocker): + def test_multi_wire_sample_regular_shape(self): """Test the return type and shape of sampling multiple wires where a rectangular array is expected""" n_sample = 10 dev = qml.device("default.qubit", wires=3, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -138,16 +106,13 @@ def circuit(): assert len(result) == 3 assert result[0].dtype == np.dtype("int") - custom_measurement_process(dev, spy) - @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") - def test_sample_output_type_in_combination(self, mocker): + def test_sample_output_type_in_combination(self): """Test the return type and shape of sampling multiple works in combination with expvals and vars""" n_sample = 10 dev = qml.device("default.qubit", wires=3, shots=n_sample) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev, diff_method="parameter-shift") def circuit(): @@ -162,13 +127,10 @@ def circuit(): assert result[2].dtype == np.dtype("int") assert np.array_equal(result[2].shape, (n_sample,)) - custom_measurement_process(dev, spy) - - def test_not_an_observable(self, mocker): + def test_not_an_observable(self): """Test that a UserWarning is raised if the provided argument might not be hermitian.""" dev = qml.device("default.qubit", wires=2, shots=10) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -178,13 +140,10 @@ def circuit(): with pytest.warns(UserWarning, match="Prod might not be hermitian."): _ = circuit() - custom_measurement_process(dev, spy) - - def test_observable_return_type_is_sample(self, mocker): + def test_observable_return_type_is_sample(self): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`""" n_shots = 10 dev = qml.device("default.qubit", wires=1, shots=n_shots) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -194,8 +153,6 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - def test_providing_observable_and_wires(self): """Test that a ValueError is raised if both an observable is provided and wires are specified""" dev = qml.device("default.qubit", wires=2) @@ -212,10 +169,9 @@ def circuit(): ): _ = circuit() - def test_providing_no_observable_and_no_wires(self, mocker): + def test_providing_no_observable_and_no_wires(self): """Test that we can provide no observable and no wires to sample function""" dev = qml.device("default.qubit", wires=2, shots=1000) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -227,9 +183,7 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - - def test_providing_no_observable_and_no_wires_shot_vector(self, mocker): + def test_providing_no_observable_and_no_wires_shot_vector(self): """Test that we can provide no observable and no wires to sample function when using a shot vector""" num_wires = 2 @@ -238,7 +192,6 @@ def test_providing_no_observable_and_no_wires_shot_vector(self, mocker): shots2 = 10 shots3 = 1000 dev = qml.device("default.qubit", wires=num_wires, shots=[shots1, shots2, shots3]) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -260,14 +213,11 @@ def circuit(): assert np.all(res[1][:, 0] == res[1][:, 1]) assert np.all(res[2][:, 0] == res[2][:, 1]) - custom_measurement_process(dev, spy) - - def test_providing_no_observable_and_wires(self, mocker): + def test_providing_no_observable_and_wires(self): """Test that we can provide no observable but specify wires to the sample function""" wires = [0, 2] wires_obj = qml.wires.Wires(wires) dev = qml.device("default.qubit", wires=3, shots=1000) - spy = mocker.spy(qml.QubitDevice, "sample") @qml.qnode(dev) def circuit(): @@ -280,13 +230,11 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - @pytest.mark.parametrize( "obs,exp", [ # Single observables - (None, int), # comp basis samples + (None, bool), # comp basis samples (qml.PauliX(0), int), (qml.PauliY(0), int), (qml.PauliZ(0), int), @@ -398,6 +346,7 @@ def test_sample_no_arguments(self, shots): @qml.qnode(dev) def circuit(): + qml.Identity(wires=list(range(3))) return qml.sample() res = circuit() diff --git a/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py index 5198c77ecaa..fddd47d9f3a 100644 --- a/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py @@ -105,18 +105,21 @@ class TestState: """Tests for the state function""" @pytest.mark.parametrize("wires", range(2, 5)) - def test_state_shape_and_dtype(self, wires): + @pytest.mark.parametrize("op,dtype", [(qml.PauliX, np.float64), (qml.PauliY, np.complex128)]) + def test_state_shape_and_dtype(self, op, dtype, 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(): + qml.Identity(wires=list(range(wires))) + op(0) return state() state_val = func() assert state_val.shape == (2**wires,) - assert state_val.dtype == np.complex128 + assert state_val.dtype == dtype def test_return_type_is_state(self): """Test that the return type of the observable is State""" @@ -148,14 +151,11 @@ def func(): state_val = func() assert np.allclose(np.sum(np.abs(state_val) ** 2), 1) - # pylint: disable=unsubscriptable-object assert np.allclose(state_val[0], 1 / np.sqrt(2)) assert np.allclose(state_val[-1], 1 / np.sqrt(2)) - assert np.allclose(state().process_state(state=dev.state, wire_order=dev.wires), state_val) - - def test_return_with_other_types(self): - """Test that an exception is raised when a state is returned along with another return + def test_return_with_other_types_works(self): + """Test that no exception is raised when a state is returned along with another return type""" dev = qml.device("default.qubit", wires=2) @@ -165,16 +165,14 @@ def func(): qml.Hadamard(wires=0) return state(), expval(qml.PauliZ(1)) - with pytest.raises( - qml.QuantumFunctionError, - match="The state or density matrix cannot be returned in combination with other return types", - ): - func() + res = func() + assert isinstance(res, tuple) + assert np.allclose(res[0], np.array([1, 0, 1, 0]) / np.sqrt(2)) + assert np.isclose(res[1], 1) @pytest.mark.parametrize("wires", range(2, 5)) - def test_state_equal_to_dev_state(self, wires): - """Test that the returned state is equal to the one stored in dev.state for a template - circuit""" + def test_state_equal_to_expected_state(self, wires): + """Test that the returned state is equal to the expected state for a template circuit""" dev = qml.device("default.qubit", wires=wires) @@ -188,10 +186,14 @@ def func(): return state() state_val = func() - assert np.allclose(state_val, func.device.state) + scripts, _, _ = dev.preprocess(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 - def test_interface_tf(self): + @pytest.mark.parametrize("op", [qml.PauliX, qml.PauliY]) + def test_interface_tf(self, op): """Test that the state correctly outputs in the tensorflow interface""" import tensorflow as tf @@ -199,6 +201,8 @@ def test_interface_tf(self): @qml.qnode(dev, interface="tf") def func(): + op(0) + op(0) for i in range(4): qml.Hadamard(i) return state() @@ -207,12 +211,13 @@ def func(): state_val = func() assert isinstance(state_val, tf.Tensor) - assert state_val.dtype == tf.complex128 + assert state_val.dtype == tf.complex128 if op is qml.PauliY else tf.float64 assert np.allclose(state_expected, state_val.numpy()) assert state_val.shape == (16,) @pytest.mark.torch - def test_interface_torch(self): + @pytest.mark.parametrize("op", [qml.PauliX, qml.PauliY]) + def test_interface_torch(self, op): """Test that the state correctly outputs in the torch interface""" import torch @@ -220,15 +225,18 @@ def test_interface_torch(self): @qml.qnode(dev, interface="torch") def func(): + op(0) + op(0) for i in range(4): qml.Hadamard(i) return state() - state_expected = 0.25 * torch.ones(16, dtype=torch.complex128) + dtype = torch.complex128 if op is qml.PauliY else torch.float64 + state_expected = 0.25 * torch.ones(16, dtype=dtype) state_val = func() assert isinstance(state_val, torch.Tensor) - assert state_val.dtype == torch.complex128 + assert state_val.dtype == dtype assert torch.allclose(state_expected, state_val) assert state_val.shape == (16,) @@ -257,7 +265,7 @@ def func(x): def test_no_state_capability(self, monkeypatch): """Test if an error is raised for devices that are not capable of returning the state. This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) capabilities = dev.capabilities().copy() capabilities["returns_state"] = False @@ -299,7 +307,6 @@ def func(): state_expected = 0.25 * np.ones(16) assert np.allclose(state_val, state_expected) - assert np.allclose(state_val, dev.state) @pytest.mark.tf @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) @@ -319,7 +326,6 @@ def func(): state_expected = 0.25 * np.ones(16) assert np.allclose(state_val, state_expected) - assert np.allclose(state_val, dev.state) @pytest.mark.autograd @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) @@ -339,7 +345,6 @@ def func(): state_expected = 0.25 * np.ones(16) assert np.allclose(state_val, state_expected) - assert np.allclose(state_val, dev.state) @pytest.mark.tf def test_gradient_with_passthru_tf(self): @@ -430,27 +435,27 @@ class TestDensityMatrix: # pylint: disable=too-many-public-methods @pytest.mark.parametrize("wires", range(2, 5)) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_density_matrix_shape_and_dtype(self, dev_name, wires): + @pytest.mark.parametrize("op,dtype", [(qml.PauliX, np.float64), (qml.PauliY, np.complex128)]) + def test_density_matrix_shape_and_dtype(self, op, dtype, wires): """Test that the density matrix is of correct size and dtype for a trivial circuit""" - dev = qml.device(dev_name, wires=wires) + dev = qml.device("default.qubit", wires=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 == np.complex128 + assert state_val.dtype == dtype - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_return_type_is_state(self, dev_name): + def test_return_type_is_state(self): """Test that the return type of the observable is State""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -463,11 +468,10 @@ def func(): assert obs[0].return_type is State @pytest.mark.torch - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_torch(self, dev_name, diff_method): + def test_correct_density_matrix_torch(self, diff_method): """Test that the correct density matrix is returned using torch interface.""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev, interface="torch", diff_method=diff_method) def func(): @@ -478,20 +482,11 @@ 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_mat) - dev = func.device - - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), - ) - @pytest.mark.jax - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_jax(self, dev_name, diff_method): + def test_correct_density_matrix_jax(self, diff_method): """Test that the correct density matrix is returned using JAX interface.""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev, interface="jax", diff_method=diff_method) def func(): @@ -503,18 +498,11 @@ def func(): assert np.allclose(expected, density_mat) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), - ) - @pytest.mark.tf - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_tf(self, dev_name, diff_method): + def test_correct_density_matrix_tf(self, diff_method): """Test that the correct density matrix is returned using the TensorFlow interface.""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev, interface="tf", diff_method=diff_method) def func(): @@ -526,18 +514,11 @@ def func(): assert np.allclose(expected, density_mat) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_product_state_first(self, dev_name): + def test_correct_density_matrix_product_state_first(self): """Test that the correct density matrix is returned when tracing out a product state""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -550,18 +531,11 @@ def func(): assert np.allclose(expected, density_first) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=0).process_state(state=dev.state, wire_order=dev.wires), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_product_state_second(self, dev_name): + def test_correct_density_matrix_product_state_second(self): """Test that the correct density matrix is returned when tracing out a product state""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -573,19 +547,12 @@ 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) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=1).process_state(state=dev.state, wire_order=dev.wires), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) @pytest.mark.parametrize("return_wire_order", ([0, 1], [1, 0])) - def test_correct_density_matrix_product_state_both(self, dev_name, return_wire_order): + def test_correct_density_matrix_product_state_both(self, return_wire_order): """Test that the correct density matrix is returned for a full product state on two wires.""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -600,20 +567,11 @@ def func(): assert np.allclose(expected, density_both) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=return_wire_order).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_three_wires_first_two(self, dev_name): + def test_correct_density_matrix_three_wires_first_two(self): """Test that the correct density matrix is returned for an example with three wires, and tracing out the third wire.""" - dev = qml.device(dev_name, wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def func(): @@ -632,20 +590,11 @@ def func(): ) assert np.allclose(expected, density_full) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=[0, 1]).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_three_wires_last_two(self, dev_name): + def test_correct_density_matrix_three_wires_last_two(self): """Test that the correct density matrix is returned for an example with three wires, and tracing out the first wire.""" - dev = qml.device(dev_name, wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def func(): @@ -668,23 +617,14 @@ def func(): assert np.allclose(expected, density) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=[1, 2]).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) @pytest.mark.parametrize( "return_wire_order", ([0], [1], [2], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2, 0], [2, 1, 0]) ) - def test_correct_density_matrix_three_wires_product(self, dev_name, return_wire_order): + def test_correct_density_matrix_three_wires_product(self, return_wire_order): """Test that the correct density matrix is returned for an example with three wires and a product state, tracing out various combinations.""" - dev = qml.device(dev_name, wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def func(): @@ -708,19 +648,10 @@ def func(): expected = np.outer(exp_statevector.conj(), exp_statevector) assert np.allclose(expected, density_full) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=return_wire_order).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_mixed_state(self, dev_name): + def test_correct_density_matrix_mixed_state(self): """Test that the correct density matrix for an example with a mixed state""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -732,11 +663,10 @@ def func(): assert np.allclose(np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]), density) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_correct_density_matrix_all_wires(self, dev_name): + def test_correct_density_matrix_all_wires(self): """Test that the correct density matrix is returned when all wires are given""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): @@ -756,38 +686,26 @@ def func(): assert np.allclose(expected, density) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=[0, 1]).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_return_with_other_types(self, dev_name): - """Test that an exception is raised when a state is returned along with another return + def test_return_with_other_types_works(self): + """Test that no exception is raised when a state is returned along with another return type""" - dev = qml.device(dev_name, wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def func(): qml.Hadamard(wires=0) return density_matrix(0), expval(qml.PauliZ(1)) - with pytest.raises( - qml.QuantumFunctionError, - match="The state or density matrix" - " cannot be returned in combination" - " with other return types", - ): - func() + res = func() + assert isinstance(res, tuple) + assert np.allclose(res[0], np.ones((2, 2)) / 2) + assert np.isclose(res[1], 1) def test_no_state_capability(self, monkeypatch): """Test if an error is raised for devices that are not capable of returning the density matrix. This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) capabilities = dev.capabilities().copy() capabilities["returns_state"] = False @@ -816,12 +734,11 @@ def func(): func() @pytest.mark.parametrize("wires", [[0, 2], ["a", -1]]) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_custom_wire_labels(self, wires, dev_name): + def test_custom_wire_labels(self, wires): """Test that the correct density matrix for an example with a mixed state when using custom wires""" - dev = qml.device(dev_name, wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def func(): @@ -834,20 +751,11 @@ def func(): assert np.allclose(expected, density) - if dev_name != "default.mixed": - assert np.allclose( - expected, - qml.density_matrix(wires=wires[1]).process_state( - state=dev.state, wire_order=dev.wires - ), - ) - @pytest.mark.parametrize("wires", [[3, 1], ["b", 1000]]) - @pytest.mark.parametrize("dev_name", ["default.qubit", "default.mixed"]) - def test_custom_wire_labels_all_wires(self, wires, dev_name): + def test_custom_wire_labels_all_wires(self, wires): """Test that the correct density matrix for an example with a mixed state when using custom wires""" - dev = qml.device(dev_name, wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def func(): diff --git a/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py index 191e6937cfa..d377f7a2e1a 100644 --- a/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py @@ -19,41 +19,13 @@ from pennylane.measurements import Variance, Shots -# TODO: Remove this when new CustomMP are the default -def custom_measurement_process(device, spy): - assert len(spy.call_args_list) > 0 # make sure method is mocked properly - - # pylint: disable=protected-access - samples = device._samples - state = device._state - call_args_list = list(spy.call_args_list) - for call_args in call_args_list: - obs = call_args.args[1] - shot_range, bin_size = ( - call_args.kwargs["shot_range"], - call_args.kwargs["bin_size"], - ) - meas = qml.var(op=obs) - old_res = device.var(obs, shot_range, bin_size) - if samples is not None: - new_res = meas.process_samples( - samples=samples, wire_order=device.wires, shot_range=shot_range, bin_size=bin_size - ) - else: - new_res = meas.process_state(state=state, wire_order=device.wires) - assert qml.math.allclose(old_res, new_res) - - class TestVar: """Tests for the var function""" @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) - @pytest.mark.parametrize("r_dtype", [np.float32, np.float64]) - def test_value(self, tol, r_dtype, mocker, shots): + def test_value(self, tol, shots): """Test that the var function works""" dev = qml.device("default.qubit", wires=2, shots=shots) - spy = mocker.spy(qml.QubitDevice, "var") - dev.R_DTYPE = r_dtype @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): @@ -67,20 +39,17 @@ def circuit(x): rtol = 0 if shots is None else 0.05 assert np.allclose(res, expected, atol=atol, rtol=rtol) - # pylint: disable=no-member, unsubscriptable-object + r_dtype = np.float64 if isinstance(res, tuple): assert res[0].dtype == r_dtype assert res[1].dtype == r_dtype else: assert res.dtype == r_dtype - custom_measurement_process(dev, spy) - - def test_not_an_observable(self, mocker): + def test_not_an_observable(self): """Test that a UserWarning is raised if the provided argument might not be hermitian.""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) def circuit(): @@ -90,12 +59,9 @@ def circuit(): with pytest.warns(UserWarning, match="Prod might not be hermitian."): _ = circuit() - custom_measurement_process(dev, spy) - - def test_observable_return_type_is_variance(self, mocker): + def test_observable_return_type_is_variance(self): """Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`""" dev = qml.device("default.qubit", wires=2) - spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) def circuit(): @@ -105,8 +71,6 @@ def circuit(): circuit() - custom_measurement_process(dev, spy) - @pytest.mark.parametrize( "obs", [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], @@ -141,10 +105,9 @@ def test_shape_shot_vector(self, obs): @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) - def test_projector_var(self, state, shots, mocker): + def test_projector_var(self, state, shots): """Tests that the variance of a ``Projector`` object is computed correctly.""" dev = qml.device("default.qubit", wires=3, shots=shots) - spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) def circuit(): @@ -156,9 +119,7 @@ def circuit(): assert np.allclose(res, expected, atol=0.02, rtol=0.02) - custom_measurement_process(dev, spy) - - def test_permuted_wires(self, mocker): + def test_permuted_wires(self): """Test that the variance of an operator with permuted wires is the same.""" obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) obs_2 = qml.prod( @@ -166,7 +127,6 @@ def test_permuted_wires(self, mocker): ) dev = qml.device("default.qubit", wires=["h", 8, 10]) - spy = mocker.spy(qml.QubitDevice, "var") @qml.qnode(dev) def circuit(): @@ -181,4 +141,3 @@ def circuit2(): return qml.var(obs_2) assert circuit() == circuit2() - custom_measurement_process(dev, spy) diff --git a/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py index d9551f3b34a..c494073d777 100644 --- a/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py @@ -18,7 +18,6 @@ import pytest import pennylane as qml -from pennylane.interfaces import INTERFACE_MAP from pennylane.measurements import VnEntropy, Shots from pennylane.measurements.vn_entropy import VnEntropyMP from pennylane.wires import Wires @@ -83,14 +82,7 @@ def circuit(): qml.StatePrep(state_vector, wires=[0, 1]) return qml.vn_entropy(wires=0) - res = circuit() - new_res = qml.vn_entropy(wires=0).process_state( - state=circuit.device.state, wire_order=circuit.device.wires - ) - assert qml.math.allclose(res, expected) - assert qml.math.allclose(new_res, expected) - assert INTERFACE_MAP.get(qml.math.get_interface(new_res)) == interface - assert res.dtype == new_res.dtype + assert qml.math.allclose(circuit(), expected) def test_queue(self): """Test that the right measurement class is queued.""" @@ -145,9 +137,10 @@ class TestIntegration: devices = ["default.qubit", "default.mixed"] diff_methods = ["backprop", "finite-diff"] - def test_shot_vec_error(self): + @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.""" - dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit", wires=2, shots=shots) @qml.qnode(device=dev) def circuit(x): @@ -155,9 +148,7 @@ def circuit(x): qml.CRX(x, wires=[0, 1]) return qml.vn_entropy(wires=[0]) - with pytest.raises( - NotImplementedError, match="Von Neumann entropy is not supported with shot vectors" - ): + with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): circuit(0.5) @pytest.mark.parametrize("wires", single_wires_list) @@ -401,19 +392,14 @@ def circuit_entropy(x): assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=1e-05) - @pytest.mark.parametrize("device", devices) - def test_qnode_entropy_no_custom_wires(self, device): - """Test that entropy cannot be returned with custom wires.""" + def test_qnode_entropy_custom_wires(self): + """Test that entropy can be returned with custom wires.""" - dev = qml.device(device, wires=["a", 1]) + dev = qml.device("default.qubit", wires=["a", 1]) @qml.qnode(dev) def circuit_entropy(x): qml.IsingXX(x, wires=["a", 1]) return qml.vn_entropy(wires=["a"]) - with pytest.raises( - qml.QuantumFunctionError, - match="Returning the Von Neumann entropy is not supported when using custom wire labels", - ): - circuit_entropy(0.1) + assert np.isclose(circuit_entropy(0.1), expected_entropy_ising_xx(0.1)) From 6e5cafd9fd376e5d32355619b4bf90bf80cd20c4 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 22 Aug 2023 10:41:46 -0400 Subject: [PATCH 23/78] put back legacy qubit device test; copy batch test to DQ2 --- .../experimental/test_default_qubit_2.py | 50 +++++++++++ tests/test_qubit_device.py | 82 +++++++++---------- 2 files changed, 90 insertions(+), 42 deletions(-) diff --git a/tests/devices/experimental/test_default_qubit_2.py b/tests/devices/experimental/test_default_qubit_2.py index 40f7ad7b655..e2163b86965 100644 --- a/tests/devices/experimental/test_default_qubit_2.py +++ b/tests/devices/experimental/test_default_qubit_2.py @@ -185,6 +185,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: diff --git a/tests/test_qubit_device.py b/tests/test_qubit_device.py index 41e9c280064..edea9cf4a83 100644 --- a/tests/test_qubit_device.py +++ b/tests/test_qubit_device.py @@ -607,7 +607,8 @@ def test_non_analytic_expval(self, mock_qubit_device_with_original_statistics, m m.setattr("numpy.mean", lambda obs, axis=None: obs) res = dev.expval(obs) - assert res == obs + with pytest.warns(UserWarning, match="The behaviour of operator"): + assert res == obs def test_no_eigval_error(self, mock_qubit_device_with_original_statistics): """Tests that an error is thrown if expval is called with an observable that does @@ -687,7 +688,8 @@ def test_non_analytic_var(self, mock_qubit_device_with_original_statistics, monk m.setattr("numpy.var", lambda obs, axis=None: obs) res = dev.var(obs) - assert res == obs + with pytest.warns(UserWarning, match="The behaviour of operator"): + assert res == obs def test_no_eigval_error(self, mock_qubit_device_with_original_statistics): """Tests that an error is thrown if var is called with an observable that does not have eigenvalues defined.""" @@ -1146,9 +1148,9 @@ class TestExecution: def test_device_executions(self): """Test the number of times a qubit device is executed over a QNode's - lifetime is tracked by the device's tracker""" + lifetime is tracked by `num_executions`""" - dev_1 = qml.device("default.qubit", wires=2) + dev_1 = qml.device("default.qubit.legacy", wires=2) def circuit_1(x, y): qml.RX(x, wires=[0]) @@ -1159,13 +1161,12 @@ def circuit_1(x, y): 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, 0.12) - assert tracker1.totals["executions"] == num_evals_1 + for _ in range(num_evals_1): + node_1(0.432, 0.12) + assert dev_1.num_executions == num_evals_1 # test a second instance of a default qubit device - dev_2 = qml.device("default.qubit", wires=2) + dev_2 = qml.device("default.qubit.legacy", wires=2) def circuit_2(x): qml.RX(x, wires=[0]) @@ -1175,10 +1176,9 @@ def circuit_2(x): 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(0.432) - assert tracker2.totals["executions"] == num_evals_2 + for _ in range(num_evals_2): + node_2(0.432) + assert dev_2.num_executions == num_evals_2 # test a new circuit on an existing instance of a qubit device def circuit_3(y): @@ -1189,10 +1189,9 @@ def circuit_3(y): node_3 = qml.QNode(circuit_3, dev_1) num_evals_3 = 7 - with tracker1: - for _ in range(num_evals_3): - node_3(0.12) - assert tracker1.totals["executions"] == num_evals_1 + num_evals_3 + for _ in range(num_evals_3): + node_3(0.12) + assert dev_1.num_executions == num_evals_1 + num_evals_3 # pylint: disable=protected-access def test_get_diagonalizing_gates(self, mock_qubit_device): @@ -1210,9 +1209,9 @@ class TestExecutionBroadcasted: def test_device_executions(self): """Test the number of times a qubit device is executed over a QNode's - lifetime is tracked by the device's tracker.""" + lifetime is tracked by `num_executions`""" - dev_1 = qml.device("default.qubit", wires=2) + dev_1 = qml.device("default.qubit.legacy", wires=2) def circuit_1(x, y): qml.RX(x, wires=[0]) @@ -1223,13 +1222,14 @@ def circuit_1(x, y): 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 + for _ in range(num_evals_1): + node_1(0.432, np.array([0.12, 0.5, 3.2])) + assert dev_1.num_executions == num_evals_1 # test a second instance of a default qubit device - dev_2 = qml.device("default.qubit", wires=2) + dev_2 = qml.device("default.qubit.legacy", wires=2) + + assert dev_2.num_executions == 0 def circuit_2(x, y): qml.RX(x, wires=[0]) @@ -1239,10 +1239,9 @@ def circuit_2(x, y): 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]), 0.12) - assert tracker2.totals["executions"] == num_evals_2 + for _ in range(num_evals_2): + node_2(np.array([0.432, 0.61, 8.2]), 0.12) + assert dev_2.num_executions == num_evals_2 # test a new circuit on an existing instance of a qubit device def circuit_3(x, y): @@ -1253,10 +1252,9 @@ def circuit_3(x, y): 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.432, 0.2]), np.array([0.12, 1.214])) - assert tracker1.totals["executions"] == num_evals_1 + num_evals_3 + for _ in range(num_evals_3): + node_3(np.array([0.432, 0.2]), np.array([0.12, 1.214])) + assert dev_1.num_executions == num_evals_1 + num_evals_3 class TestBatchExecution: @@ -1396,7 +1394,7 @@ class TestResourcesTracker: ) # Resources(wires, gates, gate_types, gate_sizes, depth, shots) devices = ( - "default.qubit", + "default.qubit.legacy", "default.qubit.autograd", "default.qubit.jax", "default.qubit.torch", @@ -1411,7 +1409,6 @@ class TestResourcesTracker: def test_tracker_single_execution(self, dev_name, qs_shots_wires, expected_resource): """Test that the tracker accurately tracks resources in a single execution""" qs, shots, wires = qs_shots_wires - qs._shots = Shots(shots) dev = qml.device(dev_name, shots=shots, wires=wires) with qml.Tracker(dev) as tracker: @@ -1421,20 +1418,21 @@ def test_tracker_single_execution(self, dev_name, qs_shots_wires, expected_resou assert tracker.history["resources"][0] == expected_resource @pytest.mark.all_interfaces - def test_tracker_multi_execution(self): + @pytest.mark.parametrize("dev_name", devices) + def test_tracker_multi_execution(self, dev_name): """Test that the tracker accurately tracks resources for multi executions""" - qs1 = qml.tape.QuantumScript([qml.Hadamard(0), qml.CNOT([0, 1])], shots=10) - qs2 = qml.tape.QuantumScript([qml.PauliZ(0), qml.CNOT([0, 1]), qml.RX(1.23, 2)], shots=10) + qs1 = qml.tape.QuantumScript([qml.Hadamard(0), qml.CNOT([0, 1])]) + qs2 = qml.tape.QuantumScript([qml.PauliZ(0), qml.CNOT([0, 1]), qml.RX(1.23, 2)]) exp_res1 = Resources(2, 2, {"Hadamard": 1, "CNOT": 1}, {1: 1, 2: 1}, 2, Shots(10)) exp_res2 = Resources(3, 3, {"PauliZ": 1, "CNOT": 1, "RX": 1}, {1: 2, 2: 1}, 2, Shots(10)) - dev = qml.device("default.qubit", wires=[0, 1, 2]) + dev = qml.device(dev_name, shots=10, wires=[0, 1, 2]) with qml.Tracker(dev) as tracker: - dev.execute([qs1]) - dev.execute([qs1, qs2]) + dev.batch_execute([qs1]) + dev.batch_execute([qs1, qs2]) - assert tracker.totals == {"batches": 2, "executions": 3} + assert tracker.totals == {"batches": 2, "executions": 3, "shots": 30, "batch_len": 3} assert len(tracker.history["resources"]) == 3 # 1 per qscript execution for tracked_r, expected_r in zip( @@ -1445,7 +1443,7 @@ def test_tracker_multi_execution(self): @pytest.mark.all_interfaces def test_tracker_grad(self): """Test that the tracker can track resources through a gradient computation""" - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) @qml.qnode(dev, diff_method="parameter-shift") def circuit(x): From a60911c11b4c09e5bd0b157e3bac3f27de4160ef Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 22 Aug 2023 18:06:34 -0400 Subject: [PATCH 24/78] fix classical shadow tests; change ci to use legacy --- .github/workflows/interface-unit-tests.yml | 4 +- .../test_classical_shadow_default_qubit_2.py | 96 ++++++------------- 2 files changed, 29 insertions(+), 71 deletions(-) diff --git a/.github/workflows/interface-unit-tests.yml b/.github/workflows/interface-unit-tests.yml index c0f46c8f6e7..da17ed6a143 100644 --- a/.github/workflows/interface-unit-tests.yml +++ b/.github/workflows/interface-unit-tests.yml @@ -283,9 +283,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/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py index 8b523526b40..2e020cfc597 100644 --- a/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py @@ -23,21 +23,15 @@ from pennylane.measurements import ClassicalShadowMP, Shots from pennylane.measurements.classical_shadow import ShadowExpvalMP -# pylint: disable=dangerous-default-value, too-many-arguments, comparison-with-callable, no-member +# pylint: disable=dangerous-default-value, too-many-arguments -def get_circuit(wires, shots, seed_recipes, interface="autograd", device="default.qubit"): +def get_circuit(wires, shots, seed_recipes, interface="autograd"): """ Return a QNode that prepares the state (|00...0> + |11...1>) / sqrt(2) and performs the classical shadow measurement """ - if device is not None: - dev = qml.device(device, wires=wires, shots=shots) - else: - dev = qml.device("default.qubit", wires=wires, shots=shots) - - # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) - dev.classical_shadow = super(type(dev), dev).classical_shadow + dev = qml.device("default.qubit", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(): @@ -51,17 +45,11 @@ def circuit(): return circuit -def get_x_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_x_basis_circuit(wires, shots, interface="autograd"): """ Return a QNode that prepares the |++..+> state and performs a classical shadow measurement """ - if device is not None: - dev = qml.device(device, wires=wires, shots=shots) - else: - dev = qml.device("default.qubit", wires=wires, shots=shots) - - # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) - dev.classical_shadow = super(type(dev), dev).classical_shadow + dev = qml.device("default.qubit", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(): @@ -72,17 +60,11 @@ def circuit(): return circuit -def get_y_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_y_basis_circuit(wires, shots, interface="autograd"): """ Return a QNode that prepares the |+i>|+i>...|+i> state and performs a classical shadow measurement """ - if device is not None: - dev = qml.device(device, wires=wires, shots=shots) - else: - dev = qml.device("default.qubit", wires=wires, shots=shots) - - # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) - dev.classical_shadow = super(type(dev), dev).classical_shadow + dev = qml.device("default.qubit", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(): @@ -94,17 +76,11 @@ def circuit(): return circuit -def get_z_basis_circuit(wires, shots, interface="autograd", device="default.qubit"): +def get_z_basis_circuit(wires, shots, interface="autograd"): """ Return a QNode that prepares the |00..0> state and performs a classical shadow measurement """ - if device is not None: - dev = qml.device(device, wires=wires, shots=shots) - else: - dev = qml.device("default.qubit", wires=wires, shots=shots) - - # make the device call the superclass method to switch between the general qubit device and device specific implementations (i.e. for default qubit) - dev.classical_shadow = super(type(dev), dev).classical_shadow + dev = qml.device("default.qubit", wires=wires, shots=shots) @qml.qnode(dev, interface=interface) def circuit(): @@ -304,14 +280,13 @@ def test_measurement_process_copy(self, wires, seed): @pytest.mark.parametrize("shots", shots_list) @pytest.mark.parametrize("seed", seed_recipes_list) @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", None]) - def test_format(self, wires, shots, seed, interface, device): + def test_format(self, wires, shots, seed, interface): """Test that the format of the returned classical shadow measurement is correct""" import tensorflow as tf import torch - circuit = get_circuit(wires, shots, seed, interface, device) + circuit = get_circuit(wires, shots, seed, interface) shadow = circuit() # test shape is correct @@ -334,56 +309,44 @@ def test_format(self, wires, shots, seed, interface, device): @pytest.mark.all_interfaces @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize("device", ["default.qubit", None]) @pytest.mark.parametrize( "circuit_fn, basis_recipe", [(get_x_basis_circuit, 0), (get_y_basis_circuit, 1), (get_z_basis_circuit, 2)], ) - def test_return_distribution(self, wires, interface, device, circuit_fn, basis_recipe): + def test_return_distribution(self, wires, interface, circuit_fn, basis_recipe): """Test that the distribution of the bits and recipes are correct for a circuit that prepares all qubits in a Pauli basis""" # high number of shots to prevent true negatives np.random.seed(42) shots = 1000 - circuit = circuit_fn(wires, shots=shots, interface=interface, device=device) + circuit = circuit_fn(wires, shots=shots, interface=interface) bits, recipes = circuit() - new_bits, new_recipes = circuit.tape.measurements[0].process(circuit.tape, circuit.device) # test that the recipes follow a rough uniform distribution ratios = np.unique(recipes, return_counts=True)[1] / (wires * shots) assert np.allclose(ratios, 1 / 3, atol=1e-1) - new_ratios = np.unique(new_recipes, return_counts=True)[1] / (wires * shots) - assert np.allclose(new_ratios, 1 / 3, atol=1e-1) # test that the bit is 0 for all X measurements assert qml.math.allequal(bits[recipes == basis_recipe], 0) - assert qml.math.allequal(new_bits[new_recipes == basis_recipe], 0) # test that the bits are uniformly distributed for all Y and Z measurements bits1 = bits[recipes == (basis_recipe + 1) % 3] ratios1 = np.unique(bits1, return_counts=True)[1] / bits1.shape[0] assert np.allclose(ratios1, 1 / 2, atol=1e-1) - new_bits1 = new_bits[new_recipes == (basis_recipe + 1) % 3] - new_ratios1 = np.unique(new_bits1, return_counts=True)[1] / new_bits1.shape[0] - assert np.allclose(new_ratios1, 1 / 2, atol=1e-1) bits2 = bits[recipes == (basis_recipe + 2) % 3] ratios2 = np.unique(bits2, return_counts=True)[1] / bits2.shape[0] assert np.allclose(ratios2, 1 / 2, atol=1e-1) - new_bits2 = new_bits[new_recipes == (basis_recipe + 2) % 3] - new_ratios2 = np.unique(new_bits2, return_counts=True)[1] / new_bits2.shape[0] - assert np.allclose(new_ratios2, 1 / 2, atol=1e-1) - @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 to obtain classical shadows""" circuit = get_circuit(wires, None, seed) - msg = "The number of shots has to be explicitly set on the device when using sample-based measurements" - with pytest.raises(qml.QuantumFunctionError, match=msg): + msg = "Analytic circuits must only contain StateMeasurements" + with pytest.raises(qml.DeviceError, match=msg): circuit() @pytest.mark.parametrize("shots", shots_list) @@ -401,9 +364,10 @@ def circuit(): return qml.classical_shadow(wires=range(wires)), 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() + res = circuit() + assert isinstance(res, tuple) and len(res) == 2 + assert qml.math.shape(res[0]) == (2, shots, wires) + assert qml.math.shape(res[1]) == () def hadamard_circuit(wires, shots=10000, interface="autograd"): @@ -497,14 +461,14 @@ def test_shots_none_error(self): circuit = hadamard_circuit(2, None) H = qml.PauliZ(0) - msg = "The number of shots has to be explicitly set on the device when using sample-based measurements" - with pytest.raises(qml.QuantumFunctionError, match=msg): + msg = "Analytic circuits must only contain StateMeasurements" + with pytest.raises(qml.DeviceError, match=msg): _ = circuit(H, k=10) - def test_multi_measurement_error(self): - """Test that an error is raised when classical shadows is returned + def test_multi_measurement_allowed(self): + """Test that no error is raised when classical shadows is returned with other measurement processes""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit", wires=2, shots=10000) @qml.qnode(dev) def circuit(): @@ -512,9 +476,9 @@ def circuit(): qml.CNOT(wires=[0, 1]) return qml.shadow_expval(qml.PauliZ(0)), 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() + res = circuit() + assert isinstance(res, tuple) + assert qml.math.allclose(res, 0, atol=0.05) def test_obs_not_queued(self): """Test that the observable passed to qml.shadow_expval is not queued""" @@ -587,12 +551,10 @@ def test_hadamard_expval(self, k=1, obs=obs_hadamard, expected=expected_hadamard superposition of qubits""" circuit = hadamard_circuit(3, shots=100000) actual = circuit(obs, k=k) - new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) assert actual.shape == (len(obs_hadamard),) assert actual.dtype == np.float64 assert qml.math.allclose(actual, expected, atol=1e-1) - assert qml.math.allclose(new_actual, expected, atol=1e-1) def test_max_entangled_expval( self, k=1, obs=obs_max_entangled, expected=expected_max_entangled @@ -601,12 +563,10 @@ def test_max_entangled_expval( entangled state""" circuit = max_entangled_circuit(3, shots=100000) actual = circuit(obs, k=k) - new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) assert actual.shape == (len(obs_max_entangled),) assert actual.dtype == np.float64 assert qml.math.allclose(actual, expected, atol=1e-1) - assert qml.math.allclose(new_actual, expected, atol=1e-1) def test_non_pauli_error(self): """Test that an error is raised when a non-Pauli observable is passed""" @@ -627,12 +587,10 @@ def test_qft_expval(self, interface, k=1, obs=obs_qft, expected=expected_qft): circuit = qft_circuit(3, shots=100000, interface=interface) actual = circuit(obs, k=k) - new_actual = circuit.tape.measurements[0].process(circuit.tape, circuit.device) assert actual.shape == (len(obs_qft),) assert actual.dtype == torch.float64 if interface == "torch" else np.float64 assert qml.math.allclose(actual, expected, atol=1e-1) - assert qml.math.allclose(new_actual, expected, atol=1e-1) obs_strongly_entangled = [ From 29ba4f44c39d24e219b5ce745e19e49809e7f53b Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 23 Aug 2023 13:21:17 -0400 Subject: [PATCH 25/78] fix some tests; drawer support for dq2 --- pennylane/drawer/draw.py | 53 ++++++++++++------- .../core/test_hamiltonian_gradient.py | 2 - .../core/test_pulse_generator_gradient.py | 2 +- tests/measurements/test_sample.py | 2 +- tests/shadow/test_shadow_transforms.py | 9 ++-- .../test_approx_time_evolution.py | 2 +- tests/test_device.py | 2 +- 7 files changed, 42 insertions(+), 30 deletions(-) diff --git a/pennylane/drawer/draw.py b/pennylane/drawer/draw.py index 13ce6c2b544..379916b0886 100644 --- a/pennylane/drawer/draw.py +++ b/pennylane/drawer/draw.py @@ -240,15 +240,22 @@ def _draw_qnode( ): @wraps(qnode) def wrapper(*args, **kwargs): - original_expansion_strategy = getattr(qnode, "expansion_strategy", None) - - try: - qnode.expansion_strategy = expansion_strategy or original_expansion_strategy - tapes = qnode.construct(args, kwargs) - finally: - qnode.expansion_strategy = original_expansion_strategy - - _wire_order = wire_order or getattr(qnode.device, "wires", None) + if expansion_strategy == "device" and isinstance( + qnode.device, qml.devices.experimental.Device + ): + qnode.construct(args, kwargs) + tapes = qnode.device.preprocess(qnode.tape) + _wire_order = wire_order or qnode.tape.wires + else: + original_expansion_strategy = getattr(qnode, "expansion_strategy", None) + + try: + qnode.expansion_strategy = expansion_strategy or original_expansion_strategy + tapes = qnode.construct(args, kwargs) + finally: + qnode.expansion_strategy = original_expansion_strategy + + _wire_order = wire_order or qnode.device.wires if tapes is not None: cache = {"tape_offset": 0, "matrices": []} @@ -535,18 +542,26 @@ def _draw_mpl_qnode( ): @wraps(qnode) def wrapper(*args, **kwargs_qnode): - original_expansion_strategy = getattr(qnode, "expansion_strategy", None) - - try: - qnode.expansion_strategy = expansion_strategy or original_expansion_strategy - qnode.construct(args, kwargs_qnode) - finally: - qnode.expansion_strategy = original_expansion_strategy - - _wire_order = wire_order or getattr(qnode.device, "wires", None) + if expansion_strategy == "device" and isinstance( + qnode.device, qml.devices.experimental.Device + ): + qnode.construct(args, kwargs) + tape = qnode.device.preprocess(qnode.tape)[0][0] + _wire_order = wire_order or qnode.tape.wires + else: + original_expansion_strategy = getattr(qnode, "expansion_strategy", None) + + try: + qnode.expansion_strategy = expansion_strategy or original_expansion_strategy + qnode.construct(args, kwargs_qnode) + finally: + qnode.expansion_strategy = original_expansion_strategy + + tape = qnode.tape + _wire_order = wire_order or qnode.device.wires return tape_mpl( - qnode.qtape, + tape, wire_order=_wire_order, show_all_wires=show_all_wires, decimals=decimals, diff --git a/tests/gradients/core/test_hamiltonian_gradient.py b/tests/gradients/core/test_hamiltonian_gradient.py index 738eecc5fc7..1bcb4bfc4fe 100644 --- a/tests/gradients/core/test_hamiltonian_gradient.py +++ b/tests/gradients/core/test_hamiltonian_gradient.py @@ -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_pulse_generator_gradient.py b/tests/gradients/core/test_pulse_generator_gradient.py index 9cee7f7cae3..2426ba114a7 100644 --- a/tests/gradients/core/test_pulse_generator_gradient.py +++ b/tests/gradients/core/test_pulse_generator_gradient.py @@ -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) diff --git a/tests/measurements/test_sample.py b/tests/measurements/test_sample.py index 5f38ef29ec8..24d3f794158 100644 --- a/tests/measurements/test_sample.py +++ b/tests/measurements/test_sample.py @@ -286,7 +286,7 @@ def circuit(): "obs,exp", [ # Single observables - (None, int), # comp basis samples + (None, bool), # comp basis samples (qml.PauliX(0), int), (qml.PauliY(0), int), (qml.PauliZ(0), int), diff --git a/tests/shadow/test_shadow_transforms.py b/tests/shadow/test_shadow_transforms.py index f021ce21e3c..277b4d857ee 100644 --- a/tests/shadow/test_shadow_transforms.py +++ b/tests/shadow/test_shadow_transforms.py @@ -174,9 +174,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(): @@ -184,8 +183,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/templates/test_subroutines/test_approx_time_evolution.py b/tests/templates/test_subroutines/test_approx_time_evolution.py index 18e2c585f8a..5bb5f055b06 100644 --- a/tests/templates/test_subroutines/test_approx_time_evolution.py +++ b/tests/templates/test_subroutines/test_approx_time_evolution.py @@ -410,7 +410,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/test_device.py b/tests/test_device.py index e1ae87149c1..7a7f303fea3 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -589,7 +589,7 @@ def test_default_expand_with_initial_state(self, op, decomp): prep = [op] ops = [qml.AngleEmbedding(features=[0.1], wires=[0], rotation="Z"), op, qml.PauliZ(wires=2)] - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) tape = qml.tape.QuantumTape(ops=ops, measurements=[], prep=prep, shots=100) new_tape = dev.default_expand_fn(tape) From 15c68d7fa51d7e17fb46a1478b9ee5ecdb076cef Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 24 Aug 2023 10:01:12 -0400 Subject: [PATCH 26/78] device setup changes --- pennylane/__init__.py | 4 +++- pennylane/devices/default_qubit.py | 4 ++-- pennylane/devices/experimental/default_qubit_2.py | 3 --- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pennylane/__init__.py b/pennylane/__init__.py index 39bccfbd256..e0c6fee6dcf 100644 --- a/pennylane/__init__.py +++ b/pennylane/__init__.py @@ -336,7 +336,9 @@ def run_cnot(): # loads the device class plugin_device_class = plugin_devices[name].load() - if Version(version()) not in SimpleSpec(plugin_device_class.pennylane_requires): + if hasattr(plugin_device_class, "pennylane_requires") and Version( + version() + ) not in SimpleSpec(plugin_device_class.pennylane_requires): raise DeviceError( f"The {name} plugin requires PennyLane versions {plugin_device_class.pennylane_requires}, " f"however PennyLane version {__version__} is installed." diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py index c71eb5c3263..e81c0a1cb92 100644 --- a/pennylane/devices/default_qubit.py +++ b/pennylane/devices/default_qubit.py @@ -103,8 +103,8 @@ class DefaultQubit(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/experimental/default_qubit_2.py b/pennylane/devices/experimental/default_qubit_2.py index 838ef2c6fc8..375d384999a 100644 --- a/pennylane/devices/experimental/default_qubit_2.py +++ b/pennylane/devices/experimental/default_qubit_2.py @@ -24,7 +24,6 @@ from pennylane.tape import QuantumTape, QuantumScript from pennylane.typing import Result, ResultBatch from pennylane.transforms import convert_to_numpy_parameters -from pennylane._version import __version__ from pennylane import DeviceError, Snapshot from . import Device @@ -136,8 +135,6 @@ def f(x): """ - pennylane_requires = __version__ - @property def name(self): """The name of the device.""" From 16e438125294e9274a0cdf05f83e83e4e28e94c5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 24 Aug 2023 22:58:12 -0400 Subject: [PATCH 27/78] more test changes --- .../finite_diff/test_spsa_gradient.py | 2 +- .../test_parameter_shift_cv.py | 54 +++++++++---------- tests/ops/qubit/test_special_unitary.py | 6 +-- tests/optimize/test_optimize_shot_adaptive.py | 32 +++++------ tests/qchem/test_hamiltonians.py | 4 +- tests/qnn/conftest.py | 4 +- tests/qnn/test_keras.py | 4 +- tests/qnn/test_qnn_torch.py | 6 +-- tests/shadow/test_shadow_entropies.py | 3 +- tests/tape/test_qscript.py | 2 +- tests/tape/test_tape.py | 2 +- .../test_subroutines/test_permute.py | 21 ++++---- tests/templates/test_subroutines/test_qft.py | 5 +- tests/templates/test_subroutines/test_qpe.py | 20 ++++--- .../test_single_excitation.py | 11 ++-- .../templates/test_subroutines/test_uccsd.py | 6 +-- tests/transforms/test_specs.py | 2 +- 17 files changed, 94 insertions(+), 90 deletions(-) diff --git a/tests/gradients/finite_diff/test_spsa_gradient.py b/tests/gradients/finite_diff/test_spsa_gradient.py index cf1b0a93e8d..3fc08ce3b13 100644 --- a/tests/gradients/finite_diff/test_spsa_gradient.py +++ b/tests/gradients/finite_diff/test_spsa_gradient.py @@ -79,7 +79,7 @@ def test_same_seeds(self): num = 5 rng = np.random.default_rng(42) first_direction = _rademacher_sampler(ids, num, rng=rng) - np.random.seed = 0 # Setting the global seed should have no effect. + np.random.seed(0) # Setting the global seed should have no effect. rng = np.random.default_rng(42) second_direction = _rademacher_sampler(ids, num, rng=rng) assert np.allclose(first_direction, second_direction) diff --git a/tests/gradients/parameter_shift/test_parameter_shift_cv.py b/tests/gradients/parameter_shift/test_parameter_shift_cv.py index 23f0910ecbf..1c622a61133 100644 --- a/tests/gradients/parameter_shift/test_parameter_shift_cv.py +++ b/tests/gradients/parameter_shift/test_parameter_shift_cv.py @@ -530,7 +530,7 @@ def test_independent_parameters_analytic(self): # (first order, so 2 executions) assert len(tapes) == 2 - res = fn(dev.execute(tapes)) + res = fn(dev.batch_execute(tapes)) assert np.allclose(res, [0, 2]) tape.trainable_params = {0, 2} @@ -540,7 +540,7 @@ def test_independent_parameters_analytic(self): # (second order, so 0 executions) assert len(tapes) == 0 - res = fn(dev.execute(tapes)) + res = fn(dev.batch_execute(tapes)) assert np.allclose(res, [0, 2]) def test_all_independent(self): @@ -557,7 +557,7 @@ def test_all_independent(self): tapes, fn = qml.gradients.param_shift_cv(tape, dev) assert len(tapes) == 0 - grad = fn(dev.execute(tapes)) + grad = fn(dev.batch_execute(tapes)) assert np.allclose(grad, [0, 0]) @@ -587,11 +587,11 @@ def test_rotation_gradient(self, gradient_recipes, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev, gradient_recipes=gradient_recipes) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, gradient_recipes=gradient_recipes, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) spy2.assert_called() expected = -hbar * alpha * np.sin(theta) @@ -616,11 +616,11 @@ def test_beamsplitter_gradient(self, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) spy2.assert_called() expected = -hbar * alpha * np.sin(theta) @@ -644,11 +644,11 @@ def test_displacement_gradient(self, mocker, tol): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) spy2.assert_called() expected = [hbar * np.cos(phi), -hbar * r * np.sin(phi)] @@ -690,11 +690,11 @@ class Rotation(qml.operation.CVOperation): spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) spy2.assert_not_called() tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) spy2.assert_called() expected = -np.exp(-r) * hbar * alpha @@ -719,7 +719,7 @@ def test_squeezed_number_state_gradient(self, mocker, tol): spy = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.execute(tapes)) + grad = fn(dev.batch_execute(tapes)) assert tape._par_info[0]["grad_method"] == "F" spy.assert_not_called() @@ -743,7 +743,7 @@ def test_multiple_squeezing_gradient(self, mocker, tol): tape = qml.tape.QuantumScript.from_queue(q) spy2 = mocker.spy(qml.gradients.parameter_shift_cv, "second_order_param_shift") tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) spy2.assert_called() # check against the known analytic formula @@ -806,10 +806,10 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): tape.trainable_params = set(range(2, 2 + op.num_params)) tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.execute(tapes)) + grad_F = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) # check that every parameter is analytic for i in range(op.num_params): @@ -819,7 +819,7 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): if obs.ev_order == 1: tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) assert np.allclose(grad_A, grad_F, atol=tol, rtol=0) @pytest.mark.parametrize("t", [0, 1]) @@ -882,13 +882,13 @@ def test_interferometer_unitary(self, t, tol): dev = qml.device("default.gaussian", wires=2) tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.execute(tapes)) + grad_F = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) assert tape._par_info[0]["grad_method"] == "A" assert tape._par_info[1]["grad_method"] == "A" @@ -923,10 +923,10 @@ def test_first_order_observable(self, tol): # circuit jacobians tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.execute(tapes)) + grad_F = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) expected = np.array( [ @@ -960,7 +960,7 @@ def test_second_order_cv(self, tol): # circuit jacobians tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.execute(tapes)) + grad_F = fn(dev.batch_execute(tapes)) expected = np.array([[2 * a**2 + 2 * n + 1, 2 * a * (2 * n + 1)]]) assert np.allclose(grad_F, expected, atol=tol, rtol=0) @@ -1063,13 +1063,13 @@ def test_gradients_gaussian_circuit(self, op, obs, tol): # jacobians must match tapes, fn = qml.gradients.finite_diff(tape) - grad_F = fn(dev.execute(tapes)) + grad_F = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev) - grad_A = fn(dev.execute(tapes)) + grad_A = fn(dev.batch_execute(tapes)) tapes, fn = param_shift_cv(tape, dev, force_order2=True) - grad_A2 = fn(dev.execute(tapes)) + grad_A2 = fn(dev.batch_execute(tapes)) assert np.allclose(grad_A2, grad_F, atol=tol, rtol=0) assert np.allclose(grad_A, grad_F, atol=tol, rtol=0) @@ -1094,7 +1094,7 @@ def test_squeezed_mean_photon_variance(self, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 2} tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.execute(tapes)) + grad = fn(dev.batch_execute(tapes)) expected = np.array( [ 2 * np.exp(2 * r) * np.sin(phi) ** 2 - 2 * np.exp(-2 * r) * np.cos(phi) ** 2, @@ -1118,7 +1118,7 @@ def test_displaced_thermal_mean_photon_variance(self, tol): tape = qml.tape.QuantumScript.from_queue(q) tape.trainable_params = {0, 1} tapes, fn = param_shift_cv(tape, dev) - grad = fn(dev.execute(tapes)) + grad = fn(dev.batch_execute(tapes)) expected = np.array([2 * a**2 + 2 * n + 1, 2 * a * (2 * n + 1)]) assert np.allclose(grad, expected, atol=tol, rtol=0) diff --git a/tests/ops/qubit/test_special_unitary.py b/tests/ops/qubit/test_special_unitary.py index ab2a05f7870..89c54509c34 100644 --- a/tests/ops/qubit/test_special_unitary.py +++ b/tests/ops/qubit/test_special_unitary.py @@ -806,7 +806,7 @@ def test_qnode_jax(self, shots, atol, use_jit): jax.config.update("jax_enable_x64", True) - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) diff_method = "backprop" if shots is None else "parameter-shift" qnode = qml.QNode(self.circuit, dev, interface="jax", diff_method=diff_method) if use_jit: @@ -843,7 +843,7 @@ def test_qnode_torch(self, shots, atol): argument controls whether autodiff or parameter-shift gradients are used.""" import torch - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) diff_method = "backprop" if shots is None else "parameter-shift" qnode = qml.QNode(self.circuit, dev, interface="torch", diff_method=diff_method) @@ -875,7 +875,7 @@ def test_qnode_tf(self, shots, atol): argument controls whether autodiff or parameter-shift gradients are used.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2, shots=shots) + dev = qml.device("default.qubit.legacy", wires=2, shots=shots) diff_method = "backprop" if shots is None else "parameter-shift" qnode = qml.QNode(self.circuit, dev, interface="tf", diff_method=diff_method) diff --git a/tests/optimize/test_optimize_shot_adaptive.py b/tests/optimize/test_optimize_shot_adaptive.py index 125bef5de33..c0d2902761a 100644 --- a/tests/optimize/test_optimize_shot_adaptive.py +++ b/tests/optimize/test_optimize_shot_adaptive.py @@ -34,7 +34,7 @@ class TestExceptions: def test_analytic_device_error(self): """Test that an exception is raised if an analytic device is used""" H = qml.Hamiltonian([0.3, 0.1], [qml.PauliX(0), qml.PauliZ(0)]) - dev = qml.device("default.qubit", wires=1, shots=None) + dev = qml.device("default.qubit.legacy", wires=1, shots=None) def ansatz(x): qml.RX(x, wires=0) @@ -58,7 +58,7 @@ def test_learning_error(self): lipschitz bound""" coeffs = [0.3, 0.1] H = qml.Hamiltonian(coeffs, [qml.PauliX(0), qml.PauliZ(0)]) - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) def ansatz(x, **kwargs): qml.RX(x, wires=0) @@ -84,7 +84,7 @@ def ansatz(x, **kwargs): def test_unknown_objective_function(self): """Test that an exception is raised if an unknown objective function is passed""" - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) @qml.qnode(dev) def circuit(x): @@ -130,7 +130,7 @@ class TestSingleShotGradientIntegration: """Integration tests to ensure that the single shot gradient is correctly computed for a variety of argument types.""" - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) H = qml.Hamiltonian([1.0], [qml.PauliZ(0)]) expval_cost = catch_warn_ExpvalCost(ansatz0, H, dev) @@ -271,7 +271,7 @@ def test_single_array_argument_step(self, cost_fn, mocker, monkeypatch): assert np.allclose(grad[0][0, 1], np.mean(single_shot_grads[0][:5, 0, 1])) assert np.allclose(grad_variance[0][0, 1], np.var(single_shot_grads[0][:5, 0, 1], ddof=1)) - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) expval_cost = catch_warn_ExpvalCost(ansatz2, H, dev) qnode = expval_cost.qnodes[0] @@ -359,7 +359,7 @@ def test_multiple_argument_step(self, mocker, monkeypatch): """Test that a simple QNode with multiple scalar arguments correctly performs an optimization step, and that the single-shot gradients generated have the correct shape""" # pylint: disable=protected-access - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) @qml.qnode(dev) def circuit(x, y): @@ -416,7 +416,7 @@ def test_multiple_array_argument_step(self, mocker, monkeypatch): """Test that a simple QNode with multiple array arguments correctly performs an optimization step, and that the single-shot gradients generated have the correct shape""" # pylint: disable=protected-access - dev = qml.device("default.qubit", wires=1, shots=100) + dev = qml.device("default.qubit.legacy", wires=1, shots=100) @qml.qnode(dev) def circuit(x, y): @@ -510,7 +510,7 @@ def test_wrs_expval_cost(self, mocker): """Checks that cost functions that are expval costs can make use of weighted random sampling""" coeffs = [0.2, 0.1] - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) H = qml.Hamiltonian(coeffs, [qml.PauliZ(0), qml.PauliZ(0) @ qml.PauliZ(1)]) expval_cost = catch_warn_ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev) @@ -530,7 +530,7 @@ def test_wrs_disabled(self, mocker): """Checks that cost functions that are expval costs can disable use of weighted random sampling""" coeffs = [0.2, 0.1] - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) H = qml.Hamiltonian(coeffs, [qml.PauliZ(0), qml.PauliZ(0) @ qml.PauliZ(1)]) expval_cost = catch_warn_ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev) @@ -545,7 +545,7 @@ def test_wrs_disabled(self, mocker): def test_unknown_term_sampling_method(self): """Checks that an exception is raised if the term sampling method is unknown""" coeffs = [0.2, 0.1] - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) H = qml.Hamiltonian(coeffs, [qml.PauliZ(0), qml.PauliZ(0) @ qml.PauliZ(1)]) expval_cost = catch_warn_ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev) @@ -560,7 +560,7 @@ def test_zero_shots(self, mocker): """Test that, if the shot budget for a single term is 0, that the jacobian computation is skipped""" coeffs = [0.2, 0.1, 0.1] - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) H = qml.Hamiltonian(coeffs, [qml.PauliZ(0), qml.PauliX(1), qml.PauliZ(0) @ qml.PauliZ(1)]) expval_cost = catch_warn_ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev) @@ -581,7 +581,7 @@ def test_single_shots(self, mocker): """Test that, if the shot budget for a single term is 1, that the number of dimensions for the returned Jacobian is expanded""" coeffs = [0.2, 0.1, 0.1] - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) H = qml.Hamiltonian(coeffs, [qml.PauliZ(0), qml.PauliX(1), qml.PauliZ(0) @ qml.PauliZ(1)]) expval_cost = catch_warn_ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev) @@ -606,7 +606,7 @@ class TestOptimization: def test_multi_qubit_rotation(self): """Test that multiple qubit rotation can be optimized""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) @qml.qnode(dev) def circuit(x): @@ -635,7 +635,7 @@ def circuit(x): @pytest.mark.slow def test_vqe_optimization(self): """Test that a simple VQE circuit can be optimized""" - dev = qml.device("default.qubit", wires=2, shots=100) + dev = qml.device("default.qubit.legacy", wires=2, shots=100) coeffs = [0.1, 0.2] obs = [qml.PauliZ(0), qml.PauliX(0)] H = qml.Hamiltonian(coeffs, obs) @@ -674,7 +674,7 @@ def test_qnode_cost(self, tol): when using a QNode as the cost function""" np.random.seed(0) - dev = qml.device("default.qubit", wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) @qml.qnode(dev, cache=False) def circuit(x): @@ -696,7 +696,7 @@ def test_expval_cost(self, tol): """Test that the cost is correctly returned when using a QNode as the cost function""" np.random.seed(0) - dev = qml.device("default.qubit", wires=1, shots=10) + dev = qml.device("default.qubit.legacy", wires=1, shots=10) def ansatz(x, **kwargs): qml.RX(x[0], wires=0) diff --git a/tests/qchem/test_hamiltonians.py b/tests/qchem/test_hamiltonians.py index d608630df2d..8600cfdfd9e 100644 --- a/tests/qchem/test_hamiltonians.py +++ b/tests/qchem/test_hamiltonians.py @@ -403,7 +403,7 @@ def test_gradient_expvalH(fs): 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) @@ -455,7 +455,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/qnn/conftest.py b/tests/qnn/conftest.py index 8fb292a10ac..858a5819c26 100644 --- a/tests/qnn/conftest.py +++ b/tests/qnn/conftest.py @@ -24,7 +24,7 @@ def get_circuit(n_qubits, output_dim, interface): """Fixture for getting a sample quantum circuit with a controllable qubit number and output dimension. Returns both the circuit and the shape of the weights.""" - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), @@ -60,7 +60,7 @@ def get_circuit_dm(n_qubits, output_dim, interface): dimension for density matrix return type. Returns both the circuit and the shape of the weights. """ - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), diff --git a/tests/qnn/test_keras.py b/tests/qnn/test_keras.py index f8261f3af8f..84900c42e81 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.2" diff --git a/tests/qnn/test_qnn_torch.py b/tests/qnn/test_qnn_torch.py index 46d6a4ec662..26add50d37c 100644 --- a/tests/qnn/test_qnn_torch.py +++ b/tests/qnn/test_qnn_torch.py @@ -663,8 +663,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) @@ -846,7 +844,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.2" 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/tape/test_qscript.py b/tests/tape/test_qscript.py index 112fe3305f9..f81b5f2e9d6 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -1399,7 +1399,7 @@ def test_sample_int_eigvals(self, ret, dtype): # Double-check the domain of the QNode output assert np.issubdtype(result.dtype, dtype) - assert qs.numeric_type is int + assert np.issubdtype(dtype, qs.numeric_type) # TODO: add cases for each interface once qml.Hermitian supports other # interfaces diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index b55262eb1cb..6112ef6b898 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -2438,7 +2438,7 @@ def circuit(): # Double-check the domain of the QNode output assert np.issubdtype(result.dtype, dtype) - assert circuit.qtape.numeric_type is int + assert circuit.qtape.numeric_type is dtype # TODO: add cases for each interface once qml.Hermitian supports other # interfaces 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..06354012851 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(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(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(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(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..e9bbca83147 100644 --- a/tests/templates/test_subroutines/test_uccsd.py +++ b/tests/templates/test_subroutines/test_uccsd.py @@ -150,8 +150,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = [0.1, 0.2] - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -213,7 +213,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/transforms/test_specs.py b/tests/transforms/test_specs.py index 375d409baaf..5c6e6f7fe65 100644 --- a/tests/transforms/test_specs.py +++ b/tests/transforms/test_specs.py @@ -92,7 +92,7 @@ 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 From 440b697ecd2d43f932478776a0874a042ff37419 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 12:08:39 -0400 Subject: [PATCH 28/78] map wires for pulse stuff; more test fixes --- pennylane/pulse/parametrized_evolution.py | 5 +++++ pennylane/pulse/parametrized_hamiltonian.py | 20 +++++++++++++++++++ tests/devices/test_lightning_qubit.py | 2 +- tests/pulse/test_hardware_hamiltonian.py | 6 +++--- tests/templates/test_embeddings/test_basis.py | 3 ++- .../test_subroutines/test_basis_rotation.py | 2 +- 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/pennylane/pulse/parametrized_evolution.py b/pennylane/pulse/parametrized_evolution.py index 838a878dbe6..f9322ea29d6 100644 --- a/pennylane/pulse/parametrized_evolution.py +++ b/pennylane/pulse/parametrized_evolution.py @@ -452,6 +452,11 @@ def _check_time_batching(self): # subtract an additional 1 because the full time evolution is not being returned. self._batch_size = self.t.shape[0] + def map_wires(self, wire_map): + mapped_op = super().map_wires(wire_map) + mapped_op.H = self.H.map_wires(wire_map) + return mapped_op + @property def hash(self): """int: Integer hash that uniquely represents the operator.""" diff --git a/pennylane/pulse/parametrized_hamiltonian.py b/pennylane/pulse/parametrized_hamiltonian.py index 1326897ce2c..7ec4dcf99c5 100644 --- a/pennylane/pulse/parametrized_hamiltonian.py +++ b/pennylane/pulse/parametrized_hamiltonian.py @@ -15,6 +15,8 @@ """ This submodule contains the ParametrizedHamiltonian class """ +from copy import copy + import pennylane as qml from pennylane.operation import Operator from pennylane.ops.qubit.hamiltonian import Hamiltonian @@ -256,6 +258,24 @@ def __repr__(self): return " " + "\n+ ".join(terms) + def map_wires(self, wire_map): + """Returns a copy of the current ParametrizedHamiltonian with its wires changed according + to the given wire map. + + Args: + wire_map (dict): dictionary containing the old wires as keys and the new wires as values + + Returns: + .ParametrizedHamiltonian: A new instance with mapped wires + """ + new_ph = copy(self) + new_ph.ops_parametrized = [op.map_wires(wire_map) for op in self.ops_parametrized] + new_ph.ops_fixed = [op.map_wires(wire_map) for op in self.ops_fixed] + new_ph.wires = Wires.all_wires( + [op.wires for op in new_ph.ops_fixed] + [op.wires for op in new_ph.ops_parametrized] + ) + return new_ph + def H_fixed(self): """The fixed term(s) of the ``ParametrizedHamiltonian``. Returns a ``Sum`` operator of ``SProd`` operators (or a single ``SProd`` operator in the event that there is only one term in ``H_fixed``). diff --git a/tests/devices/test_lightning_qubit.py b/tests/devices/test_lightning_qubit.py index e225077ecc0..bae30e7791b 100644 --- a/tests/devices/test_lightning_qubit.py +++ b/tests/devices/test_lightning_qubit.py @@ -24,7 +24,7 @@ def test_integration(): wires = 2 layers = 2 dev_l = qml.device("lightning.qubit", wires=wires) - dev_d = qml.device("default.qubit.legacy", wires=wires) + dev_d = qml.device("default.qubit", wires=wires) def circuit(weights): qml.templates.StronglyEntanglingLayers(weights, wires=range(wires)) diff --git a/tests/pulse/test_hardware_hamiltonian.py b/tests/pulse/test_hardware_hamiltonian.py index 566c3c22e13..418d45fb0d0 100644 --- a/tests/pulse/test_hardware_hamiltonian.py +++ b/tests/pulse/test_hardware_hamiltonian.py @@ -641,7 +641,7 @@ def fa(p, t): Ht = drive(amplitude=fa, phase=0, wires=1) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) @@ -683,7 +683,7 @@ def fc(p, t): H2 = drive(amplitude=fc, phase=3 * jnp.pi, wires=4) H3 = drive(amplitude=1.0, phase=0, wires=[3, 0]) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) @@ -726,7 +726,7 @@ def fb(p, t): H_drive = drive(amplitude=fa, phase=fb, wires=1) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) diff --git a/tests/templates/test_embeddings/test_basis.py b/tests/templates/test_embeddings/test_basis.py index 974c2e2e335..39085c967ee 100644 --- a/tests/templates/test_embeddings/test_basis.py +++ b/tests/templates/test_embeddings/test_basis.py @@ -236,7 +236,8 @@ def test_jax_jit(self, tol): features = jnp.array([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + # use legacy device until qml.state is fixed + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_basis_rotation.py b/tests/templates/test_subroutines/test_basis_rotation.py index 7767dd763c6..b980ae12fbd 100644 --- a/tests/templates/test_subroutines/test_basis_rotation.py +++ b/tests/templates/test_subroutines/test_basis_rotation.py @@ -458,7 +458,7 @@ def test_tf(self, tol): ] ) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) From bdec8759133b2e80408eb1b2a9c99d20689b218e Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 12:14:48 -0400 Subject: [PATCH 29/78] temp for ci: use legacy in templates --- tests/templates/test_broadcast.py | 12 ++--- .../test_embeddings/test_amplitude.py | 46 +++++++++---------- tests/templates/test_embeddings/test_angle.py | 22 ++++----- tests/templates/test_embeddings/test_basis.py | 25 +++++----- .../templates/test_embeddings/test_iqp_emb.py | 18 ++++---- .../test_embeddings/test_qaoa_emb.py | 26 +++++------ .../test_layers/test_basic_entangler.py | 16 +++---- .../templates/test_layers/test_gate_fabric.py | 18 ++++---- .../test_particle_conserving_u1.py | 16 +++---- .../test_particle_conserving_u2.py | 16 +++---- tests/templates/test_layers/test_random.py | 14 +++--- .../test_layers/test_simplified_twodesign.py | 16 +++---- .../test_layers/test_strongly_entangling.py | 16 +++---- .../test_arbitrary_state_prep.py | 16 +++---- .../test_basis_state_prep.py | 6 +-- .../test_mottonen_state_prep.py | 16 +++---- .../test_all_singles_doubles.py | 16 +++---- .../test_approx_time_evolution.py | 24 +++++----- .../test_arbitrary_unitary.py | 16 +++---- .../test_subroutines/test_basis_rotation.py | 14 +++--- .../test_commuting_evolution.py | 12 ++--- .../test_double_excitation.py | 14 +++--- .../test_subroutines/test_flip_sign.py | 2 +- .../templates/test_subroutines/test_grover.py | 4 +- .../test_subroutines/test_kupccgsd.py | 20 ++++---- .../test_subroutines/test_permute.py | 37 ++++++++------- tests/templates/test_subroutines/test_qft.py | 9 ++-- tests/templates/test_subroutines/test_qmc.py | 8 ++-- tests/templates/test_subroutines/test_qpe.py | 30 ++++++------ tests/templates/test_subroutines/test_qsvt.py | 10 ++-- .../templates/test_subroutines/test_select.py | 10 ++-- .../test_single_excitation.py | 25 +++++----- .../templates/test_subroutines/test_uccsd.py | 14 +++--- .../templates/test_swapnetworks/test_ccl2.py | 20 ++++---- .../test_tensornetworks/test_MERA.py | 6 +-- .../templates/test_tensornetworks/test_MPS.py | 2 +- .../templates/test_tensornetworks/test_TTN.py | 6 +-- 37 files changed, 296 insertions(+), 302 deletions(-) diff --git a/tests/templates/test_broadcast.py b/tests/templates/test_broadcast.py index 69b1a8f19b5..9db921a2b6e 100644 --- a/tests/templates/test_broadcast.py +++ b/tests/templates/test_broadcast.py @@ -227,7 +227,7 @@ def test_correct_parameters_in_queue(self, pattern, n_wires, gate, parameters): def test_prepares_correct_state(self, pattern, n_wires, parameters, unitary, target): """Tests the state produced by different unitaries.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -244,7 +244,7 @@ def test_throws_error_when_mismatch_params_wires(self, parameters, n_wires): """Tests that error thrown when 'parameters' does not contain one set of parameters for each wire.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -258,7 +258,7 @@ def test_throws_special_error_for_ring_pattern_2_wires(self): """Tests that the special error is thrown when 'parameters' does not contain one sequence of parameters for a two-wire ring pattern.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(pars): @@ -310,7 +310,7 @@ class TestCustomPattern: def test_reproduce_builtin_patterns(self, custom_pattern, pattern): """Tests that the custom pattern can reproduce the built in patterns.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) # qnode using custom pattern @qml.qnode(dev) @@ -338,7 +338,7 @@ def circuit2(): def test_correct_output(self, custom_pattern, expected): """Tests the output for simple cases.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def circuit(): @@ -351,7 +351,7 @@ def circuit(): def test_unknown_pattern(): """Test that an unknown pattern raises an error""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(pars): diff --git a/tests/templates/test_embeddings/test_amplitude.py b/tests/templates/test_embeddings/test_amplitude.py index 8b8d79ba1ab..6a3ecc6b462 100644 --- a/tests/templates/test_embeddings/test_amplitude.py +++ b/tests/templates/test_embeddings/test_amplitude.py @@ -74,7 +74,7 @@ def test_prepares_correct_state(self, inpt, normalize): """Checks the state for real and complex inputs.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -91,7 +91,7 @@ def test_prepares_correct_broadcasted_state(self, inpt, normalize): """Checks the state for real and complex inputs.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -107,7 +107,7 @@ def test_prepares_padded_state(self, inpt, pad): """Checks the state for real and complex padding constants.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -126,7 +126,7 @@ def test_prepares_padded_state_broadcasted(self, inpt, pad): """Checks the state for real and complex padding constants.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -142,8 +142,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.array([0, 1 / 2, 0, 1 / 2, 0, 0, 1 / 2, 1 / 2]) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -169,7 +169,7 @@ def test_throws_exception_if_not_normalized(self, inpt): """Checks exception when state is not normalized and `normalize=False`.""" not_nrmlzd = 2 * inpt n_qubits = 2 - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -185,7 +185,7 @@ def test_throws_exception_if_features_wrong_shape(self): """Checks exception if features has more than two dimensions.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -207,7 +207,7 @@ def test_throws_exception_if_fewer_features_than_amplitudes(self, inpt): no automatic padding is chosen.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -225,7 +225,7 @@ def test_throws_exception_if_more_features_than_amplitudes_padding(self, inpt): automatic padding is chosen.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -270,7 +270,7 @@ def test_amplitude_embedding_tolerance_value(self): tolerance = 10e-10 num_qubits = 5 - dev = qml.device("default.qubit", wires=num_qubits) + dev = qml.device("default.qubit.legacy", wires=num_qubits) assert np.isclose(np.sum(np.abs(inputs) ** 2), 1, tolerance) @qml.qnode(dev) @@ -315,7 +315,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol, features): """Tests common iterables as inputs.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -335,7 +335,7 @@ def test_autograd(self, tol, features): features = pnp.array(features, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -352,7 +352,7 @@ def test_autograd_pad_with(self, tol, features): features = pnp.array(features) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def node_decomposed(features): @@ -382,7 +382,7 @@ def test_jax(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -402,7 +402,7 @@ def test_jax_jit(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = jax.jit(qml.QNode(circuit_template, dev)) circuit2 = jax.jit(qml.QNode(circuit_decomposed, dev)) @@ -422,7 +422,7 @@ def test_jax_jit_pad_with(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @jax.jit @qml.qnode(dev) @@ -453,7 +453,7 @@ def test_tf(self, tol): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -471,7 +471,7 @@ def test_tf_pad_with(self, tol, features): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def node_decomposed(features): @@ -500,7 +500,7 @@ def test_tf_error_when_batching(self): features = tf.Variable(all_features[1]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) @@ -515,7 +515,7 @@ def test_tf_jit(self, tol): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = tf.function(jit_compile=True)(qml.QNode(circuit_template, dev)) circuit2 = tf.function(jit_compile=True)(qml.QNode(circuit_decomposed, dev)) @@ -534,7 +534,7 @@ def test_torch(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -552,7 +552,7 @@ def test_torch_pad_with(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def node_decomposed(features): diff --git a/tests/templates/test_embeddings/test_angle.py b/tests/templates/test_embeddings/test_angle.py index ef531695f3d..c659072f0ae 100644 --- a/tests/templates/test_embeddings/test_angle.py +++ b/tests/templates/test_embeddings/test_angle.py @@ -90,7 +90,7 @@ def test_state( """Checks the state produced using the rotation='X' strategy.""" features = [np.pi / 2, np.pi / 2, np.pi / 4, 0] - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def circuit(x=None): @@ -109,7 +109,7 @@ def test_fewer_features(self): features = [np.pi / 2, np.pi / 2, 0, np.pi / 2] - dev = qml.device("default.qubit", wires=5) + dev = qml.device("default.qubit.legacy", wires=5) @qml.qnode(dev) def circuit(x=None): @@ -124,8 +124,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.random.random(size=(3,)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -151,7 +151,7 @@ def test_exception_fewer_rotations(self): rotation gates than features.""" features = [0, 0, 1, 0] - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def circuit(x=None): @@ -165,7 +165,7 @@ def test_exception_wrongrot(self): """Verifies that exception is raised if the rotation strategy is unknown.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(x=None): @@ -206,7 +206,7 @@ def test_list_and_tuples(self, tol): features = [1.0, 1.0, 1.0] - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -225,7 +225,7 @@ def test_autograd(self, tol): features = pnp.array([1.0, 1.0, 1.0], requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -251,7 +251,7 @@ def test_jax(self, tol): features = jnp.array([1.0, 1.0, 1.0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -276,7 +276,7 @@ def test_tf(self, tol): features = tf.Variable([1.0, 1.0, 1.0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -303,7 +303,7 @@ def test_torch(self, tol): features = torch.tensor([1.0, 1.0, 1.0], requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_basis.py b/tests/templates/test_embeddings/test_basis.py index 39085c967ee..4b31d94e3c9 100644 --- a/tests/templates/test_embeddings/test_basis.py +++ b/tests/templates/test_embeddings/test_basis.py @@ -57,7 +57,7 @@ def test_state(self, state): """Checks that the correct state is prepared.""" n_qubits = 2 - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -72,8 +72,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = [1, 0, 1] - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -111,7 +111,7 @@ def test_features_as_int_conversion(self, feat, wires, expected): def test_wrong_input_bits_exception(self, x): """Checks exception if number of features is not same as number of qubits.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(): @@ -124,7 +124,7 @@ def circuit(): def test_input_not_binary_exception(self): """Checks exception if the features contain values other than zero and one.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -137,7 +137,7 @@ def circuit(x=None): def test_exception_wrong_dim(self): """Checks exception if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -173,7 +173,7 @@ def test_list_and_tuples(self, tol): """Tests common iterables as inputs.""" features = [0, 1, 0] - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -195,7 +195,7 @@ def test_autograd(self, tol): features = pnp.array([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -215,7 +215,7 @@ def test_jax(self, tol): features = jnp.array([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -236,7 +236,6 @@ def test_jax_jit(self, tol): features = jnp.array([0, 1, 0]) - # use legacy device until qml.state is fixed dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) @@ -259,7 +258,7 @@ def test_tf(self, tol): features = tf.Variable([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -279,7 +278,7 @@ def test_tf_autograph(self, tol): features = tf.Variable([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -299,7 +298,7 @@ def test_torch(self, tol): features = torch.tensor([0, 1, 0]) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_iqp_emb.py b/tests/templates/test_embeddings/test_iqp_emb.py index 5eb25401b43..603ed4aece5 100644 --- a/tests/templates/test_embeddings/test_iqp_emb.py +++ b/tests/templates/test_embeddings/test_iqp_emb.py @@ -113,8 +113,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.random.random(size=(3,)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -141,7 +141,7 @@ class TestInputs: def test_exception_wrong_number_of_features(self, features): """Verifies that an exception is raised if 'features' has the wrong trailing dimension.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def circuit(f=None): @@ -155,7 +155,7 @@ def circuit(f=None): def test_exception_wrong_ndim(self, shape): """Verifies that an exception is raised if 'features' has the wrong number of dimensions.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def circuit(f=None): @@ -207,7 +207,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol, features): """Tests common iterables as inputs.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) res = circuit(features) @@ -230,7 +230,7 @@ def test_autograd(self, tol, features): features = pnp.array(features, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -257,7 +257,7 @@ def test_jax(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -283,7 +283,7 @@ def test_tf(self, tol, features): features = tf.Variable(features) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -311,7 +311,7 @@ def test_torch(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_qaoa_emb.py b/tests/templates/test_embeddings/test_qaoa_emb.py index de49c972d67..e63ef51880f 100644 --- a/tests/templates/test_embeddings/test_qaoa_emb.py +++ b/tests/templates/test_embeddings/test_qaoa_emb.py @@ -133,7 +133,7 @@ def test_exception_wrongrot(self): n_wires = 1 weights = np.zeros(shape=(1, 1)) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -173,7 +173,7 @@ def test_output_zz(self, weights, target, tol): """Checks the output if the features and entangler weights are nonzero, which makes the circuit only depend on the ZZ gate.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -194,7 +194,7 @@ def circuit(x=None): def test_state_more_qubits_than_features(self, n_wires, features, weights, target, tol): """Checks the state is correct if there are more qubits than features.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -209,8 +209,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) features = np.random.random(size=(3,)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -263,7 +263,7 @@ def test_exception_fewer_qubits_than_features( features = [0, 0, 0, 0] n_wires = 1 weights = np.zeros(shape=(1, 2 * n_wires)) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -279,7 +279,7 @@ def test_exception_wrong_feature_shape(self, shape): n_wires = 1 weights = np.zeros(shape=(1, 1)) features = np.zeros(shape=shape) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -300,7 +300,7 @@ def circuit(): def test_exception_wrong_weight_shape(self, weights, n_wires): """Verifies that exception is raised if the shape of weights is incorrect.""" features = np.zeros(shape=(n_wires,)) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -320,7 +320,7 @@ def circuit(): def test_exception_wrong_weight_ndim(self, weights, n_wires): """Verifies that exception is raised if the shape of weights is incorrect.""" features = np.zeros(shape=(n_wires,)) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -383,7 +383,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -411,7 +411,7 @@ def test_jax(self, tol): features = jnp.array(np.random.random(size=(2,))) weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -438,7 +438,7 @@ def test_tf(self, tol): features = tf.Variable(np.random.random(size=(2,))) weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -467,7 +467,7 @@ def test_torch(self, tol): features = torch.tensor(np.random.random(size=(2,)), requires_grad=True) weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_basic_entangler.py b/tests/templates/test_layers/test_basic_entangler.py index 4c2ca6a83bf..ee0723f44b6 100644 --- a/tests/templates/test_layers/test_basic_entangler.py +++ b/tests/templates/test_layers/test_basic_entangler.py @@ -72,7 +72,7 @@ def test_rotation(self, rotation): def test_simple_target_outputs(self, weights, n_wires, target, tol): """Tests the result of the template for simple cases.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(weights): @@ -86,8 +86,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -112,7 +112,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the weights shape is incorrect.""" n_wires = 1 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(weights): @@ -175,7 +175,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -201,7 +201,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -226,7 +226,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -253,7 +253,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_gate_fabric.py b/tests/templates/test_layers/test_gate_fabric.py index 260090f79d1..d1eabd5f970 100644 --- a/tests/templates/test_layers/test_gate_fabric.py +++ b/tests/templates/test_layers/test_gate_fabric.py @@ -479,7 +479,7 @@ def test_decomposition_q(self, init_state, exp_state, tol): weight = [[[np.pi / 2, np.pi / 2]]] - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) @qml.qnode(dev) def circuit(weight): @@ -599,7 +599,7 @@ def test_layers_gate_fabric(self, num_qubits, layers, exp_state, tol): shape = qml.GateFabric.shape(n_layers=layers, n_wires=num_qubits) weight = np.pi / 2 * qml.math.ones(shape) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) init_state = qml.math.array([1 if x < num_qubits // 2 else 0 for x in wires]) @@ -617,8 +617,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 1, 2)) init_state = qml.math.array([1, 1, 0, 0]) - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "r"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "r"]) @qml.qnode(dev) def circuit(): @@ -697,7 +697,7 @@ def test_exceptions(self, weights, wires, msg_match): N = len(wires) init_state = qml.math.array([1, 1, 0, 0]) - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) @qml.qnode(dev) def circuit(): @@ -783,7 +783,7 @@ def test_autograd(self, tol): weights = pnp.random.random(size=(1, 1, 2), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -809,7 +809,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -834,7 +834,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -861,7 +861,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 1, 2)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_particle_conserving_u1.py b/tests/templates/test_layers/test_particle_conserving_u1.py index 15fd62056d3..87baee98285 100644 --- a/tests/templates/test_layers/test_particle_conserving_u1.py +++ b/tests/templates/test_layers/test_particle_conserving_u1.py @@ -128,8 +128,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 2, 2)) init_state = np.array([1, 1, 0]) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -193,7 +193,7 @@ def test_decomposition_u1ex(self, init_state, exp_state, tol): wires = range(N) weights = np.array([[[0.2045368, -0.6031732]]]) - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) @qml.qnode(dev) def circuit(weights): @@ -227,7 +227,7 @@ def test_exceptions(self, weights, n_wires, msg_match): wires = range(n_wires) init_state = np.array([1, 1, 0, 0]) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -306,7 +306,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 1, 2)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -332,7 +332,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -357,7 +357,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -384,7 +384,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 1, 2)), requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_particle_conserving_u2.py b/tests/templates/test_layers/test_particle_conserving_u2.py index 163aa458484..570489ca026 100644 --- a/tests/templates/test_layers/test_particle_conserving_u2.py +++ b/tests/templates/test_layers/test_particle_conserving_u2.py @@ -105,7 +105,7 @@ def test_decomposition_u2ex(self, init_state, exp_state, tol): weight = 0.53141 - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) @qml.qnode(dev) def circuit(weight): @@ -122,8 +122,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 5)) init_state = np.array([1, 1, 0]) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -180,7 +180,7 @@ def test_exceptions(self, weights, wires, msg_match): N = len(wires) init_state = np.array([1, 1, 0, 0]) - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) @qml.qnode(dev) def circuit(): @@ -253,7 +253,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -279,7 +279,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -304,7 +304,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -331,7 +331,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_random.py b/tests/templates/test_layers/test_random.py index 74f3bce355a..9033d3886e4 100644 --- a/tests/templates/test_layers/test_random.py +++ b/tests/templates/test_layers/test_random.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -164,7 +164,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def circuit(phi): @@ -241,7 +241,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -267,7 +267,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -292,7 +292,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -319,7 +319,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_simplified_twodesign.py b/tests/templates/test_layers/test_simplified_twodesign.py index 7d0c8edb7eb..9cddcbb3c85 100644 --- a/tests/templates/test_layers/test_simplified_twodesign.py +++ b/tests/templates/test_layers/test_simplified_twodesign.py @@ -97,7 +97,7 @@ def test_circuit_parameters(self, n_wires, n_layers, shape_weights): ) def test_correct_target_output(self, initial_layer_weights, weights, n_wires, target, tol): """Tests the result of the template for simple cases.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(initial_layer, weights): @@ -115,8 +115,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 2, 2)) initial_layer = np.random.randn(3) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -141,7 +141,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) initial_layer = np.random.randn(2) @qml.qnode(dev) @@ -222,7 +222,7 @@ def test_autograd(self, tol): initial_weights = np.random.random(size=(3,)) initial_weights = pnp.array(initial_weights, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -250,7 +250,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 2, 2))) initial_weights = jnp.array(np.random.random(size=(3,))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -277,7 +277,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 2, 2))) initial_weights = tf.Variable(np.random.random(size=(3,))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -306,7 +306,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 2, 2)), requires_grad=True) initial_weights = torch.tensor(np.random.random(size=(3,)), requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_strongly_entangling.py b/tests/templates/test_layers/test_strongly_entangling.py index 4569a724a35..2ced6729675 100644 --- a/tests/templates/test_layers/test_strongly_entangling.py +++ b/tests/templates/test_layers/test_strongly_entangling.py @@ -70,8 +70,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3, 3)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -119,7 +119,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(weights, ranges=None): @@ -142,7 +142,7 @@ def test_exception_wrong_ranges(self): """Verifies that exception is raised if the value of ranges is incorrect.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(weights, ranges=None): @@ -203,7 +203,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -229,7 +229,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -254,7 +254,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3, 3))) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -281,7 +281,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3, 3)), requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) 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..b9d5e39f1c4 100644 --- a/tests/templates/test_state_preparations/test_arbitrary_state_prep.py +++ b/tests/templates/test_state_preparations/test_arbitrary_state_prep.py @@ -157,8 +157,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(2**4 - 2)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -182,7 +182,7 @@ class TestInputs: def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def circuit(weights): @@ -243,7 +243,7 @@ def test_list_and_tuples(self, tol): weights = [1] * 6 - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -265,7 +265,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(6,)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -291,7 +291,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(6,))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -316,7 +316,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(6,))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -343,7 +343,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(6,)), requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) 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..29630b791dc 100644 --- a/tests/templates/test_state_preparations/test_basis_state_prep.py +++ b/tests/templates/test_state_preparations/test_basis_state_prep.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" basis_state = [0, 1, 0] - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -189,7 +189,7 @@ def test_error_basis_state_format(self, basis_state, wires): def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(basis_state): 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..bda0d1db038 100644 --- a/tests/templates/test_state_preparations/test_mottonen_state_prep.py +++ b/tests/templates/test_state_preparations/test_mottonen_state_prep.py @@ -244,7 +244,7 @@ def test_RZ_skipped(self, mocker, state_vector, n_wires): n_CNOT = 2**n_wires - 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev, interface="autograd") def circuit(state_vector): @@ -262,8 +262,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" state = np.array([1 / 2, 1 / 2, 0, 1 / 2, 0, 1 / 2, 0, 0]) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -348,7 +348,7 @@ class TestGradient: def test_gradient_evaluated(self, state_vector): """Test that the gradient is successfully calculated for a simple example. This test only checks that the gradient is calculated without an error.""" - dev = qml.device("default.qubit", wires=1) + dev = qml.device("default.qubit.legacy", wires=1) @qml.qnode(dev) def circuit(state_vector): @@ -378,7 +378,7 @@ def test_jax(self, inputs, expected): from jax import numpy as jnp inputs = jnp.array(inputs) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(inputs): @@ -396,7 +396,7 @@ def test_jax_jit(self, inputs, expected): from jax import numpy as jnp inputs = jnp.array(inputs) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @jax.jit @qml.qnode(dev) @@ -414,7 +414,7 @@ def test_tensorflow(self, inputs, expected): import tensorflow as tf inputs = tf.Variable(inputs) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(inputs): @@ -431,7 +431,7 @@ def test_torch(self, inputs, expected): import torch inputs = torch.tensor(inputs, requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(inputs): diff --git a/tests/templates/test_subroutines/test_all_singles_doubles.py b/tests/templates/test_subroutines/test_all_singles_doubles.py index cb37e63cd7a..733c55d1942 100644 --- a/tests/templates/test_subroutines/test_all_singles_doubles.py +++ b/tests/templates/test_subroutines/test_all_singles_doubles.py @@ -108,8 +108,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = [0.1, 0.2] - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -249,7 +249,7 @@ def test_allsinglesdoubles_exceptions( """Test that AllSinglesDoubles throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) def circuit( weights=weights, wires=wires, hf_state=hf_state, singles=singles, doubles=doubles @@ -334,7 +334,7 @@ def test_list_and_tuples(self, tol): weights = list(range(2)) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -349,7 +349,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -374,7 +374,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(2,))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -398,7 +398,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(2,))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -425,7 +425,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_approx_time_evolution.py b/tests/templates/test_subroutines/test_approx_time_evolution.py index 5bb5f055b06..9ce75bd7242 100644 --- a/tests/templates/test_subroutines/test_approx_time_evolution.py +++ b/tests/templates/test_subroutines/test_approx_time_evolution.py @@ -144,7 +144,7 @@ def test_evolution_output(self, time, hamiltonian, steps, expectation): """Tests that the output from the ApproxTimeEvolution template is correct""" n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -160,8 +160,8 @@ def test_custom_wire_labels(self, tol): [1, 1, 1], [qml.PauliX("z"), qml.PauliX("a"), qml.PauliX("k")] ) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -186,7 +186,7 @@ def test_hamiltonian_error(self): """Tests if the correct error is thrown when hamiltonian is not a pennylane.Hamiltonian object""" n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) hamiltonian = np.array([[1, 1], [1, 1]]) @@ -212,7 +212,7 @@ def test_non_pauli_error(self, hamiltonian): """Tests if the correct errors are thrown when the user attempts to input a matrix with non-Pauli terms""" n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -271,7 +271,7 @@ def test_float(self, tol): time = 0.5 - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -286,7 +286,7 @@ def test_autograd(self, tol): time = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -312,7 +312,7 @@ def test_jax(self, tol): time = jnp.array(0.5) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -337,7 +337,7 @@ def test_tf(self, tol): time = tf.Variable(0.5) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -364,7 +364,7 @@ def test_torch(self, tol): time = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -388,7 +388,7 @@ def test_torch(self, tol): @pytest.mark.autograd @pytest.mark.parametrize( "dev_name,diff_method", - [["default.qubit.autograd", "backprop"], ["default.qubit", qml.gradients.param_shift]], + [["default.qubit.autograd", "backprop"], ["default.qubit.legacy", qml.gradients.param_shift]], ) def test_trainable_hamiltonian(dev_name, diff_method): """Test that the ApproxTimeEvolution template @@ -410,7 +410,7 @@ def create_tape(coeffs, t): def cost(coeffs, t): tape = create_tape(coeffs, t) - if diff_method is qml.gradients.param_shift and dev_name != "default.qubit": + if diff_method is qml.gradients.param_shift: 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..d3ded0e0a07 100644 --- a/tests/templates/test_subroutines/test_arbitrary_unitary.py +++ b/tests/templates/test_subroutines/test_arbitrary_unitary.py @@ -152,8 +152,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(63,)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -177,7 +177,7 @@ class TestInputs: def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) @qml.qnode(dev) def circuit(weights): @@ -237,7 +237,7 @@ def test_list_and_tuples(self, tol): weights = list(range(15)) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -252,7 +252,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(15,)), requires_grad=True) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -277,7 +277,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(15,))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -301,7 +301,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(15,))) - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -328,7 +328,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(15,)), requires_grad=True) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_basis_rotation.py b/tests/templates/test_subroutines/test_basis_rotation.py index b980ae12fbd..5f833c5279b 100644 --- a/tests/templates/test_subroutines/test_basis_rotation.py +++ b/tests/templates/test_subroutines/test_basis_rotation.py @@ -91,8 +91,8 @@ def test_custom_wire_labels(self, tol): ] ) - dev = qml.device("default.qubit", wires=2) - dev2 = qml.device("default.qubit", wires=["z", "a"]) + dev = qml.device("default.qubit.legacy", wires=2) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a"]) @qml.qnode(dev) def circuit(): @@ -236,7 +236,7 @@ def test_basis_rotation_unitary(self, unitary_matrix, eigen_values, exp_state): """Test that the BasisRotation template works correctly asserting the prepared state.""" wires = range(len(unitary_matrix)) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(): @@ -289,7 +289,7 @@ def test_basis_rotation_exceptions(self, wires, unitary_matrix, msg_match): """Test that BasisRotation template throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -372,7 +372,7 @@ def test_autograd(self, tol): ] ) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -414,7 +414,7 @@ def test_jax(self, tol): ] ) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -502,7 +502,7 @@ def test_torch(self, tol): requires_grad=False, ) - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_commuting_evolution.py b/tests/templates/test_subroutines/test_commuting_evolution.py index 7cb8c22c02a..edde44dc6f8 100644 --- a/tests/templates/test_subroutines/test_commuting_evolution.py +++ b/tests/templates/test_subroutines/test_commuting_evolution.py @@ -47,8 +47,8 @@ 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) + dev1 = qml.device("default.qubit.legacy", wires=n_wires) + dev2 = qml.device("default.qubit.legacy", wires=n_wires) obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] coeffs = [1, -1] @@ -110,7 +110,7 @@ def test_matrix(): def test_forward_execution(): """Compare the foward execution to an exactly known result.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) H = qml.PauliX(0) @ qml.PauliY(1) - 1.0 * qml.PauliY(0) @ qml.PauliX(1) freq = (2, 4) @@ -147,7 +147,7 @@ def test_two_term_case(self): finite difference result for a two term shift rule case.""" n_wires = 1 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) hamiltonian = qml.Hamiltonian([1], [qml.PauliX(0)]) frequencies = (2,) @@ -172,7 +172,7 @@ def test_four_term_case(self): finite difference result for a four term shift rule case.""" n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) coeffs = [1, -1] obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] @@ -197,7 +197,7 @@ def test_differentiable_hamiltonian(self): """Tests correct gradients are produced when the Hamiltonian is differentiable.""" n_wires = 2 - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] diff_coeffs = np.array([1.0, -1.0], requires_grad=True) frequencies = (2, 4) diff --git a/tests/templates/test_subroutines/test_double_excitation.py b/tests/templates/test_subroutines/test_double_excitation.py index 76768b9a1fe..8e0a29b12cc 100644 --- a/tests/templates/test_subroutines/test_double_excitation.py +++ b/tests/templates/test_subroutines/test_double_excitation.py @@ -236,8 +236,8 @@ def test_double_ex_unitary_operations(self, wires1, wires2, ref_gates): def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" - dev = qml.device("default.qubit", wires=5) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "t", "s"]) + dev = qml.device("default.qubit.legacy", wires=5) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "t", "s"]) @qml.qnode(dev) def circuit(): @@ -270,7 +270,7 @@ class TestInputs: def test_double_excitation_unitary_exceptions(self, weight, wires1, wires2, msg_match): """Test exception if ``weight`` or ``pphh`` parameter has illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=10) + dev = qml.device("default.qubit.legacy", wires=10) def circuit(weight): qml.FermionicDoubleExcitation(weight=weight, wires1=wires1, wires2=wires2) @@ -302,7 +302,7 @@ def test_autograd(self): weight = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -323,7 +323,7 @@ def test_jax(self): import jax.numpy as jnp weight = jnp.array(0.5) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -340,7 +340,7 @@ def test_tf(self): import tensorflow as tf weight = tf.Variable(0.5) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -360,7 +360,7 @@ def test_torch(self): weight = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) diff --git a/tests/templates/test_subroutines/test_flip_sign.py b/tests/templates/test_subroutines/test_flip_sign.py index b8170167975..55002a8f604 100644 --- a/tests/templates/test_subroutines/test_flip_sign.py +++ b/tests/templates/test_subroutines/test_flip_sign.py @@ -66,7 +66,7 @@ def test_eval(self, n_status, n_wires): n_wires = 1 if n_wires == 0 else n_wires n_wires = list(range(n_wires)) - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit(): diff --git a/tests/templates/test_subroutines/test_grover.py b/tests/templates/test_subroutines/test_grover.py index bc2f0dce0fd..6dff4314aa0 100644 --- a/tests/templates/test_subroutines/test_grover.py +++ b/tests/templates/test_subroutines/test_grover.py @@ -152,7 +152,7 @@ def oracle(): qml.Toffoli(wires=wires) qml.Hadamard(wires[-1]) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def GroverSearch(num_iterations=1): @@ -205,7 +205,7 @@ def test_findstate(n_wires): """Asserts can find state marked by oracle, with operation full matrix and decomposition.""" wires = list(range(n_wires)) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circ(): diff --git a/tests/templates/test_subroutines/test_kupccgsd.py b/tests/templates/test_subroutines/test_kupccgsd.py index 0343cb4d34f..87d959aaa64 100644 --- a/tests/templates/test_subroutines/test_kupccgsd.py +++ b/tests/templates/test_subroutines/test_kupccgsd.py @@ -125,8 +125,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -247,7 +247,7 @@ def test_k_layers_upccgsd(self, num_qubits, k, exp_state, tol): shape = qml.kUpCCGSD.shape(k=k, n_wires=num_qubits, delta_sz=0) weight = np.pi / 2 * qml.math.ones(shape) - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) init_state = qml.math.array([1 if x < num_qubits // 2 else 0 for x in wires]) @@ -446,7 +446,7 @@ def test_kupccgsd_exceptions(self, wires, weights, k, delta_sz, init_state, msg_ """Test that k-UpCCGSD throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -539,7 +539,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol): """Test common iterables as inputs.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -561,7 +561,7 @@ def test_autograd(self, tol): weights = qml.numpy.random.random(size=(1, 6), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -587,7 +587,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 6))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -612,7 +612,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 6))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -639,7 +639,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 6)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -665,7 +665,7 @@ class TestGradient: def test_ps_rule_gradient(self, tol): """Test parameter-shift rule gradient.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) backprop_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="backprop")) ps_rule_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="parameter-shift")) diff --git a/tests/templates/test_subroutines/test_permute.py b/tests/templates/test_subroutines/test_permute.py index 08f240d82e3..4868cd08c82 100644 --- a/tests/templates/test_subroutines/test_permute.py +++ b/tests/templates/test_subroutines/test_permute.py @@ -26,7 +26,7 @@ class TestDecomposition: def test_identity_permutation_qnode(self, mocker): """Test that identity permutations have no effect on QNodes.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev, interface="autograd") def identity_permutation(): @@ -37,7 +37,7 @@ def identity_permutation(): identity_permutation() # expand the Permute operation - tape = spy.call_args[0][0][0] + tape = spy.call_args[0][0] assert len(tape.operations) == 0 @@ -66,7 +66,7 @@ def test_identity_permutation_tape(self): def test_two_cycle_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test some two-cycles on QNodes.""" - dev = qml.device("default.qubit", wires=len(permutation_order)) + dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def two_cycle(): @@ -76,7 +76,7 @@ def two_cycle(): spy = mocker.spy(two_cycle.device, "execute") two_cycle() - tape = spy.call_args[0][0][0] + tape = spy.call_args[0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -120,7 +120,7 @@ def test_two_cycle_permutations_tape(self, permutation_order, wire_order, expect def test_cyclic_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test more general cycles on QNodes.""" - dev = qml.device("default.qubit", wires=len(permutation_order)) + dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def cycle(): @@ -130,7 +130,7 @@ def cycle(): spy = mocker.spy(cycle.device, "execute") cycle() - tape = spy.call_args[0][0][0] + tape = spy.call_args[0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -170,7 +170,7 @@ def test_cyclic_permutations_tape(self, permutation_order, wire_order, expected_ def test_arbitrary_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test arbitrarily generated permutations on QNodes.""" - dev = qml.device("default.qubit", wires=len(permutation_order)) + dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def arbitrary_perm(): @@ -180,7 +180,7 @@ def arbitrary_perm(): spy = mocker.spy(arbitrary_perm.device, "execute") arbitrary_perm() - tape = spy.call_args[0][0][0] + tape = spy.call_args[0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -230,7 +230,7 @@ def test_subset_permutations_qnode( ): """Test permutation of wire subsets on QNodes.""" - dev = qml.device("default.qubit", wires=num_wires) + dev = qml.device("default.qubit.legacy", wires=num_wires) @qml.qnode(dev, interface="autograd") def subset_perm(): @@ -240,7 +240,7 @@ def subset_perm(): spy = mocker.spy(subset_perm.device, "execute") subset_perm() - tape = spy.call_args[0][0][0] + tape = spy.call_args[0][0] # Check that the Permute operation was expanded to SWAPs when the QNode # is evaluated, and that the wires are the same @@ -284,24 +284,23 @@ def test_custom_wire_labels(self, tol): permutation = [3, 0, 2, 1] permutation2 = ["o", "z", "k", "a"] - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "o"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "o"]) @qml.qnode(dev) def circuit(): qml.Permute(permutation, wires=range(4)) - return qml.expval(qml.Identity(0)), qml.state() + return qml.expval(qml.Identity(0)) @qml.qnode(dev2) def circuit2(): qml.Permute(permutation2, wires=["z", "a", "k", "o"]) - return qml.expval(qml.Identity("z")), qml.state() + return qml.expval(qml.Identity("z")) - res1, state1 = circuit() - res2, state2 = circuit2() + circuit() + circuit2() - assert np.allclose(res1, res2, atol=tol, rtol=0) - assert np.allclose(state1, state2, atol=tol, rtol=0) + assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) class TestInputs: @@ -319,7 +318,7 @@ class TestInputs: def test_invalid_inputs_qnodes(self, permutation_order, expected_error_message): """Tests if errors are thrown for invalid permutations with QNodes.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) @qml.qnode(dev) def permute_qubits(): diff --git a/tests/templates/test_subroutines/test_qft.py b/tests/templates/test_subroutines/test_qft.py index 9e17377f215..bbea8a3b18a 100644 --- a/tests/templates/test_subroutines/test_qft.py +++ b/tests/templates/test_subroutines/test_qft.py @@ -38,13 +38,14 @@ def test_QFT_decomposition(self, n_qubits): op = qml.QFT(wires=range(n_qubits)) decomp = op.decomposition() - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) out_states = [] for state in np.eye(2**n_qubits): + dev.reset() ops = [qml.StatePrep(state, wires=range(n_qubits))] + decomp - qs = qml.tape.QuantumScript(ops, [qml.state()]) - out_states.append(dev.execute(qs)) + dev.apply(ops) + out_states.append(dev.state) reconstructed_unitary = np.array(out_states).T expected_unitary = qml.QFT(wires=range(n_qubits)).matrix() @@ -56,7 +57,7 @@ def test_QFT_adjoint_identity(self, n_qubits, tol): """Test if using the qml.adjoint transform the resulting operation is the inverse of QFT.""" - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) @qml.qnode(dev) def circ(n_qubits): diff --git a/tests/templates/test_subroutines/test_qmc.py b/tests/templates/test_subroutines/test_qmc.py index 8cb4a01928c..8dcd83f643d 100644 --- a/tests/templates/test_subroutines/test_qmc.py +++ b/tests/templates/test_subroutines/test_qmc.py @@ -141,7 +141,7 @@ def test_example_with_pl(self): r = func_to_unitary(func, M) - dev = qml.device("default.qubit", wires=(wires + 1)) + dev = qml.device("default.qubit.legacy", wires=(wires + 1)) @qml.qnode(dev) def apply_r(input_state): @@ -361,7 +361,7 @@ def test_expected_value(self): target_wires = range(m + 1) estimation_wires = range(m + 1, n + m + 1) - dev = qml.device("default.qubit", wires=(n + m + 1)) + dev = qml.device("default.qubit.legacy", wires=(n + m + 1)) @qml.qnode(dev) def circuit(): @@ -411,7 +411,7 @@ def test_expected_value_jax_jit(self): target_wires = range(m + 1) estimation_wires = range(m + 1, n + m + 1) - dev = qml.device("default.qubit", wires=(n + m + 1)) + dev = qml.device("default.qubit.legacy", wires=(n + m + 1)) @jax.jit @qml.qnode(dev, interface="jax") @@ -455,7 +455,7 @@ def test_expected_value_custom_wires(self): target_wires = [0, "a", -1.1, -10, "bbb", 1000] estimation_wires = ["bob", -3, 42, "penny", "lane", 247, "straw", "berry", 5.5, 6.6] - dev = qml.device("default.qubit", wires=target_wires + estimation_wires) + dev = qml.device("default.qubit.legacy", wires=target_wires + estimation_wires) @qml.qnode(dev) def circuit(): diff --git a/tests/templates/test_subroutines/test_qpe.py b/tests/templates/test_subroutines/test_qpe.py index 06354012851..67aba0797d5 100644 --- a/tests/templates/test_subroutines/test_qpe.py +++ b/tests/templates/test_subroutines/test_qpe.py @@ -84,7 +84,7 @@ def test_phase_estimated(self, phase): wire_range = range(2, 10) for wires in wire_range: - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) m = qml.RX(phase, wires=0).matrix() target_wires = [0] estimation_wires = range(1, wires) @@ -99,10 +99,9 @@ def test_phase_estimated(self, phase): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tapes, _, _ = dev.preprocess(tape) - assert len(tapes) == 1 + tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) - res = dev.execute(tapes)[0].flatten() + res = dev.execute(tape).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 @@ -136,7 +135,7 @@ def test_phase_estimated_two_qubit(self): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) target_wires = [0, 1] estimation_wires = range(2, wires) @@ -151,9 +150,8 @@ def test_phase_estimated_two_qubit(self): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tapes, _, _ = dev.preprocess(tape) - assert len(tapes) == 1 - res = dev.execute(tapes)[0].flatten() + tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) + res = dev.execute(tape).flatten() if phase < 0: estimate = np.argmax(res) / 2 ** (wires - 2) - 1 @@ -186,7 +184,7 @@ def test_phase_estimated_single_ops(self, param): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) estimation_wires = range(1, wires - 1) target_wires = [0] @@ -197,9 +195,8 @@ def test_phase_estimated_single_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tapes, _, _ = dev.preprocess(tape) - res = dev.execute(tapes)[0].flatten() - assert len(tapes) == 1 + tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) + res = dev.execute(tape).flatten() estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) @@ -228,7 +225,7 @@ def test_phase_estimated_ops(self, param): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) # Offset the index of target wires to test the wire maÏp estimation_wires = range(2, wires) @@ -240,9 +237,8 @@ def test_phase_estimated_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tapes, _, _ = dev.preprocess(tape) - assert len(tapes) == 1 - res = dev.execute(tapes)[0].flatten() + tape = tape.expand(depth=2, stop_at=lambda obj: obj.name in dev.operations) + res = dev.execute(tape).flatten() estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) @@ -304,7 +300,7 @@ def test_map_wires(self): def test_adjoint(self): """Test that the QPE adjoint works.""" - dev = qml.device("default.qubit", wires=3) + dev = qml.device("default.qubit.legacy", wires=3) @qml.qnode(dev) def qpe_circuit(): diff --git a/tests/templates/test_subroutines/test_qsvt.py b/tests/templates/test_subroutines/test_qsvt.py index 841ef3d8d64..bdffcfe2186 100644 --- a/tests/templates/test_subroutines/test_qsvt.py +++ b/tests/templates/test_subroutines/test_qsvt.py @@ -98,7 +98,7 @@ def test_init_error(self): ) def test_output(self, U_A, lst_projectors, wires, operations): """Test that qml.QSVT produces the intended measurements.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -289,7 +289,7 @@ def test_QSVT_tensorflow(self, input_matrix, angles, wires): def test_QSVT_grad(self, A, phis): """Test that qml.grad results are the same as finite difference results""" - @qml.qnode(qml.device("default.qubit", wires=2)) + @qml.qnode(qml.device("default.qubit.legacy", wires=2)) def circuit(A, phis): qml.QSVT( qml.BlockEncode(A, wires=[0, 1]), @@ -361,7 +361,7 @@ class Testqsvt: ) def test_output(self, A, phis, wires, true_mat): """Test that qml.qsvt produces the correct output.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -399,7 +399,7 @@ def circuit(): ) def test_output_wx(self, A, phis, wires, result): """Test that qml.qsvt produces the correct output.""" - dev = qml.device("default.qubit", wires=len(wires)) + dev = qml.device("default.qubit.legacy", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -499,7 +499,7 @@ def test_qsvt_tensorflow(self, input_matrix, angles, wires): def test_qsvt_grad(self): """Test that qml.grad results are the same as finite difference results""" - @qml.qnode(qml.device("default.qubit", wires=2)) + @qml.qnode(qml.device("default.qubit.legacy", wires=2)) def circuit(A, phis): qml.qsvt( A, diff --git a/tests/templates/test_subroutines/test_select.py b/tests/templates/test_subroutines/test_select.py index dd63047c606..97339afac62 100644 --- a/tests/templates/test_subroutines/test_select.py +++ b/tests/templates/test_subroutines/test_select.py @@ -72,7 +72,7 @@ class TestSelect: ) def test_operation_result(self, ops, control_wires, expected_gates, n_wires): """Test the correctness of the Select template output.""" - dev = qml.device("default.qubit", wires=n_wires) + dev = qml.device("default.qubit.legacy", wires=n_wires) @qml.qnode(dev) def circuit1(): @@ -281,7 +281,7 @@ class TestInterfaces: @pytest.mark.autograd def test_autograd(self): """Tests the autograd interface.""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_select = qml.QNode(select_rx_circuit, dev) @@ -302,7 +302,7 @@ def test_tf(self): """Tests the tf interface.""" import tensorflow as tf - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_tf = qml.QNode(select_rx_circuit, dev) @@ -330,7 +330,7 @@ def test_torch(self): """Tests the torch interface.""" import torch - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_torch = qml.QNode(select_rx_circuit, dev) @@ -360,7 +360,7 @@ def test_jax(self): import jax import jax.numpy as jnp - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) input_default = [0.5, 0.2] input_jax = jnp.array(input_default) diff --git a/tests/templates/test_subroutines/test_single_excitation.py b/tests/templates/test_subroutines/test_single_excitation.py index 76eda25a2b8..75e833e889c 100644 --- a/tests/templates/test_subroutines/test_single_excitation.py +++ b/tests/templates/test_subroutines/test_single_excitation.py @@ -112,24 +112,23 @@ def test_single_ex_unitary_operations(self, single_wires, ref_gates): def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): qml.FermionicSingleExcitation(0.4, wires=[1, 0, 2]) - return qml.expval(qml.Identity(0)), qml.state() + return qml.expval(qml.Identity(0)) @qml.qnode(dev2) def circuit2(): qml.FermionicSingleExcitation(0.4, wires=["a", "z", "k"]) - return qml.expval(qml.Identity("z")), qml.state() + return qml.expval(qml.Identity("z")) - res1, state1 = circuit() - res2, state2 = circuit2() + circuit() + circuit2() - assert np.allclose(res1, res2, atol=tol, rtol=0) - assert np.allclose(state1, state2, atol=tol, rtol=0) + assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0) class TestInputs: @@ -146,7 +145,7 @@ class TestInputs: def test_single_excitation_unitary_exceptions(self, weight, single_wires, msg_match): """Test that FermionicSingleExcitation throws an exception if ``weight`` or ``single_wires`` parameter has illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=5) + dev = qml.device("default.qubit.legacy", wires=5) def circuit(weight=weight): qml.FermionicSingleExcitation(weight=weight, wires=single_wires) @@ -178,7 +177,7 @@ def test_autograd(self): weight = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -198,7 +197,7 @@ def test_jax(self): import jax.numpy as jnp weight = jnp.array(0.5) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -215,7 +214,7 @@ def test_tf(self): import tensorflow as tf weight = tf.Variable(0.5) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -235,7 +234,7 @@ def test_torch(self): weight = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) diff --git a/tests/templates/test_subroutines/test_uccsd.py b/tests/templates/test_subroutines/test_uccsd.py index e9bbca83147..700c9239256 100644 --- a/tests/templates/test_subroutines/test_uccsd.py +++ b/tests/templates/test_subroutines/test_uccsd.py @@ -213,7 +213,7 @@ class TestInputs: [[0, 2]], [], np.array([1, 1, 0, 0, 0]), - "Basis states must be of length 4", + "BasisState parameter and wires", ), ( np.array([-2.8, 1.6]), @@ -243,7 +243,7 @@ def test_uccsd_xceptions(self, weights, s_wires, d_wires, init_state, msg_match) shapes, types or values.""" N = 4 wires = range(4) - dev = qml.device("default.qubit", wires=N) + dev = qml.device("default.qubit.legacy", wires=N) def circuit( weights=weights, wires=wires, s_wires=s_wires, d_wires=d_wires, init_state=init_state @@ -308,7 +308,7 @@ def test_list_and_tuples(self, tol): weights = list(range(2)) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -323,7 +323,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -349,7 +349,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(2,))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -373,7 +373,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(2,))) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -400,7 +400,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_swapnetworks/test_ccl2.py b/tests/templates/test_swapnetworks/test_ccl2.py index 128c3cfe862..b1d9d5bad3a 100644 --- a/tests/templates/test_swapnetworks/test_ccl2.py +++ b/tests/templates/test_swapnetworks/test_ccl2.py @@ -110,8 +110,8 @@ def acquaintances(index, *_, **___): weights = np.random.random(size=10) - dev = qml.device("default.qubit", wires=5) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e", "y"]) + dev = qml.device("default.qubit.legacy", wires=5) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e", "y"]) @qml.qnode(dev) def circuit(): @@ -195,7 +195,7 @@ def test_ccl2(self, num_wires, acquaintances, weights, fermionic, shift, exp_sta shape = qml.templates.TwoLocalSwapNetwork.shape(num_wires) weights = np.pi / 2 * qml.math.ones(shape) if weights else None - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(): @@ -253,7 +253,7 @@ def test_ccl2_exceptions(self, wires, acquaintances, weights, fermionic, shift, """Test that TwoLocalSwapNetwork throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(): @@ -338,7 +338,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol): """Test common iterables as inputs.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -360,7 +360,7 @@ def test_autograd(self, tol): weights = qml.numpy.random.random(size=(6), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -386,7 +386,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=6)) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -411,7 +411,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=6)) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -438,7 +438,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=6), requires_grad=True) - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -465,7 +465,7 @@ class TestGradient: def test_ps_rule_gradient(self, tol): """Test parameter-shift rule gradient.""" - dev = qml.device("default.qubit", wires=4) + dev = qml.device("default.qubit.legacy", wires=4) backprop_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="backprop")) ps_rule_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="parameter-shift")) diff --git a/tests/templates/test_tensornetworks/test_MERA.py b/tests/templates/test_tensornetworks/test_MERA.py index 1d293e287f5..7718fab17c0 100644 --- a/tests/templates/test_tensornetworks/test_MERA.py +++ b/tests/templates/test_tensornetworks/test_MERA.py @@ -341,7 +341,7 @@ def test_exception_wrong_weight_shape( ) def test_block_params(self, block, n_params_block, wires, n_block_wires, template_weights): """Verify that the template works with arbitrary block parameters""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(): @@ -417,7 +417,7 @@ def test_template_differentiable( self, block, n_params_block, wires, n_block_wires, template_weights ): """Test that the template is differentiable for different inputs.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(template_weights): @@ -466,7 +466,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit_template(): diff --git a/tests/templates/test_tensornetworks/test_MPS.py b/tests/templates/test_tensornetworks/test_MPS.py index 9d03571f362..e4c183dbcaa 100644 --- a/tests/templates/test_tensornetworks/test_MPS.py +++ b/tests/templates/test_tensornetworks/test_MPS.py @@ -334,7 +334,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) block = getattr(self, block) expected_circuit = getattr(self, expected_circuit) diff --git a/tests/templates/test_tensornetworks/test_TTN.py b/tests/templates/test_tensornetworks/test_TTN.py index b7a23f703fd..fb9575923af 100644 --- a/tests/templates/test_tensornetworks/test_TTN.py +++ b/tests/templates/test_tensornetworks/test_TTN.py @@ -290,7 +290,7 @@ def test_exception_wrong_weight_shape( ) def test_block_params(self, block, n_params_block, wires, n_block_wires, template_weights): """Verify that the template works with arbitrary block parameters""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(): @@ -359,7 +359,7 @@ def test_template_differentiable( self, block, n_params_block, wires, n_block_wires, template_weights ): """Test that the template is differentiable for different inputs.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit(template_weights): @@ -402,7 +402,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit", wires=wires) + dev = qml.device("default.qubit.legacy", wires=wires) @qml.qnode(dev) def circuit_template(): From 4e212e11b6c11bd2a32e92374e85c16e986ad931 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 12:15:24 -0400 Subject: [PATCH 30/78] Revert "temp for ci: use legacy in templates" This reverts commit bdec8759133b2e80408eb1b2a9c99d20689b218e. --- tests/templates/test_broadcast.py | 12 ++--- .../test_embeddings/test_amplitude.py | 46 +++++++++---------- tests/templates/test_embeddings/test_angle.py | 22 ++++----- tests/templates/test_embeddings/test_basis.py | 25 +++++----- .../templates/test_embeddings/test_iqp_emb.py | 18 ++++---- .../test_embeddings/test_qaoa_emb.py | 26 +++++------ .../test_layers/test_basic_entangler.py | 16 +++---- .../templates/test_layers/test_gate_fabric.py | 18 ++++---- .../test_particle_conserving_u1.py | 16 +++---- .../test_particle_conserving_u2.py | 16 +++---- tests/templates/test_layers/test_random.py | 14 +++--- .../test_layers/test_simplified_twodesign.py | 16 +++---- .../test_layers/test_strongly_entangling.py | 16 +++---- .../test_arbitrary_state_prep.py | 16 +++---- .../test_basis_state_prep.py | 6 +-- .../test_mottonen_state_prep.py | 16 +++---- .../test_all_singles_doubles.py | 16 +++---- .../test_approx_time_evolution.py | 24 +++++----- .../test_arbitrary_unitary.py | 16 +++---- .../test_subroutines/test_basis_rotation.py | 14 +++--- .../test_commuting_evolution.py | 12 ++--- .../test_double_excitation.py | 14 +++--- .../test_subroutines/test_flip_sign.py | 2 +- .../templates/test_subroutines/test_grover.py | 4 +- .../test_subroutines/test_kupccgsd.py | 20 ++++---- .../test_subroutines/test_permute.py | 37 +++++++-------- tests/templates/test_subroutines/test_qft.py | 9 ++-- tests/templates/test_subroutines/test_qmc.py | 8 ++-- tests/templates/test_subroutines/test_qpe.py | 30 ++++++------ tests/templates/test_subroutines/test_qsvt.py | 10 ++-- .../templates/test_subroutines/test_select.py | 10 ++-- .../test_single_excitation.py | 25 +++++----- .../templates/test_subroutines/test_uccsd.py | 14 +++--- .../templates/test_swapnetworks/test_ccl2.py | 20 ++++---- .../test_tensornetworks/test_MERA.py | 6 +-- .../templates/test_tensornetworks/test_MPS.py | 2 +- .../templates/test_tensornetworks/test_TTN.py | 6 +-- 37 files changed, 302 insertions(+), 296 deletions(-) diff --git a/tests/templates/test_broadcast.py b/tests/templates/test_broadcast.py index 9db921a2b6e..69b1a8f19b5 100644 --- a/tests/templates/test_broadcast.py +++ b/tests/templates/test_broadcast.py @@ -227,7 +227,7 @@ def test_correct_parameters_in_queue(self, pattern, n_wires, gate, parameters): def test_prepares_correct_state(self, pattern, n_wires, parameters, unitary, target): """Tests the state produced by different unitaries.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -244,7 +244,7 @@ def test_throws_error_when_mismatch_params_wires(self, parameters, n_wires): """Tests that error thrown when 'parameters' does not contain one set of parameters for each wire.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -258,7 +258,7 @@ def test_throws_special_error_for_ring_pattern_2_wires(self): """Tests that the special error is thrown when 'parameters' does not contain one sequence of parameters for a two-wire ring pattern.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(pars): @@ -310,7 +310,7 @@ class TestCustomPattern: def test_reproduce_builtin_patterns(self, custom_pattern, pattern): """Tests that the custom pattern can reproduce the built in patterns.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) # qnode using custom pattern @qml.qnode(dev) @@ -338,7 +338,7 @@ def circuit2(): def test_correct_output(self, custom_pattern, expected): """Tests the output for simple cases.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def circuit(): @@ -351,7 +351,7 @@ def circuit(): def test_unknown_pattern(): """Test that an unknown pattern raises an error""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(pars): diff --git a/tests/templates/test_embeddings/test_amplitude.py b/tests/templates/test_embeddings/test_amplitude.py index 6a3ecc6b462..8b8d79ba1ab 100644 --- a/tests/templates/test_embeddings/test_amplitude.py +++ b/tests/templates/test_embeddings/test_amplitude.py @@ -74,7 +74,7 @@ def test_prepares_correct_state(self, inpt, normalize): """Checks the state for real and complex inputs.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -91,7 +91,7 @@ def test_prepares_correct_broadcasted_state(self, inpt, normalize): """Checks the state for real and complex inputs.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -107,7 +107,7 @@ def test_prepares_padded_state(self, inpt, pad): """Checks the state for real and complex padding constants.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -126,7 +126,7 @@ def test_prepares_padded_state_broadcasted(self, inpt, pad): """Checks the state for real and complex padding constants.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -142,8 +142,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.array([0, 1 / 2, 0, 1 / 2, 0, 0, 1 / 2, 1 / 2]) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -169,7 +169,7 @@ def test_throws_exception_if_not_normalized(self, inpt): """Checks exception when state is not normalized and `normalize=False`.""" not_nrmlzd = 2 * inpt n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -185,7 +185,7 @@ def test_throws_exception_if_features_wrong_shape(self): """Checks exception if features has more than two dimensions.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -207,7 +207,7 @@ def test_throws_exception_if_fewer_features_than_amplitudes(self, inpt): no automatic padding is chosen.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -225,7 +225,7 @@ def test_throws_exception_if_more_features_than_amplitudes_padding(self, inpt): automatic padding is chosen.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -270,7 +270,7 @@ def test_amplitude_embedding_tolerance_value(self): tolerance = 10e-10 num_qubits = 5 - dev = qml.device("default.qubit.legacy", wires=num_qubits) + dev = qml.device("default.qubit", wires=num_qubits) assert np.isclose(np.sum(np.abs(inputs) ** 2), 1, tolerance) @qml.qnode(dev) @@ -315,7 +315,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol, features): """Tests common iterables as inputs.""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -335,7 +335,7 @@ def test_autograd(self, tol, features): features = pnp.array(features, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -352,7 +352,7 @@ def test_autograd_pad_with(self, tol, features): features = pnp.array(features) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def node_decomposed(features): @@ -382,7 +382,7 @@ def test_jax(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -402,7 +402,7 @@ def test_jax_jit(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = jax.jit(qml.QNode(circuit_template, dev)) circuit2 = jax.jit(qml.QNode(circuit_decomposed, dev)) @@ -422,7 +422,7 @@ def test_jax_jit_pad_with(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @jax.jit @qml.qnode(dev) @@ -453,7 +453,7 @@ def test_tf(self, tol): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -471,7 +471,7 @@ def test_tf_pad_with(self, tol, features): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def node_decomposed(features): @@ -500,7 +500,7 @@ def test_tf_error_when_batching(self): features = tf.Variable(all_features[1]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) @@ -515,7 +515,7 @@ def test_tf_jit(self, tol): features = tf.Variable(all_features[0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = tf.function(jit_compile=True)(qml.QNode(circuit_template, dev)) circuit2 = tf.function(jit_compile=True)(qml.QNode(circuit_decomposed, dev)) @@ -534,7 +534,7 @@ def test_torch(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -552,7 +552,7 @@ def test_torch_pad_with(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def node_decomposed(features): diff --git a/tests/templates/test_embeddings/test_angle.py b/tests/templates/test_embeddings/test_angle.py index c659072f0ae..ef531695f3d 100644 --- a/tests/templates/test_embeddings/test_angle.py +++ b/tests/templates/test_embeddings/test_angle.py @@ -90,7 +90,7 @@ def test_state( """Checks the state produced using the rotation='X' strategy.""" features = [np.pi / 2, np.pi / 2, np.pi / 4, 0] - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def circuit(x=None): @@ -109,7 +109,7 @@ def test_fewer_features(self): features = [np.pi / 2, np.pi / 2, 0, np.pi / 2] - dev = qml.device("default.qubit.legacy", wires=5) + dev = qml.device("default.qubit", wires=5) @qml.qnode(dev) def circuit(x=None): @@ -124,8 +124,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.random.random(size=(3,)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -151,7 +151,7 @@ def test_exception_fewer_rotations(self): rotation gates than features.""" features = [0, 0, 1, 0] - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def circuit(x=None): @@ -165,7 +165,7 @@ def test_exception_wrongrot(self): """Verifies that exception is raised if the rotation strategy is unknown.""" - dev = qml.device("default.qubit.legacy", wires=1) + dev = qml.device("default.qubit", wires=1) @qml.qnode(dev) def circuit(x=None): @@ -206,7 +206,7 @@ def test_list_and_tuples(self, tol): features = [1.0, 1.0, 1.0] - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -225,7 +225,7 @@ def test_autograd(self, tol): features = pnp.array([1.0, 1.0, 1.0], requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -251,7 +251,7 @@ def test_jax(self, tol): features = jnp.array([1.0, 1.0, 1.0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -276,7 +276,7 @@ def test_tf(self, tol): features = tf.Variable([1.0, 1.0, 1.0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -303,7 +303,7 @@ def test_torch(self, tol): features = torch.tensor([1.0, 1.0, 1.0], requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_basis.py b/tests/templates/test_embeddings/test_basis.py index 4b31d94e3c9..39085c967ee 100644 --- a/tests/templates/test_embeddings/test_basis.py +++ b/tests/templates/test_embeddings/test_basis.py @@ -57,7 +57,7 @@ def test_state(self, state): """Checks that the correct state is prepared.""" n_qubits = 2 - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circuit(x=None): @@ -72,8 +72,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = [1, 0, 1] - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -111,7 +111,7 @@ def test_features_as_int_conversion(self, feat, wires, expected): def test_wrong_input_bits_exception(self, x): """Checks exception if number of features is not same as number of qubits.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(): @@ -124,7 +124,7 @@ def circuit(): def test_input_not_binary_exception(self): """Checks exception if the features contain values other than zero and one.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -137,7 +137,7 @@ def circuit(x=None): def test_exception_wrong_dim(self): """Checks exception if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -173,7 +173,7 @@ def test_list_and_tuples(self, tol): """Tests common iterables as inputs.""" features = [0, 1, 0] - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -195,7 +195,7 @@ def test_autograd(self, tol): features = pnp.array([0, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -215,7 +215,7 @@ def test_jax(self, tol): features = jnp.array([0, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -236,6 +236,7 @@ def test_jax_jit(self, tol): features = jnp.array([0, 1, 0]) + # use legacy device until qml.state is fixed dev = qml.device("default.qubit.legacy", wires=3) circuit = qml.QNode(circuit_template, dev) @@ -258,7 +259,7 @@ def test_tf(self, tol): features = tf.Variable([0, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -278,7 +279,7 @@ def test_tf_autograph(self, tol): features = tf.Variable([0, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -298,7 +299,7 @@ def test_torch(self, tol): features = torch.tensor([0, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_iqp_emb.py b/tests/templates/test_embeddings/test_iqp_emb.py index 603ed4aece5..5eb25401b43 100644 --- a/tests/templates/test_embeddings/test_iqp_emb.py +++ b/tests/templates/test_embeddings/test_iqp_emb.py @@ -113,8 +113,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" features = np.random.random(size=(3,)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -141,7 +141,7 @@ class TestInputs: def test_exception_wrong_number_of_features(self, features): """Verifies that an exception is raised if 'features' has the wrong trailing dimension.""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def circuit(f=None): @@ -155,7 +155,7 @@ def circuit(f=None): def test_exception_wrong_ndim(self, shape): """Verifies that an exception is raised if 'features' has the wrong number of dimensions.""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def circuit(f=None): @@ -207,7 +207,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol, features): """Tests common iterables as inputs.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) res = circuit(features) @@ -230,7 +230,7 @@ def test_autograd(self, tol, features): features = pnp.array(features, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -257,7 +257,7 @@ def test_jax(self, tol, features): features = jnp.array(features) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -283,7 +283,7 @@ def test_tf(self, tol, features): features = tf.Variable(features) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -311,7 +311,7 @@ def test_torch(self, tol, features): features = torch.tensor(features, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_embeddings/test_qaoa_emb.py b/tests/templates/test_embeddings/test_qaoa_emb.py index e63ef51880f..de49c972d67 100644 --- a/tests/templates/test_embeddings/test_qaoa_emb.py +++ b/tests/templates/test_embeddings/test_qaoa_emb.py @@ -133,7 +133,7 @@ def test_exception_wrongrot(self): n_wires = 1 weights = np.zeros(shape=(1, 1)) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -173,7 +173,7 @@ def test_output_zz(self, weights, target, tol): """Checks the output if the features and entangler weights are nonzero, which makes the circuit only depend on the ZZ gate.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(x=None): @@ -194,7 +194,7 @@ def circuit(x=None): def test_state_more_qubits_than_features(self, n_wires, features, weights, target, tol): """Checks the state is correct if there are more qubits than features.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -209,8 +209,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) features = np.random.random(size=(3,)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -263,7 +263,7 @@ def test_exception_fewer_qubits_than_features( features = [0, 0, 0, 0] n_wires = 1 weights = np.zeros(shape=(1, 2 * n_wires)) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(x=None): @@ -279,7 +279,7 @@ def test_exception_wrong_feature_shape(self, shape): n_wires = 1 weights = np.zeros(shape=(1, 1)) features = np.zeros(shape=shape) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -300,7 +300,7 @@ def circuit(): def test_exception_wrong_weight_shape(self, weights, n_wires): """Verifies that exception is raised if the shape of weights is incorrect.""" features = np.zeros(shape=(n_wires,)) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -320,7 +320,7 @@ def circuit(): def test_exception_wrong_weight_ndim(self, weights, n_wires): """Verifies that exception is raised if the shape of weights is incorrect.""" features = np.zeros(shape=(n_wires,)) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -383,7 +383,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -411,7 +411,7 @@ def test_jax(self, tol): features = jnp.array(np.random.random(size=(2,))) weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -438,7 +438,7 @@ def test_tf(self, tol): features = tf.Variable(np.random.random(size=(2,))) weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -467,7 +467,7 @@ def test_torch(self, tol): features = torch.tensor(np.random.random(size=(2,)), requires_grad=True) weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_basic_entangler.py b/tests/templates/test_layers/test_basic_entangler.py index ee0723f44b6..4c2ca6a83bf 100644 --- a/tests/templates/test_layers/test_basic_entangler.py +++ b/tests/templates/test_layers/test_basic_entangler.py @@ -72,7 +72,7 @@ def test_rotation(self, rotation): def test_simple_target_outputs(self, weights, n_wires, target, tol): """Tests the result of the template for simple cases.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(weights): @@ -86,8 +86,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -112,7 +112,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the weights shape is incorrect.""" n_wires = 1 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(weights): @@ -175,7 +175,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -201,7 +201,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -226,7 +226,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -253,7 +253,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_gate_fabric.py b/tests/templates/test_layers/test_gate_fabric.py index d1eabd5f970..260090f79d1 100644 --- a/tests/templates/test_layers/test_gate_fabric.py +++ b/tests/templates/test_layers/test_gate_fabric.py @@ -479,7 +479,7 @@ def test_decomposition_q(self, init_state, exp_state, tol): weight = [[[np.pi / 2, np.pi / 2]]] - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) @qml.qnode(dev) def circuit(weight): @@ -599,7 +599,7 @@ def test_layers_gate_fabric(self, num_qubits, layers, exp_state, tol): shape = qml.GateFabric.shape(n_layers=layers, n_wires=num_qubits) weight = np.pi / 2 * qml.math.ones(shape) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) init_state = qml.math.array([1 if x < num_qubits // 2 else 0 for x in wires]) @@ -617,8 +617,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 1, 2)) init_state = qml.math.array([1, 1, 0, 0]) - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "r"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "r"]) @qml.qnode(dev) def circuit(): @@ -697,7 +697,7 @@ def test_exceptions(self, weights, wires, msg_match): N = len(wires) init_state = qml.math.array([1, 1, 0, 0]) - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) @qml.qnode(dev) def circuit(): @@ -783,7 +783,7 @@ def test_autograd(self, tol): weights = pnp.random.random(size=(1, 1, 2), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -809,7 +809,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -834,7 +834,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -861,7 +861,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 1, 2)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_particle_conserving_u1.py b/tests/templates/test_layers/test_particle_conserving_u1.py index 87baee98285..15fd62056d3 100644 --- a/tests/templates/test_layers/test_particle_conserving_u1.py +++ b/tests/templates/test_layers/test_particle_conserving_u1.py @@ -128,8 +128,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 2, 2)) init_state = np.array([1, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -193,7 +193,7 @@ def test_decomposition_u1ex(self, init_state, exp_state, tol): wires = range(N) weights = np.array([[[0.2045368, -0.6031732]]]) - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) @qml.qnode(dev) def circuit(weights): @@ -227,7 +227,7 @@ def test_exceptions(self, weights, n_wires, msg_match): wires = range(n_wires) init_state = np.array([1, 1, 0, 0]) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -306,7 +306,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 1, 2)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -332,7 +332,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -357,7 +357,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 1, 2))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -384,7 +384,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 1, 2)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_particle_conserving_u2.py b/tests/templates/test_layers/test_particle_conserving_u2.py index 570489ca026..163aa458484 100644 --- a/tests/templates/test_layers/test_particle_conserving_u2.py +++ b/tests/templates/test_layers/test_particle_conserving_u2.py @@ -105,7 +105,7 @@ def test_decomposition_u2ex(self, init_state, exp_state, tol): weight = 0.53141 - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) @qml.qnode(dev) def circuit(weight): @@ -122,8 +122,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 5)) init_state = np.array([1, 1, 0]) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -180,7 +180,7 @@ def test_exceptions(self, weights, wires, msg_match): N = len(wires) init_state = np.array([1, 1, 0, 0]) - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) @qml.qnode(dev) def circuit(): @@ -253,7 +253,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -279,7 +279,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -304,7 +304,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -331,7 +331,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_random.py b/tests/templates/test_layers/test_random.py index 9033d3886e4..74f3bce355a 100644 --- a/tests/templates/test_layers/test_random.py +++ b/tests/templates/test_layers/test_random.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -164,7 +164,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def circuit(phi): @@ -241,7 +241,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -267,7 +267,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -292,7 +292,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -319,7 +319,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_simplified_twodesign.py b/tests/templates/test_layers/test_simplified_twodesign.py index 9cddcbb3c85..7d0c8edb7eb 100644 --- a/tests/templates/test_layers/test_simplified_twodesign.py +++ b/tests/templates/test_layers/test_simplified_twodesign.py @@ -97,7 +97,7 @@ def test_circuit_parameters(self, n_wires, n_layers, shape_weights): ) def test_correct_target_output(self, initial_layer_weights, weights, n_wires, target, tol): """Tests the result of the template for simple cases.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(initial_layer, weights): @@ -115,8 +115,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 2, 2)) initial_layer = np.random.randn(3) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -141,7 +141,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) initial_layer = np.random.randn(2) @qml.qnode(dev) @@ -222,7 +222,7 @@ def test_autograd(self, tol): initial_weights = np.random.random(size=(3,)) initial_weights = pnp.array(initial_weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -250,7 +250,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 2, 2))) initial_weights = jnp.array(np.random.random(size=(3,))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -277,7 +277,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 2, 2))) initial_weights = tf.Variable(np.random.random(size=(3,))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -306,7 +306,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 2, 2)), requires_grad=True) initial_weights = torch.tensor(np.random.random(size=(3,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_strongly_entangling.py b/tests/templates/test_layers/test_strongly_entangling.py index 2ced6729675..4569a724a35 100644 --- a/tests/templates/test_layers/test_strongly_entangling.py +++ b/tests/templates/test_layers/test_strongly_entangling.py @@ -70,8 +70,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3, 3)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -119,7 +119,7 @@ def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(weights, ranges=None): @@ -142,7 +142,7 @@ def test_exception_wrong_ranges(self): """Verifies that exception is raised if the value of ranges is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(weights, ranges=None): @@ -203,7 +203,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(1, 3, 3)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -229,7 +229,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 3, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -254,7 +254,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 3, 3))) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -281,7 +281,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 3, 3)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) 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 b9d5e39f1c4..d96bf25f69a 100644 --- a/tests/templates/test_state_preparations/test_arbitrary_state_prep.py +++ b/tests/templates/test_state_preparations/test_arbitrary_state_prep.py @@ -157,8 +157,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(2**4 - 2)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -182,7 +182,7 @@ class TestInputs: def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def circuit(weights): @@ -243,7 +243,7 @@ def test_list_and_tuples(self, tol): weights = [1] * 6 - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -265,7 +265,7 @@ def test_autograd(self, tol): weights = np.random.random(size=(6,)) weights = pnp.array(weights, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -291,7 +291,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(6,))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -316,7 +316,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(6,))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -343,7 +343,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(6,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) 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 29630b791dc..5819f867e2c 100644 --- a/tests/templates/test_state_preparations/test_basis_state_prep.py +++ b/tests/templates/test_state_preparations/test_basis_state_prep.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" basis_state = [0, 1, 0] - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -189,7 +189,7 @@ def test_error_basis_state_format(self, basis_state, wires): def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(basis_state): 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 bda0d1db038..6548e44464e 100644 --- a/tests/templates/test_state_preparations/test_mottonen_state_prep.py +++ b/tests/templates/test_state_preparations/test_mottonen_state_prep.py @@ -244,7 +244,7 @@ def test_RZ_skipped(self, mocker, state_vector, n_wires): n_CNOT = 2**n_wires - 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev, interface="autograd") def circuit(state_vector): @@ -262,8 +262,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" state = np.array([1 / 2, 1 / 2, 0, 1 / 2, 0, 1 / 2, 0, 0]) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -348,7 +348,7 @@ class TestGradient: def test_gradient_evaluated(self, state_vector): """Test that the gradient is successfully calculated for a simple example. This test only checks that the gradient is calculated without an error.""" - dev = qml.device("default.qubit.legacy", wires=1) + dev = qml.device("default.qubit", wires=1) @qml.qnode(dev) def circuit(state_vector): @@ -378,7 +378,7 @@ def test_jax(self, inputs, expected): from jax import numpy as jnp inputs = jnp.array(inputs) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(inputs): @@ -396,7 +396,7 @@ def test_jax_jit(self, inputs, expected): from jax import numpy as jnp inputs = jnp.array(inputs) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @jax.jit @qml.qnode(dev) @@ -414,7 +414,7 @@ def test_tensorflow(self, inputs, expected): import tensorflow as tf inputs = tf.Variable(inputs) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(inputs): @@ -431,7 +431,7 @@ def test_torch(self, inputs, expected): import torch inputs = torch.tensor(inputs, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(inputs): diff --git a/tests/templates/test_subroutines/test_all_singles_doubles.py b/tests/templates/test_subroutines/test_all_singles_doubles.py index 733c55d1942..cb37e63cd7a 100644 --- a/tests/templates/test_subroutines/test_all_singles_doubles.py +++ b/tests/templates/test_subroutines/test_all_singles_doubles.py @@ -108,8 +108,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = [0.1, 0.2] - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -249,7 +249,7 @@ def test_allsinglesdoubles_exceptions( """Test that AllSinglesDoubles throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) def circuit( weights=weights, wires=wires, hf_state=hf_state, singles=singles, doubles=doubles @@ -334,7 +334,7 @@ def test_list_and_tuples(self, tol): weights = list(range(2)) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -349,7 +349,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -374,7 +374,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(2,))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -398,7 +398,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(2,))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -425,7 +425,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_approx_time_evolution.py b/tests/templates/test_subroutines/test_approx_time_evolution.py index 9ce75bd7242..5bb5f055b06 100644 --- a/tests/templates/test_subroutines/test_approx_time_evolution.py +++ b/tests/templates/test_subroutines/test_approx_time_evolution.py @@ -144,7 +144,7 @@ def test_evolution_output(self, time, hamiltonian, steps, expectation): """Tests that the output from the ApproxTimeEvolution template is correct""" n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -160,8 +160,8 @@ def test_custom_wire_labels(self, tol): [1, 1, 1], [qml.PauliX("z"), qml.PauliX("a"), qml.PauliX("k")] ) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -186,7 +186,7 @@ def test_hamiltonian_error(self): """Tests if the correct error is thrown when hamiltonian is not a pennylane.Hamiltonian object""" n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) hamiltonian = np.array([[1, 1], [1, 1]]) @@ -212,7 +212,7 @@ def test_non_pauli_error(self, hamiltonian): """Tests if the correct errors are thrown when the user attempts to input a matrix with non-Pauli terms""" n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): @@ -271,7 +271,7 @@ def test_float(self, tol): time = 0.5 - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -286,7 +286,7 @@ def test_autograd(self, tol): time = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -312,7 +312,7 @@ def test_jax(self, tol): time = jnp.array(0.5) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -337,7 +337,7 @@ def test_tf(self, tol): time = tf.Variable(0.5) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -364,7 +364,7 @@ def test_torch(self, tol): time = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -388,7 +388,7 @@ def test_torch(self, tol): @pytest.mark.autograd @pytest.mark.parametrize( "dev_name,diff_method", - [["default.qubit.autograd", "backprop"], ["default.qubit.legacy", qml.gradients.param_shift]], + [["default.qubit.autograd", "backprop"], ["default.qubit", qml.gradients.param_shift]], ) def test_trainable_hamiltonian(dev_name, diff_method): """Test that the ApproxTimeEvolution template @@ -410,7 +410,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 d3ded0e0a07..afb45087a42 100644 --- a/tests/templates/test_subroutines/test_arbitrary_unitary.py +++ b/tests/templates/test_subroutines/test_arbitrary_unitary.py @@ -152,8 +152,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(63,)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): @@ -177,7 +177,7 @@ class TestInputs: def test_exception_wrong_dim(self): """Verifies that exception is raised if the number of dimensions of features is incorrect.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) def circuit(weights): @@ -237,7 +237,7 @@ def test_list_and_tuples(self, tol): weights = list(range(15)) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -252,7 +252,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(15,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -277,7 +277,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(15,))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -301,7 +301,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(15,))) - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -328,7 +328,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(15,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_basis_rotation.py b/tests/templates/test_subroutines/test_basis_rotation.py index 5f833c5279b..b980ae12fbd 100644 --- a/tests/templates/test_subroutines/test_basis_rotation.py +++ b/tests/templates/test_subroutines/test_basis_rotation.py @@ -91,8 +91,8 @@ def test_custom_wire_labels(self, tol): ] ) - dev = qml.device("default.qubit.legacy", wires=2) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a"]) + dev = qml.device("default.qubit", wires=2) + dev2 = qml.device("default.qubit", wires=["z", "a"]) @qml.qnode(dev) def circuit(): @@ -236,7 +236,7 @@ def test_basis_rotation_unitary(self, unitary_matrix, eigen_values, exp_state): """Test that the BasisRotation template works correctly asserting the prepared state.""" wires = range(len(unitary_matrix)) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(): @@ -289,7 +289,7 @@ def test_basis_rotation_exceptions(self, wires, unitary_matrix, msg_match): """Test that BasisRotation template throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -372,7 +372,7 @@ def test_autograd(self, tol): ] ) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -414,7 +414,7 @@ def test_jax(self, tol): ] ) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -502,7 +502,7 @@ def test_torch(self, tol): requires_grad=False, ) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_commuting_evolution.py b/tests/templates/test_subroutines/test_commuting_evolution.py index edde44dc6f8..7cb8c22c02a 100644 --- a/tests/templates/test_subroutines/test_commuting_evolution.py +++ b/tests/templates/test_subroutines/test_commuting_evolution.py @@ -47,8 +47,8 @@ def test_adjoint(): """Tests the CommutingEvolution.adjoint method provides the correct adjoint operation.""" n_wires = 2 - dev1 = qml.device("default.qubit.legacy", wires=n_wires) - dev2 = qml.device("default.qubit.legacy", wires=n_wires) + dev1 = qml.device("default.qubit", wires=n_wires) + dev2 = qml.device("default.qubit", wires=n_wires) obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] coeffs = [1, -1] @@ -110,7 +110,7 @@ def test_matrix(): def test_forward_execution(): """Compare the foward execution to an exactly known result.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) H = qml.PauliX(0) @ qml.PauliY(1) - 1.0 * qml.PauliY(0) @ qml.PauliX(1) freq = (2, 4) @@ -147,7 +147,7 @@ def test_two_term_case(self): finite difference result for a two term shift rule case.""" n_wires = 1 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) hamiltonian = qml.Hamiltonian([1], [qml.PauliX(0)]) frequencies = (2,) @@ -172,7 +172,7 @@ def test_four_term_case(self): finite difference result for a four term shift rule case.""" n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) coeffs = [1, -1] obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] @@ -197,7 +197,7 @@ def test_differentiable_hamiltonian(self): """Tests correct gradients are produced when the Hamiltonian is differentiable.""" n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)] diff_coeffs = np.array([1.0, -1.0], requires_grad=True) frequencies = (2, 4) diff --git a/tests/templates/test_subroutines/test_double_excitation.py b/tests/templates/test_subroutines/test_double_excitation.py index 8e0a29b12cc..76768b9a1fe 100644 --- a/tests/templates/test_subroutines/test_double_excitation.py +++ b/tests/templates/test_subroutines/test_double_excitation.py @@ -236,8 +236,8 @@ def test_double_ex_unitary_operations(self, wires1, wires2, ref_gates): def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" - dev = qml.device("default.qubit.legacy", wires=5) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "t", "s"]) + dev = qml.device("default.qubit", wires=5) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "t", "s"]) @qml.qnode(dev) def circuit(): @@ -270,7 +270,7 @@ class TestInputs: def test_double_excitation_unitary_exceptions(self, weight, wires1, wires2, msg_match): """Test exception if ``weight`` or ``pphh`` parameter has illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=10) + dev = qml.device("default.qubit", wires=10) def circuit(weight): qml.FermionicDoubleExcitation(weight=weight, wires1=wires1, wires2=wires2) @@ -302,7 +302,7 @@ def test_autograd(self): weight = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -323,7 +323,7 @@ def test_jax(self): import jax.numpy as jnp weight = jnp.array(0.5) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -340,7 +340,7 @@ def test_tf(self): import tensorflow as tf weight = tf.Variable(0.5) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -360,7 +360,7 @@ def test_torch(self): weight = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) diff --git a/tests/templates/test_subroutines/test_flip_sign.py b/tests/templates/test_subroutines/test_flip_sign.py index 55002a8f604..b8170167975 100644 --- a/tests/templates/test_subroutines/test_flip_sign.py +++ b/tests/templates/test_subroutines/test_flip_sign.py @@ -66,7 +66,7 @@ def test_eval(self, n_status, n_wires): n_wires = 1 if n_wires == 0 else n_wires n_wires = list(range(n_wires)) - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit(): diff --git a/tests/templates/test_subroutines/test_grover.py b/tests/templates/test_subroutines/test_grover.py index 6dff4314aa0..bc2f0dce0fd 100644 --- a/tests/templates/test_subroutines/test_grover.py +++ b/tests/templates/test_subroutines/test_grover.py @@ -152,7 +152,7 @@ def oracle(): qml.Toffoli(wires=wires) qml.Hadamard(wires[-1]) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def GroverSearch(num_iterations=1): @@ -205,7 +205,7 @@ def test_findstate(n_wires): """Asserts can find state marked by oracle, with operation full matrix and decomposition.""" wires = list(range(n_wires)) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circ(): diff --git a/tests/templates/test_subroutines/test_kupccgsd.py b/tests/templates/test_subroutines/test_kupccgsd.py index 87d959aaa64..0343cb4d34f 100644 --- a/tests/templates/test_subroutines/test_kupccgsd.py +++ b/tests/templates/test_subroutines/test_kupccgsd.py @@ -125,8 +125,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -247,7 +247,7 @@ def test_k_layers_upccgsd(self, num_qubits, k, exp_state, tol): shape = qml.kUpCCGSD.shape(k=k, n_wires=num_qubits, delta_sz=0) weight = np.pi / 2 * qml.math.ones(shape) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) init_state = qml.math.array([1 if x < num_qubits // 2 else 0 for x in wires]) @@ -446,7 +446,7 @@ def test_kupccgsd_exceptions(self, wires, weights, k, delta_sz, init_state, msg_ """Test that k-UpCCGSD throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -539,7 +539,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol): """Test common iterables as inputs.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -561,7 +561,7 @@ def test_autograd(self, tol): weights = qml.numpy.random.random(size=(1, 6), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -587,7 +587,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=(1, 6))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -612,7 +612,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=(1, 6))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -639,7 +639,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(1, 6)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -665,7 +665,7 @@ class TestGradient: def test_ps_rule_gradient(self, tol): """Test parameter-shift rule gradient.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) backprop_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="backprop")) ps_rule_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="parameter-shift")) diff --git a/tests/templates/test_subroutines/test_permute.py b/tests/templates/test_subroutines/test_permute.py index 4868cd08c82..08f240d82e3 100644 --- a/tests/templates/test_subroutines/test_permute.py +++ b/tests/templates/test_subroutines/test_permute.py @@ -26,7 +26,7 @@ class TestDecomposition: def test_identity_permutation_qnode(self, mocker): """Test that identity permutations have no effect on QNodes.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev, interface="autograd") def identity_permutation(): @@ -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 @@ -66,7 +66,7 @@ def test_identity_permutation_tape(self): def test_two_cycle_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test some two-cycles on QNodes.""" - dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) + dev = qml.device("default.qubit", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def two_cycle(): @@ -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 @@ -120,7 +120,7 @@ def test_two_cycle_permutations_tape(self, permutation_order, wire_order, expect def test_cyclic_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test more general cycles on QNodes.""" - dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) + dev = qml.device("default.qubit", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def cycle(): @@ -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 @@ -170,7 +170,7 @@ def test_cyclic_permutations_tape(self, permutation_order, wire_order, expected_ def test_arbitrary_permutations_qnode(self, mocker, permutation_order, expected_wires): """Test arbitrarily generated permutations on QNodes.""" - dev = qml.device("default.qubit.legacy", wires=len(permutation_order)) + dev = qml.device("default.qubit", wires=len(permutation_order)) @qml.qnode(dev, interface="autograd") def arbitrary_perm(): @@ -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 @@ -230,7 +230,7 @@ def test_subset_permutations_qnode( ): """Test permutation of wire subsets on QNodes.""" - dev = qml.device("default.qubit.legacy", wires=num_wires) + dev = qml.device("default.qubit", wires=num_wires) @qml.qnode(dev, interface="autograd") def subset_perm(): @@ -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 @@ -284,23 +284,24 @@ def test_custom_wire_labels(self, tol): permutation = [3, 0, 2, 1] permutation2 = ["o", "z", "k", "a"] - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "o"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "o"]) @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: @@ -318,7 +319,7 @@ class TestInputs: def test_invalid_inputs_qnodes(self, permutation_order, expected_error_message): """Tests if errors are thrown for invalid permutations with QNodes.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) @qml.qnode(dev) def permute_qubits(): diff --git a/tests/templates/test_subroutines/test_qft.py b/tests/templates/test_subroutines/test_qft.py index bbea8a3b18a..9e17377f215 100644 --- a/tests/templates/test_subroutines/test_qft.py +++ b/tests/templates/test_subroutines/test_qft.py @@ -38,14 +38,13 @@ def test_QFT_decomposition(self, n_qubits): op = qml.QFT(wires=range(n_qubits)) decomp = op.decomposition() - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=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() @@ -57,7 +56,7 @@ def test_QFT_adjoint_identity(self, n_qubits, tol): """Test if using the qml.adjoint transform the resulting operation is the inverse of QFT.""" - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) @qml.qnode(dev) def circ(n_qubits): diff --git a/tests/templates/test_subroutines/test_qmc.py b/tests/templates/test_subroutines/test_qmc.py index 8dcd83f643d..8cb4a01928c 100644 --- a/tests/templates/test_subroutines/test_qmc.py +++ b/tests/templates/test_subroutines/test_qmc.py @@ -141,7 +141,7 @@ def test_example_with_pl(self): r = func_to_unitary(func, M) - dev = qml.device("default.qubit.legacy", wires=(wires + 1)) + dev = qml.device("default.qubit", wires=(wires + 1)) @qml.qnode(dev) def apply_r(input_state): @@ -361,7 +361,7 @@ def test_expected_value(self): target_wires = range(m + 1) estimation_wires = range(m + 1, n + m + 1) - dev = qml.device("default.qubit.legacy", wires=(n + m + 1)) + dev = qml.device("default.qubit", wires=(n + m + 1)) @qml.qnode(dev) def circuit(): @@ -411,7 +411,7 @@ def test_expected_value_jax_jit(self): target_wires = range(m + 1) estimation_wires = range(m + 1, n + m + 1) - dev = qml.device("default.qubit.legacy", wires=(n + m + 1)) + dev = qml.device("default.qubit", wires=(n + m + 1)) @jax.jit @qml.qnode(dev, interface="jax") @@ -455,7 +455,7 @@ def test_expected_value_custom_wires(self): target_wires = [0, "a", -1.1, -10, "bbb", 1000] estimation_wires = ["bob", -3, 42, "penny", "lane", 247, "straw", "berry", 5.5, 6.6] - dev = qml.device("default.qubit.legacy", wires=target_wires + estimation_wires) + dev = qml.device("default.qubit", wires=target_wires + estimation_wires) @qml.qnode(dev) def circuit(): diff --git a/tests/templates/test_subroutines/test_qpe.py b/tests/templates/test_subroutines/test_qpe.py index 67aba0797d5..06354012851 100644 --- a/tests/templates/test_subroutines/test_qpe.py +++ b/tests/templates/test_subroutines/test_qpe.py @@ -84,7 +84,7 @@ def test_phase_estimated(self, phase): wire_range = range(2, 10) for wires in wire_range: - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) m = qml.RX(phase, wires=0).matrix() target_wires = [0] estimation_wires = range(1, wires) @@ -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(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 @@ -135,7 +136,7 @@ def test_phase_estimated_two_qubit(self): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) target_wires = [0, 1] estimation_wires = range(2, wires) @@ -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(tape) + assert len(tapes) == 1 + res = dev.execute(tapes)[0].flatten() if phase < 0: estimate = np.argmax(res) / 2 ** (wires - 2) - 1 @@ -184,7 +186,7 @@ def test_phase_estimated_single_ops(self, param): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) estimation_wires = range(1, wires - 1) target_wires = [0] @@ -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(tape) + res = dev.execute(tapes)[0].flatten() + assert len(tapes) == 1 estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) @@ -225,7 +228,7 @@ def test_phase_estimated_ops(self, param): wire_range = range(3, 11) for wires in wire_range: - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) # Offset the index of target wires to test the wire maÏp estimation_wires = range(2, wires) @@ -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(tape) + assert len(tapes) == 1 + res = dev.execute(tapes)[0].flatten() estimate = np.argmax(res) / 2 ** (wires - 2) estimates.append(estimate) @@ -300,7 +304,7 @@ def test_map_wires(self): def test_adjoint(self): """Test that the QPE adjoint works.""" - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) def qpe_circuit(): diff --git a/tests/templates/test_subroutines/test_qsvt.py b/tests/templates/test_subroutines/test_qsvt.py index bdffcfe2186..841ef3d8d64 100644 --- a/tests/templates/test_subroutines/test_qsvt.py +++ b/tests/templates/test_subroutines/test_qsvt.py @@ -98,7 +98,7 @@ def test_init_error(self): ) def test_output(self, U_A, lst_projectors, wires, operations): """Test that qml.QSVT produces the intended measurements.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -289,7 +289,7 @@ def test_QSVT_tensorflow(self, input_matrix, angles, wires): def test_QSVT_grad(self, A, phis): """Test that qml.grad results are the same as finite difference results""" - @qml.qnode(qml.device("default.qubit.legacy", wires=2)) + @qml.qnode(qml.device("default.qubit", wires=2)) def circuit(A, phis): qml.QSVT( qml.BlockEncode(A, wires=[0, 1]), @@ -361,7 +361,7 @@ class Testqsvt: ) def test_output(self, A, phis, wires, true_mat): """Test that qml.qsvt produces the correct output.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -399,7 +399,7 @@ def circuit(): ) def test_output_wx(self, A, phis, wires, result): """Test that qml.qsvt produces the correct output.""" - dev = qml.device("default.qubit.legacy", wires=len(wires)) + dev = qml.device("default.qubit", wires=len(wires)) @qml.qnode(dev) def circuit(): @@ -499,7 +499,7 @@ def test_qsvt_tensorflow(self, input_matrix, angles, wires): def test_qsvt_grad(self): """Test that qml.grad results are the same as finite difference results""" - @qml.qnode(qml.device("default.qubit.legacy", wires=2)) + @qml.qnode(qml.device("default.qubit", wires=2)) def circuit(A, phis): qml.qsvt( A, diff --git a/tests/templates/test_subroutines/test_select.py b/tests/templates/test_subroutines/test_select.py index 97339afac62..dd63047c606 100644 --- a/tests/templates/test_subroutines/test_select.py +++ b/tests/templates/test_subroutines/test_select.py @@ -72,7 +72,7 @@ class TestSelect: ) def test_operation_result(self, ops, control_wires, expected_gates, n_wires): """Test the correctness of the Select template output.""" - dev = qml.device("default.qubit.legacy", wires=n_wires) + dev = qml.device("default.qubit", wires=n_wires) @qml.qnode(dev) def circuit1(): @@ -281,7 +281,7 @@ class TestInterfaces: @pytest.mark.autograd def test_autograd(self): """Tests the autograd interface.""" - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_select = qml.QNode(select_rx_circuit, dev) @@ -302,7 +302,7 @@ def test_tf(self): """Tests the tf interface.""" import tensorflow as tf - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_tf = qml.QNode(select_rx_circuit, dev) @@ -330,7 +330,7 @@ def test_torch(self): """Tests the torch interface.""" import torch - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) circuit_default = qml.QNode(manual_rx_circuit, dev) circuit_torch = qml.QNode(select_rx_circuit, dev) @@ -360,7 +360,7 @@ def test_jax(self): import jax import jax.numpy as jnp - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) input_default = [0.5, 0.2] input_jax = jnp.array(input_default) diff --git a/tests/templates/test_subroutines/test_single_excitation.py b/tests/templates/test_subroutines/test_single_excitation.py index 75e833e889c..76eda25a2b8 100644 --- a/tests/templates/test_subroutines/test_single_excitation.py +++ b/tests/templates/test_subroutines/test_single_excitation.py @@ -112,23 +112,24 @@ def test_single_ex_unitary_operations(self, single_wires, ref_gates): def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @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: @@ -145,7 +146,7 @@ class TestInputs: def test_single_excitation_unitary_exceptions(self, weight, single_wires, msg_match): """Test that FermionicSingleExcitation throws an exception if ``weight`` or ``single_wires`` parameter has illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=5) + dev = qml.device("default.qubit", wires=5) def circuit(weight=weight): qml.FermionicSingleExcitation(weight=weight, wires=single_wires) @@ -177,7 +178,7 @@ def test_autograd(self): weight = pnp.array(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -197,7 +198,7 @@ def test_jax(self): import jax.numpy as jnp weight = jnp.array(0.5) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -214,7 +215,7 @@ def test_tf(self): import tensorflow as tf weight = tf.Variable(0.5) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) @@ -234,7 +235,7 @@ def test_torch(self): weight = torch.tensor(0.5, requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) diff --git a/tests/templates/test_subroutines/test_uccsd.py b/tests/templates/test_subroutines/test_uccsd.py index 700c9239256..e9bbca83147 100644 --- a/tests/templates/test_subroutines/test_uccsd.py +++ b/tests/templates/test_subroutines/test_uccsd.py @@ -213,7 +213,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]), @@ -243,7 +243,7 @@ def test_uccsd_xceptions(self, weights, s_wires, d_wires, init_state, msg_match) shapes, types or values.""" N = 4 wires = range(4) - dev = qml.device("default.qubit.legacy", wires=N) + dev = qml.device("default.qubit", wires=N) def circuit( weights=weights, wires=wires, s_wires=s_wires, d_wires=d_wires, init_state=init_state @@ -308,7 +308,7 @@ def test_list_and_tuples(self, tol): weights = list(range(2)) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -323,7 +323,7 @@ def test_autograd(self, tol): weights = pnp.array(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -349,7 +349,7 @@ def test_jax(self, tol): import jax.numpy as jnp weights = jnp.array(np.random.random(size=(2,))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -373,7 +373,7 @@ def test_tf(self, tol): import tensorflow as tf weights = tf.Variable(np.random.random(size=(2,))) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -400,7 +400,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=(2,)), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_swapnetworks/test_ccl2.py b/tests/templates/test_swapnetworks/test_ccl2.py index b1d9d5bad3a..128c3cfe862 100644 --- a/tests/templates/test_swapnetworks/test_ccl2.py +++ b/tests/templates/test_swapnetworks/test_ccl2.py @@ -110,8 +110,8 @@ def acquaintances(index, *_, **___): weights = np.random.random(size=10) - dev = qml.device("default.qubit.legacy", wires=5) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e", "y"]) + dev = qml.device("default.qubit", wires=5) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e", "y"]) @qml.qnode(dev) def circuit(): @@ -195,7 +195,7 @@ def test_ccl2(self, num_wires, acquaintances, weights, fermionic, shift, exp_sta shape = qml.templates.TwoLocalSwapNetwork.shape(num_wires) weights = np.pi / 2 * qml.math.ones(shape) if weights else None - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(): @@ -253,7 +253,7 @@ def test_ccl2_exceptions(self, wires, acquaintances, weights, fermionic, shift, """Test that TwoLocalSwapNetwork throws an exception if the parameters have illegal shapes, types or values.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(): @@ -338,7 +338,7 @@ class TestInterfaces: def test_list_and_tuples(self, tol): """Test common iterables as inputs.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -360,7 +360,7 @@ def test_autograd(self, tol): weights = qml.numpy.random.random(size=(6), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -386,7 +386,7 @@ def test_jax(self, tol): weights = jnp.array(np.random.random(size=6)) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -411,7 +411,7 @@ def test_tf(self, tol): weights = tf.Variable(np.random.random(size=6)) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -438,7 +438,7 @@ def test_torch(self, tol): weights = torch.tensor(np.random.random(size=6), requires_grad=True) - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) @@ -465,7 +465,7 @@ class TestGradient: def test_ps_rule_gradient(self, tol): """Test parameter-shift rule gradient.""" - dev = qml.device("default.qubit.legacy", wires=4) + dev = qml.device("default.qubit", wires=4) backprop_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="backprop")) ps_rule_grad = qml.grad(qml.QNode(circuit_template, dev, diff_method="parameter-shift")) diff --git a/tests/templates/test_tensornetworks/test_MERA.py b/tests/templates/test_tensornetworks/test_MERA.py index 7718fab17c0..1d293e287f5 100644 --- a/tests/templates/test_tensornetworks/test_MERA.py +++ b/tests/templates/test_tensornetworks/test_MERA.py @@ -341,7 +341,7 @@ def test_exception_wrong_weight_shape( ) def test_block_params(self, block, n_params_block, wires, n_block_wires, template_weights): """Verify that the template works with arbitrary block parameters""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(): @@ -417,7 +417,7 @@ def test_template_differentiable( self, block, n_params_block, wires, n_block_wires, template_weights ): """Test that the template is differentiable for different inputs.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(template_weights): @@ -466,7 +466,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit_template(): diff --git a/tests/templates/test_tensornetworks/test_MPS.py b/tests/templates/test_tensornetworks/test_MPS.py index e4c183dbcaa..9d03571f362 100644 --- a/tests/templates/test_tensornetworks/test_MPS.py +++ b/tests/templates/test_tensornetworks/test_MPS.py @@ -334,7 +334,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) block = getattr(self, block) expected_circuit = getattr(self, expected_circuit) diff --git a/tests/templates/test_tensornetworks/test_TTN.py b/tests/templates/test_tensornetworks/test_TTN.py index fb9575923af..b7a23f703fd 100644 --- a/tests/templates/test_tensornetworks/test_TTN.py +++ b/tests/templates/test_tensornetworks/test_TTN.py @@ -290,7 +290,7 @@ def test_exception_wrong_weight_shape( ) def test_block_params(self, block, n_params_block, wires, n_block_wires, template_weights): """Verify that the template works with arbitrary block parameters""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(): @@ -359,7 +359,7 @@ def test_template_differentiable( self, block, n_params_block, wires, n_block_wires, template_weights ): """Test that the template is differentiable for different inputs.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit(template_weights): @@ -402,7 +402,7 @@ def test_output( self, block, n_params_block, wires, n_block_wires, template_weights, expected_circuit ): """Verifies that the output of the circuits is correct.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) @qml.qnode(dev) def circuit_template(): From a79fb06b00aae166114ed33ab601d2bc765384ab Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 14:44:19 -0400 Subject: [PATCH 31/78] fix templates --- .../test_embeddings/test_amplitude.py | 21 +++++++++---------- tests/templates/test_embeddings/test_angle.py | 11 +++++----- tests/templates/test_embeddings/test_basis.py | 11 +++++----- .../templates/test_embeddings/test_iqp_emb.py | 11 +++++----- .../test_embeddings/test_qaoa_emb.py | 11 +++++----- .../test_layers/test_basic_entangler.py | 11 +++++----- .../templates/test_layers/test_gate_fabric.py | 21 ++++++++----------- .../test_particle_conserving_u1.py | 17 +++++++-------- .../test_particle_conserving_u2.py | 17 +++++++-------- tests/templates/test_layers/test_random.py | 4 ++-- .../test_layers/test_simplified_twodesign.py | 11 +++++----- .../test_layers/test_strongly_entangling.py | 11 +++++----- .../test_arbitrary_state_prep.py | 11 +++++----- .../test_basis_state_prep.py | 4 ++-- .../test_mottonen_state_prep.py | 13 ++++++------ .../test_all_singles_doubles.py | 13 ++++++------ .../test_approx_time_evolution.py | 11 +++++----- .../test_arbitrary_unitary.py | 11 +++++----- .../test_subroutines/test_basis_rotation.py | 11 +++++----- .../test_commuting_evolution.py | 18 ++++++++-------- .../test_double_excitation.py | 11 +++++----- .../test_subroutines/test_kupccgsd.py | 8 +++---- 22 files changed, 138 insertions(+), 130 deletions(-) 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 39085c967ee..5eb16f3d3b3 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 74f3bce355a..1d607c396cb 100644 --- a/tests/templates/test_layers/test_random.py +++ b/tests/templates/test_layers/test_random.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): 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..86b8c9e6339 100644 --- a/tests/templates/test_state_preparations/test_arbitrary_state_prep.py +++ b/tests/templates/test_state_preparations/test_arbitrary_state_prep.py @@ -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..d953a222a1d 100644 --- a/tests/templates/test_state_preparations/test_basis_state_prep.py +++ b/tests/templates/test_state_preparations/test_basis_state_prep.py @@ -138,8 +138,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" basis_state = [0, 1, 0] - dev = qml.device("default.qubit", wires=3) - dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) + dev = qml.device("default.qubit.legacy", wires=3) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) @qml.qnode(dev) def circuit(): 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..a845f9fcd7c 100644 --- a/tests/templates/test_state_preparations/test_mottonen_state_prep.py +++ b/tests/templates/test_state_preparations/test_mottonen_state_prep.py @@ -254,7 +254,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 +268,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 5bb5f055b06..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: 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 b980ae12fbd..2203196ec33 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..3a8786876c1 100644 --- a/tests/templates/test_subroutines/test_kupccgsd.py +++ b/tests/templates/test_subroutines/test_kupccgsd.py @@ -125,8 +125,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) - dev = qml.device("default.qubit", wires=4) - dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit.legacy", wires=4) + dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -256,9 +256,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"), From 54f38dd12d3c6ddb60499c05dbcaec4a6a6b0201 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 16:15:42 -0400 Subject: [PATCH 32/78] more test fixes --- pennylane/devices/qubit/measure.py | 2 +- tests/devices/test_default_qubit_legacy.py | 6 ++-- .../test_default_qubit_legacy_broadcasting.py | 4 +-- tests/docs/test_supported_confs.py | 12 +++---- tests/logging/test_logging_autograd.py | 34 +++++++++---------- tests/qchem/test_dipole.py | 4 ++- tests/test_device.py | 2 +- tests/test_qnode.py | 2 +- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pennylane/devices/qubit/measure.py b/pennylane/devices/qubit/measure.py index e30a0c809b0..a30552d2199 100644 --- a/pennylane/devices/qubit/measure.py +++ b/pennylane/devices/qubit/measure.py @@ -135,7 +135,7 @@ def get_measurement_function( if measurementprocess.obs.name == "SparseHamiltonian": return csr_dot_products - backprop_mode = math.get_interface(state) != "numpy" + backprop_mode = math.get_interface(state, *measurementprocess.obs.data) != "numpy" if isinstance(measurementprocess.obs, Hamiltonian): # need to work out thresholds for when its faster to use "backprop mode" measurements return sum_of_terms_method if backprop_mode else csr_dot_products diff --git a/tests/devices/test_default_qubit_legacy.py b/tests/devices/test_default_qubit_legacy.py index aa69671ae5d..b9b20ab11c0 100644 --- a/tests/devices/test_default_qubit_legacy.py +++ b/tests/devices/test_default_qubit_legacy.py @@ -626,7 +626,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( @@ -647,7 +647,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( @@ -2074,7 +2074,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 594a228cd05..1d6b29a27d1 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/docs/test_supported_confs.py b/tests/docs/test_supported_confs.py index b8d83a0d72f..3d8ffe43861 100644 --- a/tests/docs/test_supported_confs.py +++ b/tests/docs/test_supported_confs.py @@ -15,7 +15,7 @@ match the supported configurations in the code. A configuration is specified by: - 1. The quantum device, e.g. "default.qubit" + 1. The quantum device, e.g. "default.qubit.legacy" 2. The interface, e.g. "jax" 3. The differentiation method, e.g. "parameter-shift" 4. The return value of the QNode, e.g. qml.expval() or qml.probs() @@ -47,7 +47,7 @@ jax = pytest.importorskip("jax") jnp = pytest.importorskip("jax.numpy") -devices = ["default.qubit"] +devices = ["default.qubit.legacy"] interfaces = [None, "autograd", "jax", "tf", "torch"] diff_interfaces = ["autograd", "jax", "tf", "torch"] shots_list = [None, 100] @@ -113,7 +113,7 @@ def get_qnode(interface, diff_method, return_type, shots, wire_specs): """ device_wires, wire_labels, single_meas_wire, multi_meas_wire = wire_specs - dev = qml.device("default.qubit", wires=device_wires, shots=shots) + dev = qml.device("default.qubit.legacy", wires=device_wires, shots=shots) # pylint: disable=too-many-return-statements @qml.qnode(dev, interface=interface, diff_method=diff_method) @@ -264,9 +264,9 @@ class TestSupportedConfs: @pytest.mark.parametrize("shots", shots_list) @pytest.mark.parametrize("wire_specs", wire_specs_list) def test_all_device(self, interface, return_type, shots, wire_specs): - """Test diff_method=device raises an error for all interfaces for default.qubit""" + """Test diff_method=device raises an error for all interfaces for default.qubit.legacy""" msg = ( - "The default.qubit device does not provide a native " + "The default.qubit.legacy device does not provide a native " "method for computing the jacobian." ) @@ -278,7 +278,7 @@ def test_all_device(self, interface, return_type, shots, wire_specs): 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 " + "Device default.qubit.legacy only supports diff_method='backprop' when " "using the ['tf', 'torch', 'autograd', 'jax'] interfaces." ) msg = re.escape(msg) diff --git a/tests/logging/test_logging_autograd.py b/tests/logging/test_logging_autograd.py index 3ea8adfddc7..a325a578f42 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/qchem/test_dipole.py b/tests/qchem/test_dipole.py index 42e249b89a6..2db22f4500b 100644 --- a/tests/qchem/test_dipole.py +++ b/tests/qchem/test_dipole.py @@ -329,7 +329,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/test_device.py b/tests/test_device.py index 7a7f303fea3..4b853f29718 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -946,7 +946,7 @@ def test_outdated_API(self, monkeypatch): with monkeypatch.context() as m: m.setattr(qml, "version", lambda: "0.0.1") with pytest.raises(DeviceError, match="plugin requires PennyLane versions"): - qml.device("default.qubit", wires=0) + qml.device("default.qubit.legacy", wires=0) @pytest.mark.skip(reason="Reloading PennyLane messes with tape mode") def test_refresh_entrypoints(self, monkeypatch): diff --git a/tests/test_qnode.py b/tests/test_qnode.py index 8f0701a3f20..bc18db7a408 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -534,7 +534,7 @@ def func(x): assert ( repr(qn) - == "" + == "" ) qn = QNode(func, dev, interface="autograd") From 2a800d0ce3c3d511fafd9db7dbd05c9368d654b9 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 16:34:32 -0400 Subject: [PATCH 33/78] fix test with nonsense observable --- tests/ops/op_math/test_sum.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ops/op_math/test_sum.py b/tests/ops/op_math/test_sum.py index 102021e1cd5..719bedd38e3 100644 --- a/tests/ops/op_math/test_sum.py +++ b/tests/ops/op_math/test_sum.py @@ -1081,10 +1081,11 @@ def test_params_can_be_considered_trainable(self): @qml.qnode(dev, interface=None) def circuit(): - return qml.expval(Sum(qml.RX(1.1, 0), qml.RY(qnp.array(2.2), 0))) + return qml.expval( + Sum(qml.s_prod(1.1, qml.PauliX(0)), qml.s_prod(qnp.array(2.2), qml.PauliY(1))) + ) - with pytest.warns(UserWarning): - circuit() + circuit() assert circuit.tape.trainable_params == [1] From 6d3da6edcd776ddfde5b9b3a47228f841b635470 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 25 Aug 2023 17:41:22 -0400 Subject: [PATCH 34/78] slight additional test coverage --- .../gradients/core/test_gradient_transform.py | 2 +- .../transforms/test_adjoint_metric_tensor.py | 27 +++++++++++-------- .../test_merge_amplitude_embedding.py | 1 - 3 files changed, 17 insertions(+), 13 deletions(-) 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/transforms/test_adjoint_metric_tensor.py b/tests/transforms/test_adjoint_metric_tensor.py index f4c37be342f..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.experimental.DefaultQubit2() + 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_optimization/test_merge_amplitude_embedding.py b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py index 563de73daa3..935def9795b 100644 --- a/tests/transforms/test_optimization/test_merge_amplitude_embedding.py +++ b/tests/transforms/test_optimization/test_merge_amplitude_embedding.py @@ -44,7 +44,6 @@ def qfunc(): dev = qml.device("default.qubit", wires=2) assert np.allclose(qml.QNode(transformed_qfunc, dev)()[-1], 1) - @pytest.mark.xfail(reason="fails earlier because the operator inherits from StatePrep") def test_repeated_qubit(self): """Check that AmplitudeEmbedding cannot be applied if the qubit has already been used.""" From 519a96b6e1b2c7d8825db769ca190c07fbf998c0 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Sat, 26 Aug 2023 13:45:51 -0400 Subject: [PATCH 35/78] use old device for now on torch qcut test --- tests/transforms/test_qcut.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/transforms/test_qcut.py b/tests/transforms/test_qcut.py index 5ead4d26312..31652a0ed9c 100644 --- a/tests/transforms/test_qcut.py +++ b/tests/transforms/test_qcut.py @@ -4021,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): From 6f9e33b23ecf712db9dea8f376a702a09acddad7 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 29 Aug 2023 15:47:09 -0400 Subject: [PATCH 36/78] change some tests to use DQ2 --- .../test_arbitrary_state_prep.py | 20 +- .../test_basis_state_prep.py | 16 +- .../test_mottonen_state_prep.py | 32 +- tests/test_return_types_qnode.py | 338 +++++++++++++----- 4 files changed, 291 insertions(+), 115 deletions(-) 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 86b8c9e6339..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.""" 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 d953a222a1d..7b66b11b0d1 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) 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 a845f9fcd7c..16fa2273e9e 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")) 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")) 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 diff --git a/tests/test_return_types_qnode.py b/tests/test_return_types_qnode.py index 3e7a2de8394..3074c3fa7a5 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -20,7 +20,7 @@ import pennylane as qml test_wires = [2, 3, 4] -devices = ["default.qubit.legacy", "lightning.qubit", "default.mixed", "default.qutrit"] +devices = ["default.qubit", "lightning.qubit", "default.mixed", "default.qutrit"] def qubit_ansatz(x): @@ -40,7 +40,7 @@ class TestIntegrationSingleReturn: @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires): """Return state with default.qubit.""" - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) def circuit(x): qubit_ansatz(x) @@ -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,13 +137,13 @@ 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") def test_vn_entropy_shot_vec_error(self): """Test an error is raised when using shot vectors with vn_entropy.""" - dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -171,13 +171,13 @@ 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") def test_mutual_info_shot_vec_error(self): """Test an error is raised when using shot vectors with mutual_info.""" - dev = qml.device("default.qubit.legacy", wires=2, shots=[1, 10, 10, 1000]) + dev = qml.device("default.qubit", wires=2, shots=[1, 10, 10, 1000]) @qml.qnode(device=dev) def circuit(x): @@ -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,) @@ -486,7 +486,7 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import tensorflow as tf - if device in ["default.mixed", "default.qubit.legacy"]: + if device in ["default.mixed", "default.qubit"]: pytest.skip("Sample need to be rewritten for Tf.") dev = qml.device(device, wires=2, shots=shots) @@ -700,7 +700,7 @@ def test_sample(self, measurement, device, shots=100): """Test the sample measurement.""" import torch - if device in ["default.mixed", "default.qubit.legacy"]: + if device in ["default.mixed", "default.qubit"]: pytest.skip("Sample need to be rewritten for Torch.") dev = qml.device(device, wires=2, shots=shots) @@ -989,7 +989,7 @@ def circuit(x): multi_return_wires = [([0], [1]), ([1], [0]), ([0], [0]), ([1], [1])] -devices = ["default.qubit.legacy", "lightning.qubit", "default.mixed", "default.qutrit"] +devices = ["default.qubit", "lightning.qubit", "default.mixed", "default.qutrit"] class TestIntegrationMultipleReturns: @@ -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]] @@ -1335,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: @@ -1344,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) @@ -1395,9 +1395,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,) @@ -1552,7 +1552,7 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import tensorflow as tf - if device in ["default.mixed", "default.qubit.legacy"]: + if device in ["default.mixed", "default.qubit"]: pytest.skip("Sample must be reworked with interfaces.") dev = qml.device(device, wires=2, shots=shots) @@ -1816,7 +1816,7 @@ def test_expval_sample(self, measurement, device, shots=100): """Test the expval and sample measurements together.""" import torch - if device in ["default.mixed", "default.qubit.legacy"]: + if device in ["default.mixed", "default.qubit"]: pytest.skip("Sample need to be rewritten for interfaces.") dev = qml.device(device, wires=2, shots=shots) @@ -2237,7 +2237,7 @@ def circuit(x): shot_vectors = [[10, 1000], [1, 10, 10, 1000], [1, (10, 2), 1000]] -devices = ["default.qubit.legacy", "default.mixed"] +devices = ["default.qubit", "default.mixed"] @pytest.mark.parametrize("device", devices) @@ -2258,7 +2258,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 @@ -2268,7 +2275,7 @@ def circuit(x): @pytest.mark.parametrize("op,wires", probs_data) def test_probs(self, shot_vector, op, wires, device): """Test a single probability measurement.""" - dev = qml.device("default.qubit.legacy", wires=2, shots=shot_vector) + dev = qml.device("default.qubit", wires=2, shots=shot_vector) def circuit(x): qml.Hadamard(wires=[0]) @@ -2279,7 +2286,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 +2317,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 @@ -2325,7 +2346,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) @@ -2350,7 +2375,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 @@ -2375,7 +2407,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 @@ -2405,7 +2444,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 @@ -2432,7 +2478,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) @@ -2454,7 +2504,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 @@ -2544,12 +2601,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: @@ -2567,7 +2635,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): @@ -2578,12 +2650,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]): @@ -2608,14 +2691,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: @@ -2631,7 +2725,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): @@ -2642,14 +2740,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} @@ -2672,7 +2777,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): @@ -2683,12 +2792,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]): @@ -2705,7 +2825,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] @@ -2724,12 +2848,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]): @@ -2751,7 +2886,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] @@ -2770,12 +2909,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"} @@ -2799,7 +2947,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): @@ -2824,12 +2976,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): @@ -2850,7 +3011,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): @@ -2867,7 +3032,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 @@ -2923,7 +3095,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 @@ -2987,7 +3159,7 @@ def test_multiple_meas_tf_autograph(self, interface): """Return Jacobian of multiple measurements with Tf Autograph.""" import tensorflow as tf - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @tf.function @qml.qnode(dev, interface=interface) @@ -3090,7 +3262,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 @@ -3229,7 +3401,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 From c5cd3f5a881c452e535c4ca907cf6679c9ae03c6 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 31 Aug 2023 15:20:26 -0400 Subject: [PATCH 37/78] test device_batch_transform=False on legacy --- tests/transforms/test_batch_transform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/transforms/test_batch_transform.py b/tests/transforms/test_batch_transform.py index c4dd1e5e09d..eb2d671da38 100644 --- a/tests/transforms/test_batch_transform.py +++ b/tests/transforms/test_batch_transform.py @@ -679,7 +679,7 @@ class TestMapBatchTransform: def test_result(self, mocker): """Test that it correctly applies the transform to be mapped""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) H = qml.PauliZ(0) @ qml.PauliZ(1) - qml.PauliX(0) x = 0.6 y = 0.7 @@ -713,7 +713,7 @@ def test_result(self, mocker): def test_differentiation(self): """Test that an execution using map_batch_transform can be differentiated""" - dev = qml.device("default.qubit", wires=2) + dev = qml.device("default.qubit.legacy", wires=2) H = qml.PauliZ(0) @ qml.PauliZ(1) - qml.PauliX(0) weights = np.array([0.6, 0.8], requires_grad=True) From 736d9df2b3a8a767b89a37d2b99962d0bd1ecdb6 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 31 Aug 2023 15:49:39 -0400 Subject: [PATCH 38/78] move defer_measurements qnode tests to legacy device for now --- tests/test_qnode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_qnode.py b/tests/test_qnode.py index d4fe482a4e9..e6084debc6c 100644 --- a/tests/test_qnode.py +++ b/tests/test_qnode.py @@ -1057,7 +1057,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") @@ -1111,7 +1111,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): From 52eefddc1a15b863c2101488cf2db3ae096f1f70 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 31 Aug 2023 16:45:15 -0400 Subject: [PATCH 39/78] fix numeric_type stuff --- pennylane/interfaces/jax_jit.py | 12 +++--------- pennylane/measurements/sample.py | 2 +- .../test_sample_default_qubit_2.py | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/pennylane/interfaces/jax_jit.py b/pennylane/interfaces/jax_jit.py index 4488b9e1597..b763374ecef 100644 --- a/pennylane/interfaces/jax_jit.py +++ b/pennylane/interfaces/jax_jit.py @@ -29,17 +29,11 @@ Zero = jax.custom_derivatives.SymbolicZero -def _numeric_type_to_dtype(numeric_type, device): +def _numeric_type_to_dtype(numeric_type): """Auxiliary function for converting from Python numeric types to JAX dtypes based on the precision defined for the interface.""" single_precision = dtype is jnp.float32 - if numeric_type is bool: - if isinstance(device, qml.Device): - numeric_type = int - else: - return jnp.bool_ - if numeric_type is int: return jnp.int32 if single_precision else jnp.int64 @@ -67,10 +61,10 @@ def _create_shape_dtype_struct(tape: "qml.tape.QuantumScript", device: "qml.Devi shape = tape.shape(device) if len(tape.measurements) == 1: - tape_dtype = _numeric_type_to_dtype(tape.numeric_type, device) + tape_dtype = _numeric_type_to_dtype(tape.numeric_type) return jax.ShapeDtypeStruct(tuple(shape), tape_dtype) - tape_dtype = tuple(_numeric_type_to_dtype(elem, device) for elem in tape.numeric_type) + tape_dtype = tuple(_numeric_type_to_dtype(elem) for elem in tape.numeric_type) return tuple(jax.ShapeDtypeStruct(tuple(s), d) for s, d in zip(shape, tape_dtype)) diff --git a/pennylane/measurements/sample.py b/pennylane/measurements/sample.py index b5397b01429..c06b60f6d31 100644 --- a/pennylane/measurements/sample.py +++ b/pennylane/measurements/sample.py @@ -144,7 +144,7 @@ def numeric_type(self): # built-in observable with integer eigenvalues or a tensor product thereof if self.obs is None: # Computational basis samples - return bool + return int int_eigval_obs = {qml.PauliX, qml.PauliY, qml.PauliZ, qml.Hadamard, qml.Identity} tensor_terms = self.obs.obs if hasattr(self.obs, "obs") else [self.obs] every_term_standard = all(o.__class__ in int_eigval_obs for o in tensor_terms) diff --git a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py index dba5d5c640b..b5c6dcce21e 100644 --- a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py +++ b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py @@ -234,7 +234,7 @@ def circuit(): "obs,exp", [ # Single observables - (None, bool), # comp basis samples + (None, int), # comp basis samples (qml.PauliX(0), int), (qml.PauliY(0), int), (qml.PauliZ(0), int), From b3d858c84097b79d9e1acfd893d96befcc1fbd50 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 1 Sep 2023 10:12:23 -0400 Subject: [PATCH 40/78] fix tape tests --- tests/tape/test_qscript.py | 10 ++++------ tests/tape/test_tape.py | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/tape/test_qscript.py b/tests/tape/test_qscript.py index befd6666a30..1297f1a8534 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -1368,10 +1368,8 @@ def test_complex_state(self, ret): assert np.issubdtype(result.dtype, complex) assert qs.numeric_type is complex - @pytest.mark.parametrize( - "ret, dtype", [(qml.sample(), np.bool8), (qml.sample(qml.PauliZ(wires=0)), np.int64)] - ) - def test_sample_int_eigvals(self, ret, dtype): + @pytest.mark.parametrize("ret", [qml.sample(), qml.sample(qml.PauliZ(wires=0))]) + def test_sample_int_eigvals(self, ret): """Test that the tape can correctly determine the output domain for a sampling measurement with a Hermitian observable with integer eigenvalues.""" @@ -1381,8 +1379,8 @@ def test_sample_int_eigvals(self, ret, dtype): result = qml.execute([qs], dev, gradient_fn=None)[0] # Double-check the domain of the QNode output - assert np.issubdtype(result.dtype, dtype) - assert np.issubdtype(dtype, qs.numeric_type) + assert np.issubdtype(result.dtype, np.int64) + assert qs.numeric_type is int # TODO: add cases for each interface once qml.Hermitian supports other # interfaces diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index 67868ee5a24..3c143a76aec 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -2182,10 +2182,8 @@ def circuit(a, b): assert np.issubdtype(result.dtype, complex) assert circuit.qtape.numeric_type is complex - @pytest.mark.parametrize( - "ret,dtype", [(qml.sample(), bool), (qml.sample(qml.PauliZ(wires=0)), int)] - ) - def test_sample_int_eigvals(self, ret, dtype): + @pytest.mark.parametrize("ret", [qml.sample(), qml.sample(qml.PauliZ(wires=0))]) + def test_sample_int_eigvals(self, ret): """Test that the tape can correctly determine the output domain for a sampling measurement with a Hermitian observable with integer eigenvalues.""" @@ -2199,8 +2197,8 @@ def circuit(): result = circuit() # Double-check the domain of the QNode output - assert np.issubdtype(result.dtype, dtype) - assert circuit.qtape.numeric_type is dtype + assert np.issubdtype(result.dtype, int) + assert circuit.qtape.numeric_type is int # TODO: add cases for each interface once qml.Hermitian supports other # interfaces From 72b866dbbc342e13084b5427a57f3a48640aa280 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 1 Sep 2023 10:42:24 -0400 Subject: [PATCH 41/78] identity to make test work on new device --- tests/ops/qubit/test_parametric_ops.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ops/qubit/test_parametric_ops.py b/tests/ops/qubit/test_parametric_ops.py index ba71bd3208e..8c83f22ba9c 100644 --- a/tests/ops/qubit/test_parametric_ops.py +++ b/tests/ops/qubit/test_parametric_ops.py @@ -3078,6 +3078,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) From f4d929551d946eb5f91ada632d88d8af971ab03b Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 1 Sep 2023 11:08:34 -0400 Subject: [PATCH 42/78] fix sample test for numeric_type --- tests/measurements/test_sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/measurements/test_sample.py b/tests/measurements/test_sample.py index 24d3f794158..5f38ef29ec8 100644 --- a/tests/measurements/test_sample.py +++ b/tests/measurements/test_sample.py @@ -286,7 +286,7 @@ def circuit(): "obs,exp", [ # Single observables - (None, bool), # comp basis samples + (None, int), # comp basis samples (qml.PauliX(0), int), (qml.PauliY(0), int), (qml.PauliZ(0), int), From 5a76b1ed68fb5e3038d8a119e7180c813f0402a2 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 6 Sep 2023 23:56:00 -0400 Subject: [PATCH 43/78] remove old dq2 measurements tests --- .../test_classical_shadow_default_qubit_2.py | 721 ---------------- .../test_counts_default_qubit_2.py | 712 ---------------- .../test_expval_default_qubit_2.py | 189 ----- .../test_measurements_default_qubit_2.py | 581 ------------- .../test_mid_measure_default_qubit_2.py | 471 ----------- .../test_mutual_info_default_qubit_2.py | 475 ----------- .../test_probs_default_qubit_2.py | 646 -------------- ...test_purity_measurement_default_qubit_2.py | 380 --------- .../test_sample_default_qubit_2.py | 390 --------- .../test_shots_default_qubit_2.py | 252 ------ .../test_state_default_qubit_2.py | 796 ------------------ .../test_var_default_qubit_2.py | 143 ---- .../test_vn_entropy_default_qubit_2.py | 405 --------- 13 files changed, 6161 deletions(-) delete mode 100644 tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py delete mode 100644 tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py diff --git a/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py deleted file mode 100644 index 2e020cfc597..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_classical_shadow_default_qubit_2.py +++ /dev/null @@ -1,721 +0,0 @@ -# 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 classical shadows measurement processes""" - -import copy - -import autograd.numpy -import pytest - -import pennylane as qml -from pennylane import numpy as np -from pennylane.measurements import ClassicalShadowMP, Shots -from pennylane.measurements.classical_shadow import ShadowExpvalMP - -# pylint: disable=dangerous-default-value, too-many-arguments - - -def get_circuit(wires, shots, seed_recipes, interface="autograd"): - """ - Return a QNode that prepares the state (|00...0> + |11...1>) / sqrt(2) - and performs the classical shadow measurement - """ - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Hadamard(wires=0) - - for target in range(1, wires): - qml.CNOT(wires=[0, target]) - - return qml.classical_shadow(wires=range(wires), seed=seed_recipes) - - return circuit - - -def get_x_basis_circuit(wires, shots, interface="autograd"): - """ - Return a QNode that prepares the |++..+> state and performs a classical shadow measurement - """ - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - for wire in range(wires): - qml.Hadamard(wire) - return qml.classical_shadow(wires=range(wires)) - - return circuit - - -def get_y_basis_circuit(wires, shots, interface="autograd"): - """ - Return a QNode that prepares the |+i>|+i>...|+i> state and performs a classical shadow measurement - """ - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - for wire in range(wires): - qml.Hadamard(wire) - qml.RZ(np.pi / 2, wire) - return qml.classical_shadow(wires=range(wires)) - - return circuit - - -def get_z_basis_circuit(wires, shots, interface="autograd"): - """ - Return a QNode that prepares the |00..0> state and performs a classical shadow measurement - """ - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - return qml.classical_shadow(wires=range(wires)) - - return circuit - - -wires_list = [1, 3] - - -class TestProcessState: - """Unit tests for process_state_with_shots for the classical_shadow - and shadow_expval measurements""" - - def test_shape_and_dtype(self): - """Test that the shape and dtype of the measurement is correct""" - mp = qml.classical_shadow(wires=[0, 1]) - res = mp.process_state_with_shots(np.ones((2, 2)) / 2, qml.wires.Wires([0, 1]), shots=100) - - assert res.shape == (2, 100, 2) - assert res.dtype == np.int8 - - # test that the bits are either 0 and 1 - assert np.all(np.logical_or(res[0] == 0, res[0] == 1)) - - # test that the recipes are either 0, 1, or 2 (X, Y, or Z) - assert np.all(np.logical_or(np.logical_or(res[1] == 0, res[1] == 1), res[1] == 2)) - - def test_wire_order(self): - """Test that the wire order is respected""" - state = np.array([[1, 1], [0, 0]]) / np.sqrt(2) - - mp = qml.classical_shadow(wires=[0, 1]) - res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000) - - assert res.shape == (2, 1000, 2) - assert res.dtype == np.int8 - - # test that the first qubit samples are all 0s when the recipe is Z - assert np.all(res[0][res[1, ..., 0] == 2][:, 0] == 0) - - # test that the second qubit samples contain 1s when the recipe is Z - assert np.any(res[0][res[1, ..., 1] == 2][:, 1] == 1) - - res = mp.process_state_with_shots(state, qml.wires.Wires([1, 0]), shots=1000) - - assert res.shape == (2, 1000, 2) - assert res.dtype == np.int8 - - # now test that the first qubit samples contain 1s when the recipe is Z - assert np.any(res[0][res[1, ..., 0] == 2][:, 0] == 1) - - # now test that the second qubit samples are all 0s when the recipe is Z - assert np.all(res[0][res[1, ..., 1] == 2][:, 1] == 0) - - def test_subset_wires(self): - """Test that the measurement is correct when only a subset of wires is measured""" - mp = qml.classical_shadow(wires=[0, 1]) - - # GHZ state - state = np.zeros((2, 2, 2)) - state[np.array([0, 1]), np.array([0, 1]), np.array([0, 1])] = 1 / np.sqrt(2) - - res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) - - assert res.shape == (2, 100, 2) - assert res.dtype == np.int8 - - # test that the bits are either 0 and 1 - assert np.all(np.logical_or(res[0] == 0, res[0] == 1)) - - # test that the recipes are either 0, 1, or 2 (X, Y, or Z) - assert np.all(np.logical_or(np.logical_or(res[1] == 0, res[1] == 1), res[1] == 2)) - - def test_same_rng(self): - """Test results when the rng is the same""" - state = np.ones((2, 2)) / 2 - - mp1 = qml.classical_shadow(wires=[0, 1], seed=123) - mp2 = qml.classical_shadow(wires=[0, 1], seed=123) - - res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) - res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100) - - # test recipes are the same but bits are different - assert np.all(res1[1] == res2[1]) - assert np.any(res1[0] != res2[0]) - - res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100, rng=456) - res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=100, rng=456) - - # now test everything is the same - assert np.all(res1[1] == res2[1]) - assert np.all(res1[0] == res2[0]) - - def test_expval_shape_and_val(self): - """Test that shadow expval measurements work as expected""" - mp = qml.shadow_expval(qml.PauliX(0) @ qml.PauliX(1), seed=200) - res = mp.process_state_with_shots( - np.ones((2, 2)) / 2, qml.wires.Wires([0, 1]), shots=1000, rng=100 - ) - - assert res.shape == () - assert np.allclose(res, 1.0, atol=0.05) - - def test_expval_wire_order(self): - """Test that shadow expval respects the wire order""" - state = np.array([[1, 1], [0, 0]]) / np.sqrt(2) - - mp = qml.shadow_expval(qml.PauliZ(0), seed=200) - res = mp.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=3000, rng=100) - - assert res.shape == () - assert np.allclose(res, 1.0, atol=0.05) - - res = mp.process_state_with_shots(state, qml.wires.Wires([1, 0]), shots=3000, rng=100) - - assert res.shape == () - assert np.allclose(res, 0.0, atol=0.05) - - def test_expval_same_rng(self): - """Test expval results when the rng is the same""" - state = np.ones((2, 2)) / 2 - - mp1 = qml.shadow_expval(qml.PauliZ(0) @ qml.PauliZ(1), seed=123) - mp2 = qml.shadow_expval(qml.PauliZ(0) @ qml.PauliZ(1), seed=123) - - res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=100) - res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=200) - - # test results are different - assert res1 != res2 - - res1 = mp1.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=456) - res2 = mp2.process_state_with_shots(state, qml.wires.Wires([0, 1]), shots=1000, rng=456) - - # now test that results are the same - assert res1 == res2 - - -@pytest.mark.parametrize("wires", wires_list) -class TestClassicalShadow: - """Unit tests for classical_shadow measurement""" - - shots_list = [1, 100] - seed_recipes_list = [None, 74] # random seed - - @pytest.mark.parametrize("seed", seed_recipes_list) - def test_measurement_process_numeric_type(self, wires, seed): - """Test that the numeric type of the MeasurementProcess instance is correct""" - res = qml.classical_shadow(wires=range(wires), seed=seed) - assert res.numeric_type == int - - @pytest.mark.parametrize("shots", shots_list) - @pytest.mark.parametrize("seed", seed_recipes_list) - def test_measurement_process_shape(self, wires, shots, seed): - """Test that the shape of the MeasurementProcess instance is correct""" - dev = qml.device("default.qubit", wires=wires, shots=shots) - shots_obj = Shots(shots) - res = qml.classical_shadow(wires=range(wires), seed=seed) - assert res.shape(dev, shots_obj) == (2, shots, wires) - - # test an error is raised when device is None - msg = "Shots must be specified to obtain the shape of a classical shadow measurement" - with pytest.raises(qml.measurements.MeasurementShapeError, match=msg): - res.shape(dev, Shots(None)) - - def test_shape_matches(self, wires): - """Test that the shape of the MeasurementProcess matches the shape - of the tape execution""" - shots = 100 - - circuit = get_circuit(wires, shots, True) - circuit.construct((), {}) - - res = qml.execute([circuit.tape], circuit.device, None)[0] - expected_shape = qml.classical_shadow(wires=range(wires)).shape( - circuit.device, Shots(shots) - ) - - assert res.shape == expected_shape - - @pytest.mark.parametrize("seed", seed_recipes_list) - def test_measurement_process_copy(self, wires, seed): - """Test that the attributes of the MeasurementProcess instance are - correctly copied""" - res = qml.classical_shadow(wires=range(wires), seed=seed) - - copied_res = copy.copy(res) - assert isinstance(copied_res, ClassicalShadowMP) - assert copied_res.return_type == res.return_type - assert copied_res.wires == res.wires - assert copied_res.seed == res.seed - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("shots", shots_list) - @pytest.mark.parametrize("seed", seed_recipes_list) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - def test_format(self, wires, shots, seed, interface): - """Test that the format of the returned classical shadow - measurement is correct""" - import tensorflow as tf - import torch - - circuit = get_circuit(wires, shots, seed, interface) - shadow = circuit() - - # test shape is correct - assert shadow.shape == (2, shots, wires) - - # test dtype is correct - expected_dtype = np.int8 - if interface == "tf": - expected_dtype = tf.int8 - elif interface == "torch": - expected_dtype = torch.int8 - - assert shadow.dtype == expected_dtype - - bits, recipes = shadow # pylint: disable=unpacking-non-sequence - - # test allowed values of bits and recipes - assert qml.math.all(np.logical_or(bits == 0, bits == 1)) - assert qml.math.all(np.logical_or(recipes == 0, np.logical_or(recipes == 1, recipes == 2))) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize( - "circuit_fn, basis_recipe", - [(get_x_basis_circuit, 0), (get_y_basis_circuit, 1), (get_z_basis_circuit, 2)], - ) - def test_return_distribution(self, wires, interface, circuit_fn, basis_recipe): - """Test that the distribution of the bits and recipes are correct for a circuit - that prepares all qubits in a Pauli basis""" - # high number of shots to prevent true negatives - np.random.seed(42) - shots = 1000 - - circuit = circuit_fn(wires, shots=shots, interface=interface) - bits, recipes = circuit() - - # test that the recipes follow a rough uniform distribution - ratios = np.unique(recipes, return_counts=True)[1] / (wires * shots) - assert np.allclose(ratios, 1 / 3, atol=1e-1) - - # test that the bit is 0 for all X measurements - assert qml.math.allequal(bits[recipes == basis_recipe], 0) - - # test that the bits are uniformly distributed for all Y and Z measurements - bits1 = bits[recipes == (basis_recipe + 1) % 3] - ratios1 = np.unique(bits1, return_counts=True)[1] / bits1.shape[0] - assert np.allclose(ratios1, 1 / 2, atol=1e-1) - - bits2 = bits[recipes == (basis_recipe + 2) % 3] - ratios2 = np.unique(bits2, return_counts=True)[1] / bits2.shape[0] - assert np.allclose(ratios2, 1 / 2, atol=1e-1) - - @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 - to obtain classical shadows""" - circuit = get_circuit(wires, None, seed) - - msg = "Analytic circuits must only contain StateMeasurements" - with pytest.raises(qml.DeviceError, match=msg): - circuit() - - @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 - with other measurement processes""" - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - - for target in range(1, wires): - qml.CNOT(wires=[0, target]) - - return qml.classical_shadow(wires=range(wires)), qml.expval(qml.PauliZ(0)) - - res = circuit() - assert isinstance(res, tuple) and len(res) == 2 - assert qml.math.shape(res[0]) == (2, shots, wires) - assert qml.math.shape(res[1]) == () - - -def hadamard_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(obs, k=1): - for i in range(wires): - qml.Hadamard(wires=i) - return qml.shadow_expval(obs, k=k) - - return circuit - - -def max_entangled_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(obs, k=1): - qml.Hadamard(wires=0) - for i in range(1, wires): - qml.CNOT(wires=[0, i]) - return qml.shadow_expval(obs, k=k) - - return circuit - - -def qft_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) - - one_state = np.zeros(wires) - one_state[-1] = 1 - - @qml.qnode(dev, interface=interface) - def circuit(obs, k=1): - qml.BasisState(one_state, wires=range(wires)) - qml.QFT(wires=range(wires)) - return qml.shadow_expval(obs, k=k) - - return circuit - - -@pytest.mark.autograd -class TestExpvalMeasurement: - def test_measurement_process_numeric_type(self): - """Test that the numeric type of the MeasurementProcess instance is correct""" - H = qml.PauliZ(0) - res = qml.shadow_expval(H) - assert res.numeric_type == float - - @pytest.mark.parametrize("wires", [1, 2]) - @pytest.mark.parametrize("shots", [1, 10]) - def test_measurement_process_shape(self, wires, shots): - """Test that the shape of the MeasurementProcess instance is correct""" - dev = qml.device("default.qubit", wires=wires, shots=shots) - H = qml.PauliZ(0) - res = qml.shadow_expval(H) - assert len(res.shape(dev, Shots(shots))) == 0 - - def test_shape_matches(self): - """Test that the shape of the MeasurementProcess matches the shape - of the tape execution""" - wires = 2 - shots = 100 - H = qml.PauliZ(0) - - circuit = hadamard_circuit(wires, shots) - circuit.construct((H,), {}) - - res = qml.execute([circuit.tape], circuit.device, None)[0] - expected_shape = qml.shadow_expval(H).shape(circuit.device, Shots(shots)) - - assert res.shape == expected_shape - - def test_measurement_process_copy(self): - """Test that the attributes of the MeasurementProcess instance are - correctly copied""" - H = qml.PauliZ(0) - res = qml.shadow_expval(H, k=10) - - copied_res = copy.copy(res) - assert type(copied_res) == type(res) # pylint: disable=unidiomatic-typecheck - assert copied_res.return_type == res.return_type - assert qml.equal(copied_res.H, res.H) - assert copied_res.k == res.k - assert copied_res.seed == res.seed - - def test_shots_none_error(self): - """Test that an error is raised when a device with shots=None is used - to obtain classical shadows""" - circuit = hadamard_circuit(2, None) - H = qml.PauliZ(0) - - msg = "Analytic circuits must only contain StateMeasurements" - with pytest.raises(qml.DeviceError, match=msg): - _ = circuit(H, k=10) - - def test_multi_measurement_allowed(self): - """Test that no error is raised when classical shadows is returned - with other measurement processes""" - dev = qml.device("default.qubit", wires=2, shots=10000) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - qml.CNOT(wires=[0, 1]) - return qml.shadow_expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(0)) - - res = circuit() - assert isinstance(res, tuple) - assert qml.math.allclose(res, 0, atol=0.05) - - def test_obs_not_queued(self): - """Test that the observable passed to qml.shadow_expval is not queued""" - with qml.queuing.AnnotatedQueue() as q: - qml.PauliY(0) - qml.shadow_expval(qml.PauliZ(0)) - - tape = qml.tape.QuantumScript.from_queue(q) - assert len(tape.operations) == 1 - assert tape.operations[0].name == "PauliY" - assert len(tape.measurements) == 1 - assert isinstance(tape.measurements[0], ShadowExpvalMP) - - -obs_hadamard = [ - qml.PauliX(1), - qml.PauliX(0) @ qml.PauliX(2), - qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), - qml.PauliY(2), - qml.PauliY(1) @ qml.PauliZ(2), - qml.PauliX(0) @ qml.PauliY(1), - qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), -] -expected_hadamard = [1, 1, 1, 0, 0, 0, 0] - -obs_max_entangled = [ - qml.PauliX(1), - qml.PauliX(0) @ qml.PauliX(2), - qml.PauliZ(2), - qml.Identity(1) @ qml.PauliZ(2), - qml.PauliZ(1) @ qml.PauliZ(2), - qml.PauliX(0) @ qml.PauliY(1), - qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), - qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliY(2), -] -expected_max_entangled = [0, 0, 0, 0, 1, 0, 0, -1] - -obs_qft = [ - qml.PauliX(0), - qml.PauliX(0) @ qml.PauliX(1), - qml.PauliX(0) @ qml.PauliX(2), - qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), - qml.PauliZ(2), - qml.PauliX(1) @ qml.PauliY(2), - qml.PauliY(1) @ qml.PauliX(2), - qml.Identity(0) @ qml.PauliY(1) @ qml.PauliX(2), - qml.PauliX(0) @ qml.PauliY(1) @ qml.PauliY(2), - qml.PauliY(0) @ qml.PauliX(1) @ qml.PauliX(2), -] -expected_qft = [ - -1, - 0, - -1 / np.sqrt(2), - -1 / np.sqrt(2), - 0, - 0, - 1 / np.sqrt(2), - 1 / np.sqrt(2), - -1 / np.sqrt(2), - 0, -] - - -@pytest.mark.autograd -class TestExpvalForward: - """Test the shadow_expval measurement process forward pass""" - - def test_hadamard_expval(self, k=1, obs=obs_hadamard, expected=expected_hadamard): - """Test that the expval estimation is correct for a uniform - superposition of qubits""" - circuit = hadamard_circuit(3, shots=100000) - actual = circuit(obs, k=k) - - assert actual.shape == (len(obs_hadamard),) - assert actual.dtype == np.float64 - assert qml.math.allclose(actual, expected, atol=1e-1) - - def test_max_entangled_expval( - self, k=1, obs=obs_max_entangled, expected=expected_max_entangled - ): - """Test that the expval estimation is correct for a maximally - entangled state""" - circuit = max_entangled_circuit(3, shots=100000) - actual = circuit(obs, k=k) - - assert actual.shape == (len(obs_max_entangled),) - assert actual.dtype == np.float64 - assert qml.math.allclose(actual, expected, atol=1e-1) - - def test_non_pauli_error(self): - """Test that an error is raised when a non-Pauli observable is passed""" - circuit = hadamard_circuit(3) - - msg = "Observable must be a linear combination of Pauli observables" - with pytest.raises(ValueError, match=msg): - circuit(qml.Hadamard(0) @ qml.Hadamard(2)) - - -# pylint: disable=too-few-public-methods -@pytest.mark.all_interfaces -class TestExpvalForwardInterfaces: - @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - def test_qft_expval(self, interface, k=1, obs=obs_qft, expected=expected_qft): - """Test that the expval estimation is correct for a QFT state""" - import torch - - circuit = qft_circuit(3, shots=100000, interface=interface) - actual = circuit(obs, k=k) - - assert actual.shape == (len(obs_qft),) - assert actual.dtype == torch.float64 if interface == "torch" else np.float64 - assert qml.math.allclose(actual, expected, atol=1e-1) - - -obs_strongly_entangled = [ - qml.PauliX(1), - qml.PauliX(0) @ qml.PauliX(2), - qml.PauliX(0) @ qml.Identity(1) @ qml.PauliX(2), - qml.PauliY(2), - qml.PauliY(1) @ qml.PauliZ(2), - qml.PauliX(0) @ qml.PauliY(1), - qml.PauliX(0) @ qml.PauliY(1) @ qml.Identity(2), -] - - -def strongly_entangling_circuit(wires, shots=10000, interface="autograd"): - dev = qml.device("default.qubit", wires=wires, shots=shots) - - @qml.qnode(dev, interface=interface) - def circuit(x, obs, k): - qml.StronglyEntanglingLayers(weights=x, wires=range(wires)) - return qml.shadow_expval(obs, k=k) - - return circuit - - -def strongly_entangling_circuit_exact(wires, interface="autograd"): - dev = qml.device("default.qubit", wires=wires) - - @qml.qnode(dev, interface=interface) - def circuit(x, obs): - qml.StronglyEntanglingLayers(weights=x, wires=range(wires)) - return [qml.expval(o) for o in obs] - - return circuit - - -class TestExpvalBackward: - """Test the shadow_expval measurement process backward pass""" - - @pytest.mark.autograd - def test_backward_autograd(self, obs=obs_strongly_entangled): - """Test that the gradient of the expval estimation is correct for - the autograd interface""" - shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="autograd") - exact_circuit = strongly_entangling_circuit_exact(3, "autograd") - - def cost_exact(x, obs): - return autograd.numpy.hstack(exact_circuit(x, obs)) - - # make rotations close to pi / 2 to ensure gradients are not too small - x = np.random.uniform( - 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) - ) - actual = qml.jacobian(shadow_circuit)(x, obs, k=1) - expected = qml.jacobian(cost_exact, argnum=0)(x, obs) - - assert qml.math.allclose(actual, expected, atol=1e-1) - - @pytest.mark.jax - def test_backward_jax(self, obs=obs_strongly_entangled): - """Test that the gradient of the expval estimation is correct for - the jax interface""" - import jax - from jax import numpy as jnp - - shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="jax") - exact_circuit = strongly_entangling_circuit_exact(3, "jax") - - # make rotations close to pi / 2 to ensure gradients are not too small - x = jnp.array( - np.random.uniform( - 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) - ) - ) - - actual = jax.jacrev(shadow_circuit)(x, obs, k=1) - expected = jax.jacrev(exact_circuit)(x, obs) - - assert qml.math.allclose(actual, expected, atol=1e-1) - - @pytest.mark.tf - def test_backward_tf(self, obs=obs_strongly_entangled): - """Test that the gradient of the expval estimation is correct for - the tensorflow interface""" - import tensorflow as tf - - shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="tf") - exact_circuit = strongly_entangling_circuit_exact(3, "tf") - - # make rotations close to pi / 2 to ensure gradients are not too small - x = tf.Variable( - np.random.uniform( - 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) - ) - ) - - with tf.GradientTape() as tape: - out = shadow_circuit(x, obs, k=10) - - actual = tape.jacobian(out, x) - - with tf.GradientTape() as tape2: - out2 = qml.math.hstack(exact_circuit(x, obs)) - - expected = tape2.jacobian(out2, x) - - assert qml.math.allclose(actual, expected, atol=1e-1) - - @pytest.mark.torch - def test_backward_torch(self, obs=obs_strongly_entangled): - """Test that the gradient of the expval estimation is correct for - the pytorch interface""" - import torch - - shadow_circuit = strongly_entangling_circuit(3, shots=20000, interface="torch") - exact_circuit = strongly_entangling_circuit_exact(3, "torch") - - # make rotations close to pi / 2 to ensure gradients are not too small - x = torch.tensor( - np.random.uniform( - 0.8, 2, size=qml.StronglyEntanglingLayers.shape(n_layers=2, n_wires=3) - ), - requires_grad=True, - ) - - actual = torch.autograd.functional.jacobian(lambda x: shadow_circuit(x, obs, k=10), x) - expected = torch.autograd.functional.jacobian(lambda x: tuple(exact_circuit(x, obs)), x) - - assert qml.math.allclose(actual, qml.math.stack(expected), atol=1e-1) diff --git a/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py deleted file mode 100644 index 3ac4ce72070..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_counts_default_qubit_2.py +++ /dev/null @@ -1,712 +0,0 @@ -# Copyright 2018-2023 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. -"""Tests for the qml.counts measurement process.""" -import copy -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import AllCounts, Counts, CountsMP -from pennylane.wires import Wires - - -class TestCounts: - """Tests for the counts function""" - - def test_counts_properties(self): - """Test that the properties are correct.""" - meas1 = qml.counts(wires=0) - meas2 = qml.counts(op=qml.PauliX(0), all_outcomes=True) - assert meas1.samples_computational_basis is True - assert meas1.return_type == Counts - assert meas2.samples_computational_basis is False - assert meas2.return_type == AllCounts - - def test_queue(self): - """Test that the right measurement class is queued.""" - - with qml.queuing.AnnotatedQueue() as q: - op = qml.PauliX(0) - m = qml.counts(op) - - assert q.queue[0] is m - assert isinstance(m, CountsMP) - - def test_copy(self): - """Test that the ``__copy__`` method also copies the ``all_outcomes`` information.""" - meas = qml.counts(wires=0, all_outcomes=True) - meas_copy = copy.copy(meas) - assert meas_copy.wires == Wires(0) - assert meas_copy.all_outcomes is True - - def test_providing_observable_and_wires(self): - """Test that a ValueError is raised if both an observable is provided and wires are - specified""" - - with pytest.raises( - ValueError, - match="Cannot specify the wires to sample if an observable is provided." - " The wires to sample will be determined directly from the observable.", - ): - qml.counts(qml.PauliZ(0), wires=[0, 1]) - - def test_observable_might_not_be_hermitian(self): - """Test that a UserWarning is raised if the provided - argument might not be hermitian.""" - - with pytest.warns(UserWarning, match="Prod might not be hermitian."): - qml.counts(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - - def test_hash(self): - """Test that the hash property includes the all_outcomes property.""" - m1 = qml.counts(all_outcomes=True) - m2 = qml.counts(all_outcomes=False) - - assert m1.hash != m2.hash - - m3 = CountsMP(eigvals=[0.5, -0.5], wires=qml.wires.Wires(0), all_outcomes=True) - assert m3.hash != m1.hash - - def test_repr(self): - """Test that the repr includes the all_outcomes property.""" - m1 = CountsMP(wires=Wires(0), all_outcomes=True) - assert repr(m1) == "CountsMP(wires=[0], all_outcomes=True)" - - m2 = CountsMP(obs=qml.PauliX(0), all_outcomes=True) - assert repr(m2) == "CountsMP(PauliX(wires=[0]), all_outcomes=True)" - - m3 = CountsMP(eigvals=(-1, 1), all_outcomes=False) - assert repr(m3) == "CountsMP(eigvals=[-1 1], wires=[], all_outcomes=False)" - - -class TestProcessSamples: - """Unit tests for the counts.process_samples method""" - - def test_counts_shape_single_wires(self): - """Test that the counts output is correct for single wires""" - shots = 1000 - samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) - - result = qml.counts(wires=0).process_samples(samples, wire_order=[0]) - - assert len(result) == 2 - assert set(result.keys()) == {"0", "1"} - assert result["0"] == np.count_nonzero(samples[:, 0] == 0) - assert result["1"] == np.count_nonzero(samples[:, 0] == 1) - - def test_counts_shape_multi_wires(self): - """Test that the counts function outputs counts of the right size - for multiple wires""" - shots = 1000 - samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) - - result = qml.counts(wires=[0, 1]).process_samples(samples, wire_order=[0, 1]) - - assert len(result) == 4 - assert set(result.keys()) == {"00", "01", "10", "11"} - assert result["00"] == np.count_nonzero( - np.logical_and(samples[:, 0] == 0, samples[:, 1] == 0) - ) - assert result["01"] == np.count_nonzero( - np.logical_and(samples[:, 0] == 0, samples[:, 1] == 1) - ) - assert result["10"] == np.count_nonzero( - np.logical_and(samples[:, 0] == 1, samples[:, 1] == 0) - ) - assert result["11"] == np.count_nonzero( - np.logical_and(samples[:, 0] == 1, samples[:, 1] == 1) - ) - - def test_counts_obs(self): - """Test that the counts function outputs counts of the right size for observables""" - shots = 1000 - samples = np.random.choice([0, 1], size=(shots, 2)).astype(np.bool8) - - result = qml.counts(qml.PauliZ(0)).process_samples(samples, wire_order=[0]) - - assert len(result) == 2 - assert set(result.keys()) == {1, -1} - assert result[1] == np.count_nonzero(samples[:, 0] == 0) - assert result[-1] == np.count_nonzero(samples[:, 0] == 1) - - def test_counts_all_outcomes_wires(self): - """Test that the counts output is correct when all_outcomes is passed""" - shots = 1000 - samples = np.zeros((shots, 2)).astype(np.bool8) - - result1 = qml.counts(wires=0, all_outcomes=False).process_samples(samples, wire_order=[0]) - - assert len(result1) == 1 - assert set(result1.keys()) == {"0"} - assert result1["0"] == shots - - result2 = qml.counts(wires=0, all_outcomes=True).process_samples(samples, wire_order=[0]) - - assert len(result2) == 2 - assert set(result2.keys()) == {"0", "1"} - assert result2["0"] == shots - assert result2["1"] == 0 - - def test_counts_all_outcomes_obs(self): - """Test that the counts output is correct when all_outcomes is passed""" - shots = 1000 - samples = np.zeros((shots, 2)).astype(np.bool8) - - result1 = qml.counts(qml.PauliZ(0), all_outcomes=False).process_samples( - samples, wire_order=[0] - ) - - assert len(result1) == 1 - assert set(result1.keys()) == {1} - assert result1[1] == shots - - result2 = qml.counts(qml.PauliZ(0), all_outcomes=True).process_samples( - samples, wire_order=[0] - ) - - assert len(result2) == 2 - assert set(result2.keys()) == {1, -1} - assert result2[1] == shots - assert result2[-1] == 0 - - -class TestCountsIntegration: - # pylint:disable=too-many-public-methods,not-an-iterable - - def test_counts_dimension(self): - """Test that the counts function outputs counts of the right size""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=2, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.54, wires=0) - return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliX(1)) - - sample = circuit() - - assert len(sample) == 2 - assert np.all([sum(s.values()) == n_sample for s in sample]) - - def test_batched_counts_dimension(self): - """Test that the counts function outputs counts of the right size with batching""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=2, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - qml.RX([0.54, 0.65], wires=0) - return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliX(1)) - - sample = circuit() - - assert isinstance(sample, tuple) - assert len(sample) == 2 - assert np.all([sum(s.values()) == n_sample for batch in sample for s in batch]) - - def test_counts_combination(self): - """Test the output of combining expval, var and counts""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=3, shots=n_sample) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(0.54, wires=0) - - return ( - qml.counts(qml.PauliZ(0)), - qml.expval(qml.PauliX(1)), - qml.var(qml.PauliY(2)), - ) - - result = circuit() - - assert len(result) == 3 - assert sum(result[0].values()) == n_sample - - def test_single_wire_counts(self): - """Test the return type and shape of sampling counts from a single wire""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=1, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.54, wires=0) - - return qml.counts(qml.PauliZ(0)) - - result = circuit() - - assert isinstance(result, dict) - assert sum(result.values()) == n_sample - - def test_multi_wire_counts_regular_shape(self): - """Test the return type and shape of sampling multiple wires - where a rectangular array is expected""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=3, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - return ( - qml.counts(qml.PauliZ(0)), - qml.counts(qml.PauliZ(1)), - qml.counts(qml.PauliZ(2)), - ) - - result = circuit() - - # If all the dimensions are equal the result will end up to be a proper rectangular array - assert isinstance(result, tuple) - assert len(result) == 3 - assert all(sum(r.values()) == n_sample for r in result) - assert all(all(v.dtype == np.dtype("int") for v in r.values()) for r in result) - - def test_observable_return_type_is_counts(self): - """Test that the return type of the observable is :attr:`ObservableReturnTypes.Counts`""" - n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - res = qml.counts(qml.PauliZ(0)) - return res - - circuit() - assert circuit._qfunc_output.return_type is Counts # pylint: disable=protected-access - - def test_providing_no_observable_and_no_wires_counts(self): - """Test that we can provide no observable and no wires to sample function""" - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - res = qml.counts() - assert res.obs is None - assert res.wires == qml.wires.Wires([]) - return res - - circuit() - - def test_providing_no_observable_and_wires_counts(self): - """Test that we can provide no observable but specify wires to the sample function""" - wires = [0, 2] - wires_obj = qml.wires.Wires(wires) - dev = qml.device("default.qubit", wires=3, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - res = qml.counts(wires=wires) - - assert res.obs is None - assert res.wires == wires_obj - return res - - circuit() - - def test_batched_counts_work_individually(self): - """Test that each counts call operates independently""" - n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - qml.pow(qml.PauliX(0), z=[1, 2]) - return qml.counts() - - assert circuit() == [{"1": 10}, {"0": 10}] - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_no_op_finite_shots(self, interface, wires, basis_state): - """Check all interfaces with computational basis state counts and - finite shot""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - qml.PauliX(1) - return qml.counts(wires=wires) - - res = circuit() - assert res == {basis_state: n_shots} - assert qml.math.get_interface(res[basis_state]) == interface - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_operator_finite_shots(self, interface): - """Check all interfaces with observable measurement counts and finite - shot""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - return qml.counts(qml.PauliZ(0)) - - res = circuit() - assert res == {1: n_shots} - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - @pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_binned( - self, shot_vec, interface, wires, basis_state - ): # pylint:disable=too-many-arguments - """Check all interfaces with computational basis state counts and - different shot vectors""" - dev = qml.device("default.qubit", wires=3, shots=shot_vec) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - qml.PauliX(1) - return qml.counts(wires=wires) - - res = circuit() - - assert isinstance(res, tuple) - assert res[0] == {basis_state: shot_vec[0]} - assert res[1] == {basis_state: shot_vec[1]} - assert res[2] == {basis_state: shot_vec[2]} - assert len(res) == len(shot_vec) - assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - def test_counts_operator_binned(self, shot_vec, interface): - """Check all interfaces with observable measurement counts and different - shot vectors""" - dev = qml.device("default.qubit", wires=3, shots=shot_vec) - - @qml.qnode(dev, interface=interface) - def circuit(): - return qml.counts(qml.PauliZ(0)) - - res = circuit() - - assert isinstance(res, tuple) - assert res[0] == {1: shot_vec[0]} - assert res[1] == {1: shot_vec[1]} - assert res[2] == {1: shot_vec[2]} - assert len(res) == len(shot_vec) - assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - def test_counts_binned_4_wires(self, shot_vec): - """Check the autograd interface with computational basis state counts and - different shot vectors on a device with 4 wires""" - dev = qml.device("default.qubit", wires=4, shots=shot_vec) - - @qml.qnode(dev, interface="autograd") - def circuit(): - qml.Identity(0) - qml.PauliX(1) - qml.PauliX(2) - qml.PauliX(3) - return qml.counts() - - res = circuit() - basis_state = "0111" - - assert isinstance(res, tuple) - assert res[0][basis_state] == shot_vec[0] - assert res[1][basis_state] == shot_vec[1] - assert res[2][basis_state] == shot_vec[2] - assert len(res) == len(shot_vec) - assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - - @pytest.mark.parametrize("shot_vec", [(1, 10, 10), (1, 10, 1000)]) - def test_counts_operator_binned_4_wires(self, shot_vec): - """Check the autograd interface with observable samples to obtain - counts from and different shot vectors on a device with 4 wires""" - dev = qml.device("default.qubit", wires=4, shots=shot_vec) - - @qml.qnode(dev, interface="autograd") - def circuit(): - qml.PauliX(1) - qml.PauliX(2) - qml.PauliX(3) - return qml.counts(qml.PauliZ(0)) - - res = circuit() - sample = 1 - - assert isinstance(res, tuple) - assert res[0][sample] == shot_vec[0] - assert res[1][sample] == shot_vec[1] - assert res[2][sample] == shot_vec[2] - assert len(res) == len(shot_vec) - assert sum(sum(res_bin.values()) for res_bin in res) == sum(shot_vec) - - meas2 = [ - qml.expval(qml.PauliZ(0)), - qml.var(qml.PauliZ(0)), - qml.probs(wires=[1, 0]), - qml.sample(wires=1), - ] - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - @pytest.mark.parametrize("meas2", meas2) - @pytest.mark.parametrize("shots", [1000, (1, 10)]) - def test_counts_observable_finite_shots(self, interface, meas2, shots): - """Check all interfaces with observable measurement counts and finite - shot""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - if isinstance(shots, tuple) and interface == "torch": - pytest.skip("Torch needs to be updated for shot vectors.") - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.PauliX(0) - return qml.counts(wires=0), qml.apply(meas2) - - res = circuit() - assert isinstance(res, tuple) - - num_shot_bins = 1 if isinstance(shots, int) else len(shots) - - if num_shot_bins == 1: - counts_term_indices = [i * 2 for i in range(num_shot_bins)] - for ind in counts_term_indices: - assert isinstance(res[ind], dict) - else: - assert len(res) == 2 - - assert isinstance(res[0], tuple) - assert isinstance(res[0][0], dict) - assert isinstance(res[1], tuple) - assert isinstance(res[1][0], dict) - - def test_all_outcomes_kwarg_providing_observable(self): - """Test that the dictionary keys *all* eigenvalues of the observable, - including 0 count values, if observable is given and all_outcomes=True""" - - n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - res = qml.counts(qml.PauliZ(0), all_outcomes=True) - return res - - res = circuit() - - assert res == {1: n_shots, -1: 0} - - def test_all_outcomes_kwarg_no_observable_no_wires(self): - """Test that the dictionary keys are *all* the possible combinations - of basis states for the device, including 0 count values, if no wire - count and no observable are given and all_outcomes=True""" - - n_shots = 10 - dev = qml.device("default.qubit", wires=2, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - qml.Identity(wires=[0, 1]) - return qml.counts(all_outcomes=True) - - res = circuit() - - assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} - - def test_all_outcomes_kwarg_providing_wires_and_no_observable(self): - """Test that the dictionary keys are *all* possible combinations - of basis states for the specified wires, including 0 count values, - if wire count is given and all_outcomes=True""" - - n_shots = 10 - dev = qml.device("default.qubit", wires=4, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - return qml.counts(wires=[0, 2], all_outcomes=True) - - res = circuit() - - assert res == {"00": n_shots, "01": 0, "10": 0, "11": 0} - - def test_all_outcomes_hermitian(self): - """Tests that the all_outcomes=True option for counts works with the - qml.Hermitian observable""" - - n_shots = 10 - dev = qml.device("default.qubit", wires=2, shots=n_shots) - - A = np.array([[1, 0], [0, -1]]) - - @qml.qnode(dev) - def circuit(x): - return qml.counts(qml.Hermitian(x, wires=0), all_outcomes=True) - - res = circuit(A) - - assert res == {-1.0: 0, 1.0: n_shots} - - def test_all_outcomes_multiple_measurements(self): - """Tests that the all_outcomes=True option for counts works when - multiple measurements are performed""" - - dev = qml.device("default.qubit", wires=2, shots=10) - - @qml.qnode(dev) - def circuit(): - qml.Identity(wires=[0, 1]) - return qml.sample(qml.PauliZ(0)), qml.counts(), qml.counts(all_outcomes=True) - - res = circuit() - - assert len(res[0]) == 10 - assert res[1] == {"00": 10} - assert res[2] == {"00": 10, "01": 0, "10": 0, "11": 0} - - def test_batched_all_outcomes(self): - """Tests that all_outcomes=True works with broadcasting.""" - n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - qml.pow(qml.PauliX(0), z=[1, 2]) - return qml.counts(qml.PauliZ(0), all_outcomes=True) - - assert circuit() == [{1: 0, -1: n_shots}, {1: n_shots, -1: 0}] - - def test_counts_empty_wires(self): - """Test that using ``qml.counts`` with an empty wire list raises an error.""" - with pytest.raises(ValueError, match="Cannot set an empty list of wires."): - qml.counts(wires=[]) - - @pytest.mark.parametrize("shots", [1, 100]) - def test_counts_no_arguments(self, shots): - """Test that using ``qml.counts`` with no arguments returns the counts of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - return qml.counts() - - res = circuit() - - assert qml.math.allequal(res, {"000": shots}) - - -@pytest.mark.all_interfaces -@pytest.mark.parametrize("wires, basis_state", [(None, "010"), ([2, 1], "01")]) -@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_counts_no_op_finite_shots(interface, wires, basis_state): - """Check all interfaces with computational basis state counts and finite shot""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - qml.PauliX(1) - return qml.counts(wires=wires) - - res = circuit() - assert res == {basis_state: n_shots} - assert qml.math.get_interface(res[basis_state]) == interface - - -@pytest.mark.all_interfaces -@pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) -@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_no_op_finite_shots(interface, wires, basis_states): - """Check all interfaces with computational basis state counts and - finite shot""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - qml.pow(qml.PauliX(1), z=[1, 2]) - return qml.counts(wires=wires) - - assert circuit() == [{basis_state: n_shots} for basis_state in basis_states] - - -@pytest.mark.all_interfaces -@pytest.mark.parametrize("wires, basis_states", [(None, ("010", "000")), ([2, 1], ("01", "00"))]) -@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_and_expval_no_op_finite_shots(interface, wires, basis_states): - """Check all interfaces with computational basis state counts and - finite shot""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.Identity(2) - qml.pow(qml.PauliX(1), z=[1, 2]) - return qml.counts(wires=wires), qml.expval(qml.PauliZ(0)) - - res = circuit() - assert isinstance(res, tuple) and len(res) == 2 - for i, basis_state in enumerate(basis_states): - assert list(res[0][i].keys()) == [basis_state] - assert qml.math.allequal(list(res[0][i].values()), n_shots) - # assert res[0] == [{basis_state: expected_n_shots} for basis_state in basis_states] - assert len(res[1]) == 2 and qml.math.allequal(res[1], 1) - - -@pytest.mark.all_interfaces -@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_operator_finite_shots(interface): - """Check all interfaces with observable measurement counts, batching and finite shots""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.pow(qml.PauliX(0), z=[1, 2]) - return qml.counts(qml.PauliZ(0)) - - assert circuit() == [{-1: n_shots}, {1: n_shots}] - - -@pytest.mark.all_interfaces -@pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) -def test_batched_counts_and_expval_operator_finite_shots(interface): - """Check all interfaces with observable measurement counts, batching and finite shots""" - n_shots = 10 - dev = qml.device("default.qubit", wires=3, shots=n_shots) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.pow(qml.PauliX(0), z=[1, 2]) - return qml.counts(qml.PauliZ(0)), qml.expval(qml.PauliZ(0)) - - res = circuit() - assert isinstance(res, tuple) and len(res) == 2 - assert res[0] == [{-1: n_shots}, {1: n_shots}] - assert len(res[1]) == 2 and qml.math.allequal(res[1], [-1, 1]) diff --git a/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py deleted file mode 100644 index 26b3caaf3be..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_expval_default_qubit_2.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2018-2020 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 expval module""" -import copy -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import Expectation, Shots -from pennylane.measurements.expval import ExpectationMP - - -class TestExpval: - """Tests for the expval function""" - - @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) - def test_value(self, tol, shots): - """Test that the expval interface works""" - dev = qml.device("default.qubit", wires=2, shots=shots) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.expval(qml.PauliY(0)) - - x = 0.54 - res = circuit(x) - expected = -np.sin(x) - - atol = tol if shots is None else 0.05 - rtol = 0 if shots is None else 0.05 - assert np.allclose(res, expected, atol=atol, rtol=rtol) - - r_dtype = np.float64 - if isinstance(res, tuple): - assert res[0].dtype == r_dtype - assert res[1].dtype == r_dtype - else: - assert res.dtype == r_dtype - - def test_not_an_observable(self): - """Test that a warning is raised if the provided - argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.52, wires=0) - return qml.expval(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - - with pytest.warns(UserWarning, match="Prod might not be hermitian."): - _ = circuit() - - def test_observable_return_type_is_expectation(self): - """Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - res = qml.expval(qml.PauliZ(0)) - assert res.return_type is Expectation - return res - - circuit() - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_numeric_type(self, obs): - """Test that the numeric type is correct.""" - res = qml.expval(obs) - assert res.numeric_type is float - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_shape(self, obs): - """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=1) - - res = qml.expval(obs) - # pylint: disable=use-implicit-booleaness-not-comparison - assert res.shape(dev, Shots(None)) == () - assert res.shape(dev, Shots(100)) == () - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_shape_shot_vector(self, obs): - """Test that the shape is correct with the shot vector too.""" - res = qml.expval(obs) - shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) - assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) - - @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) - @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) - def test_projector_expval(self, state, shots): - """Tests that the expectation of a ``Projector`` object is computed correctly for both of - its subclasses.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - np.random.seed(42) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(0) - return qml.expval(qml.Projector(state, wires=range(3))) - - res = circuit() - expected = [0.5, 0.5] if isinstance(shots, list) else 0.5 - assert np.allclose(res, expected, atol=0.02, rtol=0.02) - - def test_permuted_wires(self): - """Test that the expectation value of an operator with permuted wires is the same.""" - obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) - obs_2 = qml.prod( - qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) - ) - - dev = qml.device("default.qubit", wires=["h", 8, 10]) - - @qml.qnode(dev) - def circuit(): - qml.RX(1.23, wires=["h"]) - qml.RY(2.34, wires=[8]) - return qml.expval(obs) - - @qml.qnode(dev) - def circuit2(): - qml.RX(1.23, wires=["h"]) - qml.RY(2.34, wires=[8]) - return qml.expval(obs_2) - - assert circuit() == circuit2() - - def test_copy_observable(self): - """Test that the observable is copied if present.""" - m = qml.expval(qml.PauliX(0)) - copied_m = copy.copy(m) - assert m.obs is not copied_m.obs - assert qml.equal(m.obs, copied_m.obs) - - def test_copy_eigvals(self): - """Test that the eigvals value is just assigned to new mp without copying.""" - # pylint: disable=protected-access - m = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0)) - copied_m = copy.copy(m) - assert m._eigvals is copied_m._eigvals - - def test_standard_obs(self): - """Check that the hash of an expectation value of an observable can distinguish different observables.""" - - o1 = qml.prod(qml.PauliX(0), qml.PauliY(1)) - o2 = qml.prod(qml.PauliX(0), qml.PauliZ(1)) - - assert qml.expval(o1).hash == qml.expval(o1).hash - assert qml.expval(o2).hash == qml.expval(o2).hash - assert qml.expval(o1).hash != qml.expval(o2).hash - - o3 = qml.sum(qml.PauliX("a"), qml.PauliY("b")) - assert qml.expval(o1).hash != qml.expval(o3).hash - - def test_eigvals(self): - """Test that the eigvals property controls the hash property.""" - m1 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0)) - m2 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(0), id="something") - - assert m1.hash == m2.hash - - m3 = ExpectationMP(eigvals=[-0.5, 0.5], wires=qml.wires.Wires(1)) - assert m1.hash != m3.hash - - m4 = ExpectationMP(eigvals=[-1, 1], wires=qml.wires.Wires(1)) - assert m1.hash != m4.hash - assert m3.hash != m4.hash diff --git a/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py deleted file mode 100644 index 3b29552cf4d..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_measurements_default_qubit_2.py +++ /dev/null @@ -1,581 +0,0 @@ -# Copyright 2018-2020 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 measurements module""" -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import ( - ClassicalShadowMP, - Counts, - CountsMP, - Expectation, - ExpectationMP, - MeasurementProcess, - MeasurementTransform, - MidMeasure, - MutualInfoMP, - Probability, - ProbabilityMP, - Sample, - SampleMeasurement, - SampleMP, - ShadowExpvalMP, - Shots, - State, - StateMeasurement, - StateMP, - Variance, - VarianceMP, - VnEntropyMP, - expval, - sample, - var, -) -from pennylane.operation import DecompositionUndefinedError -from pennylane.queuing import AnnotatedQueue - -# pylint: disable=too-few-public-methods, unused-argument - - -class NotValidMeasurement(MeasurementProcess): - @property - def return_type(self): - return "NotValidReturnType" - - -@pytest.mark.parametrize( - "return_type, value", - [ - (Expectation, "expval"), - (Sample, "sample"), - (Counts, "counts"), - (Variance, "var"), - (Probability, "probs"), - (State, "state"), - (MidMeasure, "measure"), - ], -) -def test_ObservableReturnTypes(return_type, value): - """Test the ObservableReturnTypes enum value, repr, and enum membership.""" - - assert return_type.value == value - assert isinstance(return_type, qml.measurements.ObservableReturnTypes) - assert repr(return_type) == value - - -def test_no_measure(): - """Test that failing to specify a measurement - raises an exception""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(x): - qml.RX(x, wires=0) - return qml.PauliY(0) - - with pytest.raises(qml.QuantumFunctionError, match="must return either a single measurement"): - _ = circuit(0.65) - - -def test_numeric_type_unrecognized_error(): - """Test that querying the numeric type of a measurement process with an - unrecognized return type raises an error.""" - - mp = NotValidMeasurement() - with pytest.raises( - qml.QuantumFunctionError, - match="The numeric type of the measurement NotValidMeasurement is not defined", - ): - _ = mp.numeric_type - - -def test_shape_unrecognized_error(): - """Test that querying the shape of a measurement process with an - unrecognized return type raises an error.""" - dev = qml.device("default.qubit", wires=2) - mp = NotValidMeasurement() - with pytest.raises( - qml.QuantumFunctionError, - match="The shape of the measurement NotValidMeasurement is not defined", - ): - mp.shape(dev, Shots(None)) - - -def test_none_return_type(): - """Test that a measurement process without a return type property has return_type - `None`""" - - class NoReturnTypeMeasurement(MeasurementProcess): - """Dummy measurement process with no return type.""" - - mp = NoReturnTypeMeasurement() - assert mp.return_type is None - - -def test_eq_correctness(): - """Test that using `==` on two equivalent operators is True when both measurement - processes are the same object and False otherwise.""" - - class DummyMP(MeasurementProcess): - """Dummy measurement process with no return type.""" - - mp1 = DummyMP(0) - mp2 = DummyMP(0) - - with pytest.warns(UserWarning, match="The behaviour of measurement process equality"): - assert mp1 == mp1 # pylint: disable=comparison-with-itself - assert mp1 != mp2 - - -def test_hash_correctness(): - """Test that the hash of two equivalent measurement processes is the same when - both are the same object and different otherwise.""" - - class DummyMP(MeasurementProcess): - """Dummy measurement process with no return type.""" - - mp1 = DummyMP(0) - mp2 = DummyMP(0) - - with pytest.warns(UserWarning, match="The behaviour of measurement process hashing"): - assert len({mp1, mp1}) == 1 - assert len({mp1, mp2}) == 2 - - -@pytest.mark.parametrize( - "stat_func,return_type", [(expval, Expectation), (var, Variance), (sample, Sample)] -) -class TestStatisticsQueuing: - """Tests for annotating the return types of the statistics functions""" - - @pytest.mark.parametrize( - "op", - [qml.PauliX, qml.PauliY, qml.PauliZ, qml.Hadamard, qml.Identity], - ) - def test_annotating_obs_return_type(self, stat_func, return_type, op): - """Test that the return_type related info is updated for a - measurement""" - with AnnotatedQueue() as q: - A = op(0) - stat_func(A) - - assert len(q.queue) == 1 - meas_proc = q.queue[0] - assert isinstance(meas_proc, MeasurementProcess) - assert meas_proc.return_type == return_type - - def test_annotating_tensor_hermitian(self, stat_func, return_type): - """Test that the return_type related info is updated for a measurement - when called for an Hermitian observable""" - - mx = np.array([[1, 0], [0, 1]]) - - with AnnotatedQueue() as q: - Herm = qml.Hermitian(mx, wires=[1]) - stat_func(Herm) - - assert len(q.queue) == 1 - meas_proc = q.queue[0] - assert isinstance(meas_proc, MeasurementProcess) - assert meas_proc.return_type == return_type - - @pytest.mark.parametrize( - "op1,op2", - [ - (qml.PauliY, qml.PauliX), - (qml.Hadamard, qml.Hadamard), - (qml.PauliY, qml.Identity), - (qml.Identity, qml.Identity), - ], - ) - def test_annotating_tensor_return_type(self, op1, op2, stat_func, return_type): - """Test that the return_type related info is updated for a measurement - when called for an Tensor observable""" - with AnnotatedQueue() as q: - A = op1(0) - B = op2(1) - tensor_op = A @ B - stat_func(tensor_op) - - assert len(q.queue) == 1 - meas_proc = q.queue[0] - assert isinstance(meas_proc, MeasurementProcess) - assert meas_proc.return_type == return_type - - @pytest.mark.parametrize( - "op1,op2", - [ - (qml.PauliY, qml.PauliX), - (qml.Hadamard, qml.Hadamard), - (qml.PauliY, qml.Identity), - (qml.Identity, qml.Identity), - ], - ) - def test_queueing_tensor_observable(self, op1, op2, stat_func, return_type): - """Test that if the constituent components of a tensor operation are not - found in the queue for annotation, they are not queued or annotated.""" - A = op1(0) - B = op2(1) - - with AnnotatedQueue() as q: - tensor_op = A @ B - stat_func(tensor_op) - - assert len(q.queue) == 1 - - meas_proc = q.queue[0] - assert isinstance(meas_proc, MeasurementProcess) - assert meas_proc.return_type == return_type - - def test_not_an_observable(self, stat_func, return_type): # pylint: disable=unused-argument - """Test that a UserWarning is raised if the provided - argument might not be hermitian.""" - if stat_func is sample: - pytest.skip("Sampling is not yet supported with symbolic operators.") - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.52, wires=0) - return stat_func(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - - with pytest.warns(UserWarning, match="Prod might not be hermitian."): - _ = circuit() - - -class TestProperties: - """Test for the properties""" - - def test_wires_match_observable(self): - """Test that the wires of the measurement process - match an internal observable""" - obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=["a", "b"]) - m = qml.expval(op=obs) - - assert np.all(m.wires == obs.wires) - - def test_eigvals_match_observable(self): - """Test that the eigenvalues of the measurement process - match an internal observable""" - obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) - m = qml.expval(op=obs) - - assert np.all(m.eigvals() == np.array([1, 2, 3, 4])) - - # changing the observable data should be reflected - obs.data = [np.diag([5, 6, 7, 8])] - assert np.all(m.eigvals() == np.array([5, 6, 7, 8])) - - def test_error_obs_and_eigvals(self): - """Test that providing both eigenvalues and an observable - results in an error""" - obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) - - with pytest.raises(ValueError, match="Cannot set the eigenvalues"): - ExpectationMP(obs=obs, eigvals=[0, 1]) - - def test_error_obs_and_wires(self): - """Test that providing both wires and an observable - results in an error""" - obs = qml.Hermitian(np.diag([1, 2, 3, 4]), wires=[0, 1]) - - with pytest.raises(ValueError, match="Cannot set the wires"): - ExpectationMP(obs=obs, wires=qml.wires.Wires([0, 1])) - - def test_observable_with_no_eigvals(self): - """An observable with no eigenvalues defined should cause - the eigvals method to return a NotImplementedError""" - obs = qml.NumberOperator(wires=0) - m = qml.expval(op=obs) - assert m.eigvals() is None - - def test_repr(self): - """Test the string representation of a MeasurementProcess.""" - m = qml.expval(op=qml.PauliZ(wires="a") @ qml.PauliZ(wires="b")) - expected = "expval(PauliZ(wires=['a']) @ PauliZ(wires=['b']))" - assert str(m) == expected - - m = qml.probs(op=qml.PauliZ(wires="a")) - expected = "probs(PauliZ(wires=['a']))" - assert str(m) == expected - - m = ProbabilityMP(eigvals=(1, 0), wires=qml.wires.Wires(0)) - assert repr(m) == "probs(eigvals=[1 0], wires=[0])" - - -class TestExpansion: - """Test for measurement expansion""" - - def test_expand_pauli(self): - """Test the expansion of a Pauli observable""" - obs = qml.PauliX(0) @ qml.PauliY(1) - m = qml.expval(op=obs) - tape = m.expand() - - assert len(tape.operations) == 4 - - assert tape.operations[0].name == "Hadamard" - assert tape.operations[0].wires.tolist() == [0] - - assert tape.operations[1].name == "PauliZ" - assert tape.operations[1].wires.tolist() == [1] - assert tape.operations[2].name == "S" - assert tape.operations[2].wires.tolist() == [1] - assert tape.operations[3].name == "Hadamard" - assert tape.operations[3].wires.tolist() == [1] - - assert len(tape.measurements) == 1 - assert tape.measurements[0].return_type is Expectation - assert tape.measurements[0].wires.tolist() == [0, 1] - assert np.all(tape.measurements[0].eigvals() == np.array([1, -1, -1, 1])) - - def test_expand_hermitian(self, tol): - """Test the expansion of an hermitian observable""" - H = np.array([[1, 2], [2, 4]]) - obs = qml.Hermitian(H, wires=["a"]) - - m = qml.expval(op=obs) - tape = m.expand() - - assert len(tape.operations) == 1 - - assert tape.operations[0].name == "QubitUnitary" - assert tape.operations[0].wires.tolist() == ["a"] - assert np.allclose( - tape.operations[0].parameters[0], - np.array([[-2, 1], [1, 2]]) / np.sqrt(5), - atol=tol, - rtol=0, - ) - - assert len(tape.measurements) == 1 - assert tape.measurements[0].return_type is Expectation - assert tape.measurements[0].wires.tolist() == ["a"] - assert np.all(tape.measurements[0].eigvals() == np.array([0, 5])) - - def test_expand_no_observable(self): - """Check that an exception is raised if the measurement to - be expanded has no observable""" - with pytest.raises(DecompositionUndefinedError): - ProbabilityMP(wires=qml.wires.Wires([0, 1])).expand() - - @pytest.mark.parametrize( - "m", - [ - ExpectationMP(obs=qml.PauliX(0) @ qml.PauliY(1)), - VarianceMP(obs=qml.PauliX(0) @ qml.PauliY(1)), - ProbabilityMP(obs=qml.PauliX(0) @ qml.PauliY(1)), - ExpectationMP(obs=qml.PauliX(5)), - VarianceMP(obs=qml.PauliZ(0) @ qml.Identity(3)), - ProbabilityMP(obs=qml.PauliZ(0) @ qml.Identity(3)), - ], - ) - def test_has_decomposition_true_pauli(self, m): - """Test that measurements of Paulis report to have a decomposition.""" - assert m.has_decomposition is True - - def test_has_decomposition_true_hermitian(self): - """Test that measurements of Hermitians report to have a decomposition.""" - H = np.array([[1, 2], [2, 4]]) - obs = qml.Hermitian(H, wires=["a"]) - m = qml.expval(op=obs) - assert m.has_decomposition is True - - def test_has_decomposition_false_hermitian_wo_diaggates(self): - """Test that measurements of Hermitians report to have a decomposition.""" - - class HermitianNoDiagGates(qml.Hermitian): - @property - def has_diagonalizing_gates( - self, - ): # pylint: disable=invalid-overridden-method, arguments-renamed - return False - - H = np.array([[1, 2], [2, 4]]) - obs = HermitianNoDiagGates(H, wires=["a"]) - m = ExpectationMP(obs=obs) - assert m.has_decomposition is False - - def test_has_decomposition_false_no_observable(self): - """Check a MeasurementProcess without observable to report not having a decomposition""" - m = ProbabilityMP(wires=qml.wires.Wires([0, 1])) - assert m.has_decomposition is False - - m = ExpectationMP(wires=qml.wires.Wires([0, 1]), eigvals=np.ones(4)) - assert m.has_decomposition is False - - @pytest.mark.parametrize( - "m", - [ - SampleMP(), - SampleMP(wires=["a", 1]), - CountsMP(all_outcomes=True), - CountsMP(wires=["a", 1], all_outcomes=True), - CountsMP(), - CountsMP(wires=["a", 1]), - StateMP(), - VnEntropyMP(wires=["a", 1]), - MutualInfoMP(wires=[["a", 1], ["b", 2]]), - ProbabilityMP(wires=["a", 1]), - ], - ) - def test_samples_computational_basis_true(self, m): - """Test that measurements of Paulis report to have a decomposition.""" - assert m.samples_computational_basis is True - - @pytest.mark.parametrize( - "m", - [ - ExpectationMP(obs=qml.PauliX(2)), - VarianceMP(obs=qml.PauliX("a")), - ProbabilityMP(obs=qml.PauliX("b")), - SampleMP(obs=qml.PauliX("a")), - CountsMP(obs=qml.PauliX("a")), - ShadowExpvalMP(H=qml.PauliX("a")), - ClassicalShadowMP(wires=[["a", 1], ["b", 2]]), - ], - ) - def test_samples_computational_basis_false(self, m): - """Test that measurements of Paulis report to have a decomposition.""" - assert m.samples_computational_basis is False - - -class TestDiagonalizingGates: - def test_no_expansion(self): - """Test a measurement that has no expansion""" - m = qml.sample() - - assert m.diagonalizing_gates() == [] - - def test_obs_diagonalizing_gates(self): - """Test diagonalizing_gates method with and observable.""" - m = qml.expval(qml.PauliY(0)) - - res = m.diagonalizing_gates() - - assert len(res) == 3 - - expected_classes = [qml.PauliZ, qml.S, qml.Hadamard] - for op, c in zip(res, expected_classes): - assert isinstance(op, c) - - -class TestSampleMeasurement: - """Tests for the SampleMeasurement class.""" - - def test_custom_sample_measurement(self): - """Test the execution of a custom sampled measurement.""" - - class MyMeasurement(SampleMeasurement): - # pylint: disable=signature-differs - def process_samples(self, samples, wire_order, shot_range=None, bin_size=None): - return qml.math.sum(samples[..., self.wires]) - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(0) - return MyMeasurement(wires=[0]), MyMeasurement(wires=[1]) - - assert qml.math.allequal(circuit(), [1000, 0]) - - def test_sample_measurement_without_shots(self): - """Test that executing a sampled measurement with ``shots=None`` raises an error.""" - - class MyMeasurement(SampleMeasurement): - # pylint: disable=signature-differs - def process_samples(self, samples, wire_order, shot_range, bin_size): - return qml.math.sum(samples[..., self.wires]) - - @property - def return_type(self): - return Sample - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(0) - return MyMeasurement(wires=[0]), MyMeasurement(wires=[1]) - - with pytest.raises( - qml.DeviceError, - match="Analytic circuits must only contain StateMeasurements; got sample", - ): - circuit() - - -class TestStateMeasurement: - """Tests for the SampleMeasurement class.""" - - def test_custom_state_measurement(self): - """Test the execution of a custom state measurement.""" - - class MyMeasurement(StateMeasurement): - def process_state(self, state, wire_order): - return qml.math.sum(state) - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - return MyMeasurement() - - assert circuit() == 1 - - def test_state_measurement_with_shots(self): - """Test that executing a state measurement with shots raises an error.""" - - class MyMeasurement(StateMeasurement): - def process_state(self, state, wire_order): - return qml.math.sum(state) - - @property - def return_type(self): - return State - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - return MyMeasurement() - - with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): - circuit() - - -class TestMeasurementTransform: - """Tests for the MeasurementTransform class.""" - - 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) - return len(tapes) - - def process_samples(self, samples, wire_order, shot_range=None, bin_size=None): - return [True] - - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - return CountTapesMP(wires=[0]) - - assert circuit() == 1 diff --git a/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py deleted file mode 100644 index 6aa70a21457..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_mid_measure_default_qubit_2.py +++ /dev/null @@ -1,471 +0,0 @@ -# Copyright 2018-2020 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 mid_measure module""" - -from itertools import product -import pytest - -import pennylane as qml -import pennylane.numpy as np -from pennylane.measurements import MidMeasureMP, MeasurementValue -from pennylane.wires import Wires - -# pylint: disable=too-few-public-methods, too-many-public-methods - - -def test_samples_computational_basis(): - """Test that samples_computational_basis is always false for mid circuit measurements.""" - m = MidMeasureMP(Wires(0)) - assert not m.samples_computational_basis - - -class TestMeasure: - """Tests for the measure function""" - - def test_many_wires_error(self): - """Test that an error is raised if multiple wires are passed to - measure.""" - with pytest.raises( - qml.QuantumFunctionError, - match="Only a single qubit can be measured in the middle of the circuit", - ): - qml.measure(wires=[0, 1]) - - def test_hash(self): - """Test that the hash for `MidMeasureMP` is defined correctly.""" - m1 = MidMeasureMP(Wires(0), id="m1") - m2 = MidMeasureMP(Wires(0), id="m2") - m3 = MidMeasureMP(Wires(1), id="m1") - m4 = MidMeasureMP(Wires(0), id="m1") - - assert m1.hash != m2.hash - assert m1.hash != m3.hash - assert m1.hash == m4.hash - - -mp1 = MidMeasureMP(Wires(0), id="m0") -mp2 = MidMeasureMP(Wires(1), id="m1") -mp3 = MidMeasureMP(Wires(2), id="m2") - - -class TestMeasurementValueManipulation: - """Test all the dunder methods associated with the MeasurementValue class""" - - def test_apply_function_to_measurement(self): - """Test the general _apply method that can apply an arbitrary function to a measurement.""" - - m = MeasurementValue([mp1], lambda v: v) - - sin_of_m = m._apply(np.sin) # pylint: disable=protected-access - assert sin_of_m[0] == 0.0 - assert sin_of_m[1] == np.sin(1) - - def test_and_with_bool(self): - """Test the __add__ dunder method between MeasurementValue and scalar.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = m & False - assert not m_add[0] - assert not m_add[1] - - def test_and_to_measurements(self): - """Test the __add__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - sum_of_measurements = m0 & m1 - assert not sum_of_measurements[0] - assert not sum_of_measurements[1] - assert not sum_of_measurements[2] - assert sum_of_measurements[3] - - def test_or_with_bool(self): - """Test the __or__ dunder method between MeasurementValue and scalar.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = m | False - assert not m_add[0] - assert m_add[1] - - def test_or_to_measurements(self): - """Test the __or__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - sum_of_measurements = m0 | m1 - assert not sum_of_measurements[0] - assert sum_of_measurements[1] - assert sum_of_measurements[2] - assert sum_of_measurements[3] - - def test_add_with_scalar(self): - """Test the __add__ dunder method between MeasurementValue and scalar.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = m + 5 - assert m_add[0] == 5 - assert m_add[1] == 6 - - def test_add_to_measurements(self): - """Test the __add__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - sum_of_measurements = m0 + m1 - assert sum_of_measurements[0] == 0 - assert sum_of_measurements[1] == 1 - assert sum_of_measurements[2] == 1 - assert sum_of_measurements[3] == 2 - - def test_radd_with_scalar(self): - """Test the __radd__ dunder method between a scalar and a MeasurementValue.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = 5 + m - assert m_add[0] == 5 - assert m_add[1] == 6 - - def test_sub_with_scalar(self): - """Test the __sub__ dunder method between MeasurementValue and scalar.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = m - 5 - assert m_add[0] == -5 - assert m_add[1] == -4 - - def test_sub_to_measurements(self): - """Test the __sub__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - sum_of_measurements = m0 - m1 - assert sum_of_measurements[0] == 0 - assert sum_of_measurements[1] == -1 - assert sum_of_measurements[2] == 1 - assert sum_of_measurements[3] == 0 - - def test_rsub_with_scalar(self): - """Test the __rsub__ dunder method between a scalar and a MeasurementValue.""" - m = MeasurementValue([mp1], lambda v: v) - m_add = 5 - m - assert m_add[0] == 5 - assert m_add[1] == 4 - - def test_mul_with_scalar(self): - """Test the __mul__ dunder method between a MeasurementValue and a scalar""" - m = MeasurementValue([mp1], lambda v: v) - m_mul = m * 5 - assert m_mul[0] == 0 - assert m_mul[1] == 5 - - def test_mul_with_measurement(self): - """Test the __mul__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - mul_of_measurements = m0 * m1 - assert mul_of_measurements[0] == 0 - assert mul_of_measurements[1] == 0 - assert mul_of_measurements[2] == 0 - assert mul_of_measurements[3] == 1 - - def test_rmul_with_scalar(self): - """Test the __rmul__ dunder method between a scalar and a MeasurementValue.""" - m = MeasurementValue([mp1], lambda v: v) - m_mul = 5 * m - assert m_mul[0] == 0 - assert m_mul[1] == 5 - - def test_truediv_with_scalar(self): - """Test the __truediv__ dunder method between a MeasurementValue and a scalar""" - m = MeasurementValue([mp1], lambda v: v) - m_mul = m / 5.0 - assert m_mul[0] == 0 - assert m_mul[1] == 1 / 5.0 - - def test_truediv_with_measurement(self): - """Test the __truediv__ dunder method between two MeasurementValues.""" - m0 = MeasurementValue([mp1], lambda v: v) + 3.0 - m1 = MeasurementValue([mp2], lambda v: v) + 5.0 - mul_of_measurements = m0 / m1 - assert mul_of_measurements[0] == 3.0 / 5.0 - assert mul_of_measurements[1] == 3.0 / 6.0 - assert mul_of_measurements[2] == 4.0 / 5.0 - assert mul_of_measurements[3] == 4.0 / 6.0 - - def test_rtruediv_with_scalar(self): - """Test the __rtruediv__ dunder method between a scalar and a MeasurementValue.""" - m = MeasurementValue([mp1], lambda v: v) + 3.0 - m_mul = 5 / m - assert m_mul[0] == 5 / 3.0 - assert m_mul[1] == 5 / 4.0 - - def test_inversion(self): - """Test the __inv__ dunder method.""" - m = MeasurementValue([mp1], lambda v: v) - m_inversion = ~m - assert m_inversion[0] is True - assert m_inversion[1] is False - - def test_lt(self): - """Test the __lt__ dunder method between a MeasurementValue and a float.""" - m = MeasurementValue([mp1], lambda v: v) - m_inversion = m < 0.5 - assert m_inversion[0] is True - assert m_inversion[1] is False - - def test_lt_with_other_measurement_value(self): - """Test the __lt__ dunder method between two MeasurementValues""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 < m2 - assert compared[0] is False - assert compared[1] is True - assert compared[2] is False - assert compared[3] is False - - def test_gt(self): - """Test the __gt__ dunder method between a MeasurementValue and a float.""" - m = MeasurementValue([mp1], lambda v: v) - m_inversion = m > 0.5 - assert m_inversion[0] is False - assert m_inversion[1] is True - - def test_gt_with_other_measurement_value(self): - """Test the __gt__ dunder method between two MeasurementValues.""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 > m2 - assert compared[0] is False - assert compared[1] is False - assert compared[2] is True - assert compared[3] is False - - def test_le(self): - """Test the __le__ dunder method between a MeasurementValue and a float.""" - m = MeasurementValue([mp1], lambda v: v) - m_inversion = m <= 0.5 - assert m_inversion[0] is True - assert m_inversion[1] is False - - def test_le_with_other_measurement_value(self): - """Test the __le__ dunder method between two MeasurementValues""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 <= m2 - assert compared[0] is True - assert compared[1] is True - assert compared[2] is False - assert compared[3] is True - - def test_ge(self): - """Test the __ge__ dunder method between a MeasurementValue and a flaot.""" - m = MeasurementValue([mp1], lambda v: v) - m_inversion = m >= 0.5 - assert m_inversion[0] is False - assert m_inversion[1] is True - - def test_ge_with_other_measurement_value(self): - """Test the __ge__ dunder method between two MeasurementValues.""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 >= m2 - assert compared[0] is True - assert compared[1] is False - assert compared[2] is True - assert compared[3] is True - - def test_equality_with_scalar(self): - """Test the __eq__ dunder method between a MeasurementValue and an integer.""" - m = MeasurementValue([mp1], lambda v: v) - m_eq = m == 0 - assert m_eq[0] is True # confirming value is actually eq to True, not just truthy - assert m_eq[1] is False - - def test_equality_with_scalar_opposite(self): - """Test the __eq__ dunder method between a MeasurementValue and an integer.""" - m = MeasurementValue([mp1], lambda v: v) - m_eq = m == 1 - assert m_eq[0] is False - assert m_eq[1] is True - - def test_eq_with_other_measurement_value(self): - """Test the __eq__ dunder method between two MeasurementValues.""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 == m2 - assert compared[0] is True - assert compared[1] is False - assert compared[2] is False - assert compared[3] is True - - def test_non_equality_with_scalar(self): - """Test the __ne__ dunder method between a MeasurementValue and an integer.""" - m = MeasurementValue([mp1], lambda v: v) - m_eq = m != 0 - assert m_eq[0] is False # confirming value is actually eq to True, not just truthy - assert m_eq[1] is True - - def test_non_equality_with_scalar_opposite(self): - """Test the __ne__ dunder method between a MeasurementValue and an integer.""" - m = MeasurementValue([mp1], lambda v: v) - m_eq = m != 1 - assert m_eq[0] is True - assert m_eq[1] is False - - def test_non_eq_with_other_measurement_value(self): - """Test the __ne__ dunder method between two MeasurementValues.""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 != m2 - assert compared[0] is False - assert compared[1] is True - assert compared[2] is True - assert compared[3] is False - - def test_merge_measurements_values_dependant_on_same_measurement(self): - """Test that the _merge operation does not create more than 2 branches when combining two MeasurementValues - that are based on the same measurement.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp1], lambda v: v) - combined = m0 + m1 - assert combined[0] == 0 - assert combined[1] == 2 - - def test_combine_measurement_value_with_non_measurement(self): - """Test that we can use dunder methods to combine a MeasurementValue with the underlying "primitive" - of that measurement value.""" - m0 = MeasurementValue([mp1], lambda v: v) - out = m0 + 10 - assert out[0] == 10 - assert out[1] == 11 - - def test_branches_method(self): - """Test the __eq__ dunder method between two MeasurementValues.""" - m1 = MeasurementValue([mp1], lambda v: v) - m2 = MeasurementValue([mp2], lambda v: v) - compared = m1 == m2 - branches = compared.branches - assert branches[(0, 0)] is True - assert branches[(0, 1)] is False - assert branches[(1, 0)] is False - assert branches[(1, 1)] is True - - def test_str(self): - """Test that the output of the __str__ dunder method is as expected""" - m = MeasurementValue([mp1], lambda v: v) - assert str(m) == "if m0=0 => 0\nif m0=1 => 1" - - def test_complex_str(self): - """Test that the output of the __str__ dunder method is as expected - w.r.t a more complicated MeasurementValue""" - a = MeasurementValue([mp1], lambda v: v) - b = MeasurementValue([mp2], lambda v: v) - assert ( - str(a + b) - == """if m0=0,m1=0 => 0 -if m0=0,m1=1 => 1 -if m0=1,m1=0 => 1 -if m0=1,m1=1 => 2""" - ) - - -unary_dunders = ["__invert__"] - - -measurement_value_binary_dunders = [ - "__add__", - "__mul__", - "__radd__", - "__rmul__", - "__rsub__", - "__sub__", -] - -boolean_binary_dunders = [ - "__and__", - "__eq__", - "__ge__", - "__gt__", - "__le__", - "__lt__", - "__ne__", - "__or__", -] - -binary_dunders = measurement_value_binary_dunders + boolean_binary_dunders - -divisions = ["__rtruediv__", "__truediv__"] - - -class TestMeasurementCompositeValueManipulation: - """Test composite application of dunder methods associated with the MeasurementValue class""" - - @pytest.mark.parametrize("unary_name", unary_dunders) - @pytest.mark.parametrize("binary1_name, binary2_name", product(binary_dunders, binary_dunders)) - def test_composition_between_measurement_values(self, unary_name, binary1_name, binary2_name): - """Test the composition of dunder methods.""" - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - - # 1. Apply a unary dunder method - unary = getattr(m0, unary_name) - m0 = unary() - assert isinstance(m0, MeasurementValue) - - # 2. Apply first binary dunder method - binary_dunder1 = getattr(m0, binary1_name) - sum_of_measurements = binary_dunder1(m1) - assert isinstance(sum_of_measurements, MeasurementValue) - - # 3. Apply a unary dunder method on the new MV - unary = getattr(sum_of_measurements, unary_name) - m0 = unary() - assert isinstance(m0, MeasurementValue) - - # 4. Apply second binary dunder method - binary_dunder2 = getattr(m0, binary2_name) - - m2 = MeasurementValue([mp1], lambda v: v) - boolean_of_measurements = binary_dunder2(m2) - - assert isinstance(boolean_of_measurements, MeasurementValue) - - @pytest.mark.parametrize("mv_dunder_name", measurement_value_binary_dunders) - @pytest.mark.parametrize("boolean_dunder_name", boolean_binary_dunders) - @pytest.mark.parametrize("scalar", [MeasurementValue([mp2], lambda v: v), 0, 1.0, 1.0 + 0j]) - @pytest.mark.parametrize("boolean", [MeasurementValue([mp3], lambda v: v), True, False, None]) - def test_composition_measurement_values_and_boolean( - self, mv_dunder_name, boolean_dunder_name, scalar, boolean - ): # pylint: disable=too-many-arguments - """Test the composition of dunder methods, applying one whose argument is scalar and one whose argument - is a boolean.""" - m0 = MeasurementValue([mp1], lambda v: v) - - # 1. Apply first binary dunder method between m0 and scalar - binary_dunder1 = getattr(m0, mv_dunder_name) - sum_of_measurements = binary_dunder1(scalar) - assert isinstance(sum_of_measurements, MeasurementValue) - - # 2. Apply second binary dunder method between m0 and boolean - binary_dunder2 = getattr(m0, boolean_dunder_name) - boolean_of_measurements = binary_dunder2(boolean) - assert isinstance(boolean_of_measurements, MeasurementValue) - - @pytest.mark.parametrize("div", divisions) - @pytest.mark.parametrize("other", [MeasurementValue([mp3], lambda v: v) + 5, np.pi]) - @pytest.mark.parametrize("binary", binary_dunders) - def test_composition_with_division(self, binary, div, other): - """Test the composition of dunder methods with division.""" - # 1. Apply a binary dundar - m0 = MeasurementValue([mp1], lambda v: v) - m1 = MeasurementValue([mp2], lambda v: v) - - binary_dunder = getattr(m0, binary) - m0 = binary_dunder(m1) - - # 2. Apply a division method - division_dunder = getattr(m0, div) - res = division_dunder(other) - assert isinstance(res, MeasurementValue) diff --git a/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py deleted file mode 100644 index 0a12a8aab36..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_mutual_info_default_qubit_2.py +++ /dev/null @@ -1,475 +0,0 @@ -# Copyright 2018-2020 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 mutual_info module""" -import copy - -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import MutualInfo, Shots -from pennylane.measurements.mutual_info import MutualInfoMP -from pennylane.wires import Wires - - -class TestMutualInfoUnitTests: - """Tests for the mutual_info function""" - - def test_queue(self): - """Test that the right measurement class is queued.""" - - with qml.queuing.AnnotatedQueue() as q: - m = qml.mutual_info(wires0=[0], wires1=[1]) - - assert q.queue[0] is m - assert isinstance(q.queue[0], MutualInfoMP) - - @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ([1, 10], ((), ()))]) - def test_shape(self, shots, shape): - """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - res = qml.mutual_info(wires0=[0], wires1=[1]) - assert res.shape(dev, Shots(shots)) == shape - - def test_properties(self): - """Test that the properties are correct.""" - meas = qml.mutual_info(wires0=[0], wires1=[1]) - assert meas.numeric_type == float - assert meas.return_type == MutualInfo - - def test_copy(self): - """Test that the ``__copy__`` method also copies the ``log_base`` information.""" - meas = qml.mutual_info(wires0=[0], wires1=[1], log_base=2) - meas_copy = copy.copy(meas) - assert meas_copy.log_base == 2 - assert meas_copy.wires == Wires([0, 1]) - - def test_repr(self): - """Test that the representation includes information about both wires and the log_base""" - m1 = qml.mutual_info(wires0=[0], wires1=[1]) - assert repr(m1) == "MutualInfo(wires0=[0], wires1=[1], log_base=None)" - - def test_hash(self): - """Test the hash property includes the log_base property and the separation of the wires into two subsytems.""" - m1 = MutualInfoMP(wires=[Wires(0), Wires(1)], log_base=2) - m2 = MutualInfoMP(wires=[Wires(0), Wires(1)], log_base=10) - assert m1.hash != m2.hash - - m3 = MutualInfoMP(wires=[Wires((0, 1)), Wires(2)]) - m4 = MutualInfoMP(wires=[Wires((0)), Wires((1, 2))]) - assert m3.hash != m4.hash - - -class TestIntegration: - """Tests for the mutual information functions""" - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - @pytest.mark.parametrize( - "state, expected", - [ - ([1.0, 0.0, 0.0, 0.0], 0), - ([qml.math.sqrt(2) / 2, 0.0, qml.math.sqrt(2) / 2, 0.0], 0), - ([qml.math.sqrt(2) / 2, 0.0, 0.0, qml.math.sqrt(2) / 2], 2 * qml.math.log(2)), - (qml.math.ones(4) * 0.5, 0.0), - ], - ) - def test_mutual_info_output(self, interface, state, expected): - """Test the output of qml.mutual_info""" - dev = qml.device("default.qubit", wires=4) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.StatePrep(state, wires=[0, 1]) - return qml.mutual_info(wires0=[0, 2], wires1=[1, 3]) - - res = circuit() - assert np.allclose(res, expected, atol=1e-6) - - @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.""" - dev = qml.device("default.qubit", wires=2, shots=shots) - - @qml.qnode(device=dev) - def circuit(x): - qml.Hadamard(wires=[0]) - qml.CRX(x, wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): - circuit(0.5) - - diff_methods = ["backprop", "finite-diff"] - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - @pytest.mark.parametrize("params", np.linspace(0, 2 * np.pi, 8)) - def test_qnode_state(self, device, interface, params): - """Test that the mutual information transform works for QNodes by comparing - against analytic values""" - dev = qml.device(device, wires=2) - - params = qml.math.asarray(params, like=interface) - - @qml.qnode(dev, interface=interface) - def circuit(params): - qml.RY(params, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.state() - - actual = qml.qinfo.mutual_info(circuit, wires0=[0], wires1=[1])(params) - - # compare transform results with analytic values - expected = -2 * np.cos(params / 2) ** 2 * np.log( - np.cos(params / 2) ** 2 + 1e-10 - ) - 2 * np.sin(params / 2) ** 2 * np.log(np.sin(params / 2) ** 2 + 1e-10) - - assert np.allclose(actual, expected) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - @pytest.mark.parametrize("params", zip(np.linspace(0, np.pi, 8), np.linspace(0, 2 * np.pi, 8))) - def test_qnode_mutual_info(self, device, interface, params): - """Test that the measurement process for mutual information works for QNodes - by comparing against the mutual information transform""" - dev = qml.device(device, wires=2) - - params = qml.math.asarray(np.array(params), like=interface) - - @qml.qnode(dev, interface=interface) - def circuit_mutual_info(params): - qml.RY(params[0], wires=0) - qml.RY(params[1], wires=1) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - @qml.qnode(dev, interface=interface) - def circuit_state(params): - qml.RY(params[0], wires=0) - qml.RY(params[1], wires=1) - qml.CNOT(wires=[0, 1]) - return qml.state() - - actual = circuit_mutual_info(params) - - # compare measurement results with transform results - expected = qml.qinfo.mutual_info(circuit_state, wires0=[0], wires1=[1])(params) - - assert np.allclose(actual, expected) - - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) - def test_mutual_info_wire_labels(self, device): - """Test that mutual_info is correct with custom wire labels""" - param = np.array([0.678, 1.234]) - wires = ["a", 8] - dev = qml.device(device, wires=wires) - - @qml.qnode(dev) - def circuit(param): - qml.RY(param, wires=wires[0]) - qml.CNOT(wires=wires) - return qml.state() - - actual = qml.qinfo.mutual_info(circuit, wires0=[wires[0]], wires1=[wires[1]])(param) - - # compare transform results with analytic values - expected = -2 * np.cos(param / 2) ** 2 * np.log(np.cos(param / 2) ** 2) - 2 * np.sin( - param / 2 - ) ** 2 * np.log(np.sin(param / 2) ** 2) - - assert np.allclose(actual, expected) - - @pytest.mark.jax - @pytest.mark.parametrize("params", np.linspace(0, 2 * np.pi, 8)) - def test_qnode_state_jax_jit(self, params): - """Test that the mutual information transform works for QNodes by comparing - against analytic values, for the JAX-jit interface""" - import jax - import jax.numpy as jnp - - dev = qml.device("default.qubit", wires=2) - - params = jnp.array(params) - - @qml.qnode(dev, interface="jax-jit") - def circuit(params): - qml.RY(params, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.state() - - actual = jax.jit(qml.qinfo.mutual_info(circuit, wires0=[0], wires1=[1]))(params) - - # compare transform results with analytic values - expected = -2 * jnp.cos(params / 2) ** 2 * jnp.log( - jnp.cos(params / 2) ** 2 + 1e-10 - ) - 2 * jnp.sin(params / 2) ** 2 * jnp.log(jnp.sin(params / 2) ** 2 + 1e-10) - - assert np.allclose(actual, expected) - - @pytest.mark.jax - @pytest.mark.parametrize("params", zip(np.linspace(0, np.pi, 8), np.linspace(0, 2 * np.pi, 8))) - @pytest.mark.parametrize("interface", ["jax-jit"]) - def test_qnode_mutual_info_jax_jit(self, params, interface): - """Test that the measurement process for mutual information works for QNodes - by comparing against the mutual information transform, for the JAX-jit interface""" - import jax - import jax.numpy as jnp - - dev = qml.device("default.qubit", wires=2) - - params = jnp.array(params) - - @qml.qnode(dev, interface=interface) - def circuit_mutual_info(params): - qml.RY(params[0], wires=0) - qml.RY(params[1], wires=1) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - @qml.qnode(dev, interface="jax-jit") - def circuit_state(params): - qml.RY(params[0], wires=0) - qml.RY(params[1], wires=1) - qml.CNOT(wires=[0, 1]) - return qml.state() - - actual = jax.jit(circuit_mutual_info)(params) - - # compare measurement results with transform results - expected = jax.jit(qml.qinfo.mutual_info(circuit_state, wires0=[0], wires1=[1]))(params) - - assert np.allclose(actual, expected) - - @pytest.mark.autograd - @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["auto", "autograd"]) - def test_qnode_grad(self, param, diff_method, interface): - """Test that the gradient of mutual information works for QNodes - with the autograd interface""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(param): - qml.RY(param, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - if param == 0: - # we don't allow gradients to flow through the discontinuity at 0 - expected = 0 - else: - expected = np.sin(param) * ( - np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) - ) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - actual = qml.grad(circuit)(param) - assert np.allclose(actual, expected, atol=tol) - - @pytest.mark.jax - @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax"]) - def test_qnode_grad_jax(self, param, diff_method, interface): - """Test that the gradient of mutual information works for QNodes - with the JAX interface""" - import jax - import jax.numpy as jnp - - dev = qml.device("default.qubit", wires=2) - - param = jnp.array(param) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(param): - qml.RY(param, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - if param == 0: - # we don't allow gradients to flow through the discontinuity at 0 - expected = 0 - else: - expected = jnp.sin(param) * ( - jnp.log(jnp.cos(param / 2) ** 2) - jnp.log(jnp.sin(param / 2) ** 2) - ) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - actual = jax.grad(circuit)(param) - assert np.allclose(actual, expected, atol=tol) - - @pytest.mark.jax - @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax-jit"]) - def test_qnode_grad_jax_jit(self, param, diff_method, interface): - """Test that the gradient of mutual information works for QNodes - with the JAX-jit interface""" - import jax - import jax.numpy as jnp - - dev = qml.device("default.qubit", wires=2) - - param = jnp.array(param) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(param): - qml.RY(param, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - if param == 0: - # we don't allow gradients to flow through the discontinuity at 0 - expected = 0 - else: - expected = jnp.sin(param) * ( - jnp.log(jnp.cos(param / 2) ** 2) - jnp.log(jnp.sin(param / 2) ** 2) - ) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - actual = jax.jit(jax.grad(circuit))(param) - assert np.allclose(actual, expected, atol=tol) - - @pytest.mark.tf - @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["tf"]) - def test_qnode_grad_tf(self, param, diff_method, interface): - """Test that the gradient of mutual information works for QNodes - with the tensorflow interface""" - import tensorflow as tf - - dev = qml.device("default.qubit", wires=2) - - param = tf.Variable(param) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(param): - qml.RY(param, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - if param == 0: - # we don't allow gradients to flow through the discontinuity at 0 - expected = 0 - else: - expected = np.sin(param) * ( - np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) - ) - - with tf.GradientTape() as tape: - out = circuit(param) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - actual = tape.gradient(out, param) - assert np.allclose(actual, expected, atol=tol) - - @pytest.mark.torch - @pytest.mark.parametrize("param", np.linspace(0, 2 * np.pi, 16)) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["torch"]) - def test_qnode_grad_torch(self, param, diff_method, interface): - """Test that the gradient of mutual information works for QNodes - with the torch interface""" - import torch - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(param): - qml.RY(param, wires=0) - qml.CNOT(wires=[0, 1]) - return qml.mutual_info(wires0=[0], wires1=[1]) - - if param == 0: - # we don't allow gradients to flow through the discontinuity at 0 - expected = 0 - else: - expected = np.sin(param) * ( - np.log(np.cos(param / 2) ** 2) - np.log(np.sin(param / 2) ** 2) - ) - - param = torch.tensor(param, requires_grad=True) - out = circuit(param) - out.backward() # pylint: disable=no-member - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - actual = param.grad - assert np.allclose(actual, expected, atol=tol) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("device", ["default.qubit", "default.mixed", "lightning.qubit"]) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tensorflow", "torch"]) - @pytest.mark.parametrize( - "params", [np.array([0.0, 0.0]), np.array([0.3, 0.4]), np.array([0.6, 0.8])] - ) - def test_subsystem_overlap_error(self, device, interface, params): - """Test that an error is raised when the subsystems overlap""" - dev = qml.device(device, wires=3) - - params = qml.math.asarray(params, like=interface) - - @qml.qnode(dev, interface=interface) - def circuit(params): - qml.RY(params[0], wires=0) - qml.RY(params[1], wires=1) - qml.CNOT(wires=[0, 1]) - qml.CNOT(wires=[0, 2]) - return qml.mutual_info(wires0=[0, 1], wires1=[1, 2]) - - msg = "Subsystems for computing mutual information must not overlap" - with pytest.raises(qml.QuantumFunctionError, match=msg): - circuit(params) - - @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])]) - def test_custom_wire_labels_error(self, interface, params): - """Tests that an error is raised when mutual information is measured - with custom wire labels""" - dev = qml.device("default.qubit", wires=["a", "b"]) - - params = qml.math.asarray(params, like=interface) - - @qml.qnode(dev, interface=interface) - def circuit(params): - qml.RY(params[0], wires="a") - qml.RY(params[1], wires="b") - qml.CNOT(wires=["a", "b"]) - return qml.mutual_info(wires0=["a"], wires1=["b"]) - - @qml.qnode(dev, interface=interface) - def circuit_expected(params): - qml.RY(params[0], wires="a") - qml.RY(params[1], wires="b") - qml.CNOT(wires=["a", "b"]) - return qml.state() - - actual = circuit(params) - expected = qml.qinfo.mutual_info(circuit_expected, wires0=["a"], wires1=["b"])(params) - assert np.allclose(actual, expected) diff --git a/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py deleted file mode 100644 index 90eb587b9d8..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_probs_default_qubit_2.py +++ /dev/null @@ -1,646 +0,0 @@ -# Copyright 2018-2020 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 probs module""" -import numpy as np -import pytest - -import pennylane as qml -from pennylane import numpy as pnp -from pennylane.measurements import ( - MeasurementProcess, - Probability, - ProbabilityMP, - Shots, -) -from pennylane.queuing import AnnotatedQueue - - -# make the test deterministic -np.random.seed(42) - - -@pytest.fixture(name="init_state") -def fixture_init_state(): - """Fixture that creates an initial state""" - - def _init_state(n): - """An initial state over n wires""" - state = np.random.random([2**n]) + np.random.random([2**n]) * 1j - state /= np.linalg.norm(state) - return state - - return _init_state - - -class TestProbs: - """Tests for the probs function""" - - # pylint:disable=too-many-public-methods - - def test_queue(self): - """Test that the right measurement class is queued.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - return qml.probs(wires=0) - - circuit() - - assert isinstance(circuit.tape[0], ProbabilityMP) - - def test_numeric_type(self): - """Test that the numeric type is correct.""" - res = qml.probs(wires=0) - assert res.numeric_type is float - - @pytest.mark.parametrize("wires", [[0], [2, 1], ["a", "c", 3]]) - @pytest.mark.parametrize("shots", [None, 10]) - def test_shape(self, wires, shots): - """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - res = qml.probs(wires=wires) - assert res.shape(dev, Shots(shots)) == (2 ** len(wires),) - - @pytest.mark.parametrize("wires", [[0], [2, 1], ["a", "c", 3]]) - def test_shape_shot_vector(self, wires): - """Test that the shape is correct with the shot vector too.""" - res = qml.probs(wires=wires) - shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) - assert res.shape(dev, Shots(shot_vector)) == ( - (2 ** len(wires),), - (2 ** len(wires),), - (2 ** len(wires),), - ) - - @pytest.mark.parametrize("wires", [[0], [0, 1], [1, 0, 2]]) - def test_annotating_probs(self, wires): - """Test annotating probs""" - with AnnotatedQueue() as q: - qml.probs(wires) - - assert len(q.queue) == 1 - - meas_proc = q.queue[0] - assert isinstance(meas_proc, MeasurementProcess) - assert meas_proc.return_type == Probability - - def test_probs_empty_wires(self): - """Test that using ``qml.probs`` with an empty wire list raises an error.""" - with pytest.raises(ValueError, match="Cannot set an empty list of wires."): - qml.probs(wires=[]) - - @pytest.mark.parametrize("shots", [None, 100]) - def test_probs_no_arguments(self, shots): - """Test that using ``qml.probs`` with no arguments returns the probabilities of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.Identity(wires=[0, 1, 2]) - return qml.probs() - - res = circuit() - - assert qml.math.allequal(res, [1, 0, 0, 0, 0, 0, 0, 0]) - - def test_full_prob(self, init_state, tol): - """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=4) - - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - return qml.probs(wires=range(4)) - - res = circuit() - expected = np.abs(state) ** 2 - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_marginal_prob(self, init_state, tol): - """Test that the correct marginal probability is returned.""" - dev = qml.device("default.qubit", wires=4) - - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - return qml.probs(wires=[1, 3]) - - res = circuit() - expected = np.reshape(np.abs(state) ** 2, [2] * 4) - expected = np.einsum("ijkl->jl", expected).flatten() - assert np.allclose(res, expected, atol=tol, rtol=0) - - def test_marginal_prob_more_wires(self, init_state, tol): - """Test that the correct marginal probability is returned, when the - states_to_binary method is used for probability computations.""" - dev = qml.device("default.qubit", wires=4) - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - return qml.probs(wires=[1, 0, 3]) - - res = circuit() - - expected = np.reshape(np.abs(state) ** 2, [2] * 4) - expected = np.einsum("ijkl->jil", expected).flatten() - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["numpy", "jax", "torch", "tensorflow"]) - @pytest.mark.parametrize( - "subset_wires,expected", - [ - ([0, 1], [0.25, 0.25, 0.25, 0.25]), - ([1, 2], [0.5, 0, 0.5, 0]), - ([0, 2], [0.5, 0, 0.5, 0]), - ([2, 0], [0.5, 0.5, 0, 0]), - ([2, 1], [0.5, 0.5, 0, 0]), - ([1, 2, 0], [0.25, 0.25, 0, 0, 0.25, 0.25, 0, 0]), - ], - ) - def test_process_state(self, interface, subset_wires, expected): - """Tests that process_state functions as expected with all interfaces.""" - state = qml.math.array([1 / 2, 0] * 4, like=interface) - wires = qml.wires.Wires(range(3)) - subset_probs = qml.probs(wires=subset_wires).process_state(state, wires) - assert subset_probs.shape == (len(expected),) - assert qml.math.allclose(subset_probs, expected) - - @pytest.mark.all_interfaces - @pytest.mark.parametrize("interface", ["numpy", "jax", "torch", "tensorflow"]) - @pytest.mark.parametrize( - "subset_wires,expected", - [ - ([1, 2], [[0.5, 0, 0.5, 0], [0, 0.5, 0, 0.5]]), - ([2, 0], [[0.5, 0.5, 0, 0], [0, 0, 0.5, 0.5]]), - ( - [1, 2, 0], - [[0.25, 0.25, 0, 0, 0.25, 0.25, 0, 0], [0, 0, 0.25, 0.25, 0, 0, 0.25, 0.25]], - ), - ], - ) - def test_process_state_batched(self, interface, subset_wires, expected): - """Tests that process_state functions as expected with all interfaces with batching.""" - states = qml.math.array([[1 / 2, 0] * 4, [0, 1 / 2] * 4], like=interface) - wires = qml.wires.Wires(range(3)) - subset_probs = qml.probs(wires=subset_wires).process_state(states, wires) - assert subset_probs.shape == qml.math.shape(expected) - assert qml.math.allclose(subset_probs, expected) - - def test_integration(self, tol): - """Test the probability is correct for a known state preparation.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=1) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[0, 1]) - - # expected probability, using [00, 01, 10, 11] - # ordering, is [0.5, 0.5, 0, 0] - - res = circuit() - expected = np.array([0.5, 0.5, 0, 0]) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("shots", [100, [1, 10, 100]]) - def test_integration_analytic_false(self, tol, shots): - """Test the probability is correct for a known state preparation when the - analytic attribute is set to False.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(0) - return qml.probs(wires=dev.wires) - - res = circuit() - expected = np.array([0, 0, 0, 0, 1, 0, 0, 0]) - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("shots", [None, 100]) - def test_batch_size(self, shots): - """Test the probability is correct for a batched input.""" - dev = qml.device("default.qubit", wires=1, shots=shots) - - @qml.qnode(dev) - def circuit(x): - qml.RX(x, 0) - return qml.probs(wires=dev.wires) # TODO: Use ``qml.probs()`` when supported - - x = np.array([0, np.pi / 2]) - res = circuit(x) - expected = [[1.0, 0.0], [0.5, 0.5]] - assert np.allclose(res, expected, atol=0.1, rtol=0.1) - - @pytest.mark.autograd - def test_numerical_analytic_diff_agree(self, tol): - """Test that the finite difference and parameter shift rule - provide the same Jacobian.""" - w = 4 - dev = qml.device("default.qubit", wires=w) - - def circuit(x, y, z): - for i in range(w): - qml.RX(x, wires=i) - qml.PhaseShift(z, wires=i) - qml.RY(y, wires=i) - - qml.CNOT(wires=[0, 1]) - qml.CNOT(wires=[1, 2]) - qml.CNOT(wires=[2, 3]) - - return qml.probs(wires=[1, 3]) - - params = pnp.array([0.543, -0.765, -0.3], requires_grad=True) - - circuit_F = qml.QNode(circuit, dev, diff_method="finite-diff") - circuit_A = qml.QNode(circuit, dev, diff_method="parameter-shift") - res_F = qml.jacobian(circuit_F)(*params) - res_A = qml.jacobian(circuit_A)(*params) - - # Both jacobians should be of shape (2**prob.wires, num_params) - assert isinstance(res_F, tuple) and len(res_F) == 3 - assert all(_r.shape == (2**2,) for _r in res_F) - assert isinstance(res_A, tuple) and len(res_A) == 3 - assert all(_r.shape == (2**2,) for _r in res_A) - - # Check that they agree up to numeric tolerance - assert all(np.allclose(_rF, _rA, atol=tol, rtol=0) for _rF, _rA in zip(res_F, res_A)) - - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param_one_qubit(self, hermitian, tol): - """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=1) - - @qml.qnode(dev) - def circuit(x): - qml.RZ(x, wires=0) - return qml.probs(op=qml.Hermitian(hermitian, wires=0)) - - res = circuit(0.56) - - def circuit_rotated(x): - qml.RZ(x, wires=0) - qml.Hermitian(hermitian, wires=0).diagonalizing_gates() - - state = np.array([1, 0]) - matrix = qml.matrix(circuit_rotated)(0.56) - state = np.dot(matrix, state) - expected = np.reshape(np.abs(state) ** 2, [2] * 1) - expected = expected.flatten() - - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param(self, hermitian, tol): - """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=3) - - @qml.qnode(dev) - def circuit(x, y): - qml.RZ(x, wires=0) - qml.CNOT(wires=[0, 1]) - qml.RY(y, wires=1) - qml.CNOT(wires=[0, 2]) - return qml.probs(op=qml.Hermitian(hermitian, wires=0)) - - res = circuit(0.56, 0.1) - - def circuit_rotated(x, y): - qml.RZ(x, wires=0) - qml.CNOT(wires=[0, 1]) - qml.RY(y, wires=1) - qml.CNOT(wires=[0, 2]) - qml.Hermitian(hermitian, wires=0).diagonalizing_gates() - - state = np.array([1, 0, 0, 0, 0, 0, 0, 0]) - matrix = qml.matrix(circuit_rotated)(0.56, 0.1) - state = np.dot(matrix, state) - expected = np.reshape(np.abs(state) ** 2, [2] * 3) - expected = np.einsum("ijk->i", expected).flatten() - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_generalize_param_multiple(self, hermitian, tol): - """Test that the correct probability is returned.""" - dev = qml.device("default.qubit", wires=3) - - @qml.qnode(dev) - def circuit(x, y): - qml.RZ(x, wires=0) - qml.CNOT(wires=[0, 1]) - qml.RY(y, wires=1) - qml.CNOT(wires=[0, 2]) - return ( - qml.probs(op=qml.Hermitian(hermitian, wires=0)), - qml.probs(wires=[1]), - qml.probs(wires=[2]), - ) - - res = circuit(0.56, 0.1) - res = np.reshape(res, (3, 2)) - - def circuit_rotated(x, y): - qml.RZ(x, wires=0) - qml.CNOT(wires=[0, 1]) - qml.RY(y, wires=1) - qml.CNOT(wires=[0, 2]) - qml.Hermitian(hermitian, wires=0).diagonalizing_gates() - - state = np.array([1, 0, 0, 0, 0, 0, 0, 0]) - matrix = qml.matrix(circuit_rotated)(0.56, 0.1) - state = np.dot(matrix, state) - - expected = np.reshape(np.abs(state) ** 2, [2] * 3) - expected_0 = np.einsum("ijk->i", expected).flatten() - expected_1 = np.einsum("ijk->j", expected).flatten() - expected_2 = np.einsum("ijk->k", expected).flatten() - - assert np.allclose(res[0], expected_0, atol=tol, rtol=0) - assert np.allclose(res[1], expected_1, atol=tol, rtol=0) - assert np.allclose(res[2], expected_2, atol=tol, rtol=0) - - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - @pytest.mark.parametrize("wire", [0, 1, 2, 3]) - def test_prob_generalize_initial_state(self, hermitian, wire, init_state, tol): - """Test that the correct probability is returned.""" - # pylint:disable=too-many-arguments - dev = qml.device("default.qubit", wires=4) - - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - qml.PauliX(wires=0) - qml.PauliX(wires=1) - qml.PauliX(wires=2) - qml.PauliX(wires=3) - return qml.probs(op=qml.Hermitian(hermitian, wires=wire)) - - res = circuit() - - def circuit_rotated(): - qml.PauliX(wires=0) - qml.PauliX(wires=1) - qml.PauliX(wires=2) - qml.PauliX(wires=3) - qml.Hermitian(hermitian, wires=wire).diagonalizing_gates() - - matrix = qml.matrix(circuit_rotated)() - state = np.dot(matrix, state) - expected = np.reshape(np.abs(state) ** 2, [2] * 4) - - if wire == 0: - expected = np.einsum("ijkl->i", expected).flatten() - elif wire == 1: - expected = np.einsum("ijkl->j", expected).flatten() - elif wire == 2: - expected = np.einsum("ijkl->k", expected).flatten() - elif wire == 3: - expected = np.einsum("ijkl->l", expected).flatten() - - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("operation", [qml.PauliX, qml.PauliY, qml.Hadamard]) - @pytest.mark.parametrize("wire", [0, 1, 2, 3]) - def test_operation_prob(self, operation, wire, init_state, tol): - "Test the rotated probability with different wires and rotating operations." - # pylint:disable=too-many-arguments - dev = qml.device("default.qubit", wires=4) - - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - qml.PauliY(wires=2) - qml.PauliZ(wires=3) - return qml.probs(op=operation(wires=wire)) - - res = circuit() - - def circuit_rotated(): - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - qml.PauliY(wires=2) - qml.PauliZ(wires=3) - operation(wires=wire).diagonalizing_gates() - - matrix = qml.matrix(circuit_rotated)() - state = np.dot(matrix, state) - expected = np.reshape(np.abs(state) ** 2, [2] * 4) - - if wire == 0: - expected = np.einsum("ijkl->i", expected).flatten() - elif wire == 1: - expected = np.einsum("ijkl->j", expected).flatten() - elif wire == 2: - expected = np.einsum("ijkl->k", expected).flatten() - elif wire == 3: - expected = np.einsum("ijkl->l", expected).flatten() - - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("observable", [(qml.PauliX, qml.PauliY)]) - def test_observable_tensor_prob(self, observable, init_state, tol): - "Test the rotated probability with a tensor observable." - dev = qml.device("default.qubit", wires=4) - - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - qml.PauliY(wires=2) - qml.PauliZ(wires=3) - return qml.probs(op=observable[0](wires=0) @ observable[1](wires=1)) - - res = circuit() - - def circuit_rotated(): - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - qml.PauliY(wires=2) - qml.PauliZ(wires=3) - observable[0](wires=0).diagonalizing_gates() - observable[1](wires=1).diagonalizing_gates() - - matrix = qml.matrix(circuit_rotated)() - state = np.dot(matrix, state) - expected = np.reshape(np.abs(state) ** 2, [2] * 4) - - expected = np.einsum("ijkl->ij", expected).flatten() - - assert np.allclose(res, expected, atol=tol, rtol=0) - - @pytest.mark.parametrize("coeffs, obs", [([1, 1], [qml.PauliX(wires=0), qml.PauliX(wires=1)])]) - def test_hamiltonian_error(self, coeffs, obs, init_state): - "Test that an error is returned for hamiltonians." - H = qml.Hamiltonian(coeffs, obs) - - dev = qml.device("default.qubit", wires=4) - state = init_state(4) - - @qml.qnode(dev) - def circuit(): - qml.StatePrep(state, wires=list(range(4))) - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - qml.PauliY(wires=2) - qml.PauliZ(wires=3) - return qml.probs(op=H) - - with pytest.raises( - qml.QuantumFunctionError, - match="Hamiltonians are not supported for rotating probabilities.", - ): - circuit() - - @pytest.mark.parametrize( - "operation", [qml.SingleExcitation, qml.SingleExcitationPlus, qml.SingleExcitationMinus] - ) - def test_generalize_prob_not_hermitian(self, operation): - """Test that Operators that do not have a diagonalizing_gates representation cannot - be used in probability measurements.""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(wires=0) - qml.PauliZ(wires=1) - return qml.probs(op=operation(0.56, wires=[0, 1])) - - with pytest.raises( - qml.QuantumFunctionError, - match="does not define diagonalizing gates : cannot be used to rotate the probability", - ): - circuit() - - @pytest.mark.parametrize("hermitian", [1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])]) - def test_prob_wires_and_hermitian(self, hermitian): - """Test that we can cannot give simultaneously wires and a hermitian.""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.PauliX(wires=0) - return qml.probs(op=qml.Hermitian(hermitian, wires=0), wires=1) - - with pytest.raises( - qml.QuantumFunctionError, - match="Cannot specify the wires to probs if an observable is " - "provided. The wires for probs will be determined directly from the observable.", - ): - circuit() - - @pytest.mark.parametrize( - "wires, expected", - [ - ( - [0], - [ - [[0, 0, 0.5], [1, 1, 0.5]], - [[0.5, 0.5, 0], [0.5, 0.5, 1]], - [[0, 0.5, 1], [1, 0.5, 0]], - ], - ), - ( - [0, 1], - [ - [[0, 0, 0], [0, 0, 0.5], [0.5, 0, 0], [0.5, 1, 0.5]], - [[0.5, 0.5, 0], [0, 0, 0], [0, 0, 0], [0.5, 0.5, 1]], - [[0, 0.5, 0.5], [0, 0, 0.5], [0.5, 0, 0], [0.5, 0.5, 0]], - ], - ), - ], - ) - def test_estimate_probability_with_binsize_with_broadcasting(self, wires, expected): - """Tests the estimate_probability method with a bin size and parameter broadcasting""" - samples = np.array( - [ - [[1, 0], [1, 1], [1, 1], [1, 1], [1, 1], [0, 1]], - [[0, 0], [1, 1], [1, 1], [0, 0], [1, 1], [1, 1]], - [[1, 0], [1, 1], [1, 1], [0, 0], [0, 1], [0, 0]], - ] - ) - - res = qml.probs(wires=wires).process_samples( - samples=samples, wire_order=wires, shot_range=None, bin_size=2 - ) - - assert np.allclose(res, expected) - - 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) - - @qml.qnode(dev) - def circuit(x, y): - qml.RX(x, wires=[0]) - qml.RY(y, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliX(1)), qml.probs(wires=[0, 1]) - - res = circuit(1, 2) - assert isinstance(res, tuple) and len(res) == 2 - - def test_commuting_probs_in_computational_basis(self): - """Test that `qml.probs` can be used in the computational basis with other commuting observables.""" - dev = qml.device("default.qubit", wires=5) - - @qml.qnode(dev) - def circuit(x, y): - qml.RX(x, wires=[0]) - qml.RY(y, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)), qml.probs(wires=[0, 1]) - - res = circuit(1, 2) - - @qml.qnode(dev) - def circuit2(x, y): - qml.RX(x, wires=[0]) - qml.RY(y, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.expval(qml.PauliZ(0)) - - @qml.qnode(dev) - def circuit3(x, y): - qml.RX(x, wires=[0]) - qml.RY(y, wires=[1]) - qml.CNOT(wires=[0, 1]) - return qml.probs(wires=[0, 1]) - - res2 = circuit2(1, 2) - res3 = circuit3(1, 2) - - assert res[0] == res2 - assert qml.math.allequal(res[1:], res3) diff --git a/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py deleted file mode 100644 index ccaab4fb5bc..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_purity_measurement_default_qubit_2.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright 2018-2023 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. -"""Tests for the purity measurement process""" - -import pytest - -import numpy as np -import pennylane as qml - -from pennylane.measurements import PurityMP, Shots - -# pylint: disable=too-many-arguments - - -def expected_purity_ising_xx(param): - """Returns the analytical purity for subsystems of the IsingXX""" - - eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - return eig_1**2 + eig_2**2 - - -def expected_purity_grad_ising_xx(param): - """The analytic gradient purity for the IsingXX""" - - eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - grad_expected_purity = ( - 2 - * eig_1 - * (np.sin(param / 2) ** 3 * np.cos(param / 2) - np.sin(param / 2) * np.cos(param / 2) ** 3) - / np.sqrt(1 - 4 * np.sin(param / 2) ** 2 * np.cos(param / 2) ** 2) - ) + ( - 2 - * eig_2 - * ( - np.sin(param / 2) - * np.cos(param / 2) - * (np.cos(param / 2) ** 2 - np.sin(param / 2) ** 2) - ) - / np.sqrt(1 - 4 * np.sin(param / 2) ** 2 * np.cos(param / 2) ** 2) - ) - return grad_expected_purity - - -class TestPurityUnitTest: - """Tests for purity measurements""" - - def test_return_type(self): - """Test that the return type is defined and the purity enum.""" - m = PurityMP(wires=qml.wires.Wires((0, 1))) - assert m.return_type is qml.measurements.Purity - - def test_numeric_type(self): - """Test that the numeric type of PurityMP is float.""" - m = PurityMP(wires=qml.wires.Wires(0)) - assert m.numeric_type is float - - @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ((1, 10), ((), ()))]) - def test_shape_new(self, shots, shape): - """Test the ``shape_new`` method.""" - meas = qml.purity(wires=0) - dev = qml.device("default.qubit", wires=1, shots=shots) - assert meas.shape(dev, Shots(shots)) == shape - - -class TestPurityIntegration: - """Test the purity meausrement with qnodes and devices.""" - - devices = ["default.qubit", "lightning.qubit", "default.mixed"] - grad_supported_devices = ["default.qubit", "default.mixed"] - mix_supported_devices = ["default.mixed"] - - diff_methods = ["backprop", "finite-diff"] - - parameters = np.linspace(0, 2 * np.pi, 3) - probs = np.array([0.001, 0.01, 0.1, 0.2]) - - wires_list = [([0], True), ([1], True), ([0, 1], False)] - - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - def test_IsingXX_qnode_purity(self, device, param, wires, is_partial): - """Tests purity for a qnode""" - - dev = qml.device(device, wires=2) - - @qml.qnode(dev) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - purity = circuit(param) - expected_purity = expected_purity_ising_xx(param) if is_partial else 1 - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.parametrize("device", mix_supported_devices) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("param", probs) - def test_bit_flip_qnode_purity(self, device, wires, param, is_partial): - """Tests purity for a qnode on a noisy device with bit flips""" - - dev = qml.device(device, wires=2) - - @qml.qnode(dev) - def circuit(p): - qml.Hadamard(wires=0) - qml.CNOT(wires=[0, 1]) - qml.BitFlip(p, wires=0) - qml.BitFlip(p, wires=1) - return qml.purity(wires=wires) - - purity = circuit(param) - expected_purity = ( - 0.5 - if is_partial - else 4 * (0.5 - (1 - param) * param) ** 2 + 4 * (1 - param) ** 2 * param**2 - ) - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.parametrize("device", grad_supported_devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("diff_method", diff_methods) - def test_IsingXX_qnode_purity_grad(self, device, param, wires, is_partial, diff_method): - """Tests purity for a qnode""" - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, diff_method=diff_method) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - grad_purity = qml.grad(circuit)(param) - expected_grad = expected_purity_grad_ising_xx(param) if is_partial else 0 - assert qml.math.allclose(grad_purity, expected_grad, rtol=1e-04, atol=1e-05) - - @pytest.mark.parametrize("device", mix_supported_devices) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("param", probs) - @pytest.mark.parametrize("diff_method", diff_methods) - def test_bit_flip_qnode_purity_grad(self, device, wires, param, is_partial, diff_method): - """Tests gradient of purity for a qnode on a noisy device with bit flips""" - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, diff_method=diff_method) - def circuit(p): - qml.Hadamard(wires=0) - qml.CNOT(wires=[0, 1]) - qml.BitFlip(p, wires=0) - qml.BitFlip(p, wires=1) - return qml.purity(wires=wires) - - purity_grad = qml.grad(circuit)(param) - expected_purity_grad = 0 if is_partial else 32 * (param - 0.5) ** 3 - assert qml.math.allclose(purity_grad, expected_purity_grad, rtol=1e-04, atol=1e-05) - - @pytest.mark.jax - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("interface", ["jax"]) - def test_IsingXX_qnode_purity_jax(self, device, param, wires, is_partial, interface): - """Test purity for a QNode with jax interface.""" - - import jax.numpy as jnp - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - purity = circuit(jnp.array(param)) - expected_purity = expected_purity_ising_xx(param) if is_partial else 1 - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.jax - @pytest.mark.parametrize("device", grad_supported_devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax"]) - def test_IsingXX_qnode_purity_grad_jax( - self, device, param, wires, is_partial, diff_method, interface - ): - """Test purity for a QNode gradient with Jax.""" - - import jax - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - grad_purity = jax.grad(circuit)(jax.numpy.array(param)) - grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 - - assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) - - @pytest.mark.jax - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("interface", ["jax-jit"]) - def test_IsingXX_qnode_purity_jax_jit(self, device, param, wires, is_partial, interface): - """Test purity for a QNode with jax interface.""" - - import jax - import jax.numpy as jnp - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - purity = jax.jit(circuit)(jnp.array(param)) - expected_purity = expected_purity_ising_xx(param) if is_partial else 1 - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.jax - @pytest.mark.parametrize("device", grad_supported_devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax-jit"]) - def test_IsingXX_qnode_purity_grad_jax_jit( - self, device, param, wires, is_partial, diff_method, interface - ): - """Test purity for a QNode gradient with Jax.""" - - import jax - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - grad_purity = jax.jit(jax.grad(circuit))(jax.numpy.array(param)) - grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 - - assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) - - @pytest.mark.torch - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("interface", ["torch"]) - def test_IsingXX_qnode_purity_torch(self, device, param, wires, is_partial, interface): - """Tests purity for a qnode""" - - import torch - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - purity = circuit(torch.tensor(param)) - expected_purity = expected_purity_ising_xx(param) if is_partial else 1 - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.torch - @pytest.mark.parametrize("device", grad_supported_devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["torch"]) - def test_IsingXX_qnode_purity_grad_torch( - self, device, param, wires, is_partial, diff_method, interface - ): - """Test purity for a QNode gradient with torch.""" - - import torch - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - expected_grad = expected_purity_grad_ising_xx(param) if is_partial else 0 - - param = torch.tensor(param, dtype=torch.float64, requires_grad=True) - purity = circuit(param) - purity.backward() # pylint: disable=no-member - grad_purity = param.grad - - assert qml.math.allclose(grad_purity, expected_grad, rtol=1e-04, atol=1e-05) - - @pytest.mark.tf - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("interface", ["tf"]) - def test_IsingXX_qnode_purity_tf(self, device, param, wires, is_partial, interface): - """Tests purity for a qnode""" - - import tensorflow as tf - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - purity = circuit(tf.Variable(param)) - expected_purity = expected_purity_ising_xx(param) if is_partial else 1 - assert qml.math.allclose(purity, expected_purity) - - @pytest.mark.tf - @pytest.mark.parametrize("device", grad_supported_devices) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("wires,is_partial", wires_list) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["tf"]) - def test_IsingXX_qnode_purity_grad_tf( - self, device, param, wires, is_partial, diff_method, interface - ): - """Test purity for a QNode gradient with tf.""" - - import tensorflow as tf - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.purity(wires=wires) - - grad_expected_purity = expected_purity_grad_ising_xx(param) if is_partial else 0 - - param = tf.Variable(param) - with tf.GradientTape() as tape: - purity = circuit(param) - - grad_purity = tape.gradient(purity, param) - - assert qml.math.allclose(grad_purity, grad_expected_purity, rtol=1e-04, atol=1e-05) - - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("param", parameters) - def test_qnode_entropy_custom_wires(self, device, param): - """Test that purity can be returned with custom wires.""" - - dev = qml.device(device, wires=["a", 1]) - - @qml.qnode(dev) - def circuit(x): - qml.IsingXX(x, wires=["a", 1]) - return qml.purity(wires=["a"]) - - purity = circuit(param) - expected_purity = expected_purity_ising_xx(param) - assert qml.math.allclose(purity, expected_purity) diff --git a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py deleted file mode 100644 index b5c6dcce21e..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_sample_default_qubit_2.py +++ /dev/null @@ -1,390 +0,0 @@ -# Copyright 2018-2020 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 sample module""" -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import MeasurementShapeError, Sample, Shots -from pennylane.operation import EigvalsUndefinedError, Operator - -# pylint: disable=protected-access, no-member - - -class TestSample: - """Tests for the sample function""" - - @pytest.mark.parametrize("n_sample", (1, 10)) - def test_sample_dimension(self, n_sample): - """Test that the sample function outputs samples of the right size""" - - dev = qml.device("default.qubit", wires=2, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.54, wires=0) - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliX(1)) - - output = circuit() - - assert len(output) == 2 - assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == ( - (n_sample,) if not n_sample == 1 else () - ) - assert circuit._qfunc_output[1].shape(dev, Shots(n_sample)) == ( - (n_sample,) if not n_sample == 1 else () - ) - - @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") - def test_sample_combination(self): - """Test the output of combining expval, var and sample""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=3, shots=n_sample) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - qml.RX(0.54, wires=0) - - return qml.sample(qml.PauliZ(0)), qml.expval(qml.PauliX(1)), qml.var(qml.PauliY(2)) - - result = circuit() - - assert len(result) == 3 - assert np.array_equal(result[0].shape, (n_sample,)) - assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == (n_sample,) - assert isinstance(result[1], np.float64) - assert isinstance(result[2], np.float64) - - def test_single_wire_sample(self): - """Test the return type and shape of sampling a single wire""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=1, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.54, wires=0) - return qml.sample(qml.PauliZ(0)) - - result = circuit() - - assert isinstance(result, np.ndarray) - assert np.array_equal(result.shape, (n_sample,)) - assert circuit._qfunc_output.shape(dev, Shots(n_sample)) == (n_sample,) - - def test_multi_wire_sample_regular_shape(self): - """Test the return type and shape of sampling multiple wires - where a rectangular array is expected""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=3, shots=n_sample) - - @qml.qnode(dev) - def circuit(): - return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1)), qml.sample(qml.PauliZ(2)) - - result = circuit() - - assert circuit._qfunc_output[0].shape(dev, Shots(n_sample)) == (n_sample,) - assert circuit._qfunc_output[1].shape(dev, Shots(n_sample)) == (n_sample,) - assert circuit._qfunc_output[2].shape(dev, Shots(n_sample)) == (n_sample,) - - # If all the dimensions are equal the result will end up to be a proper rectangular array - assert isinstance(result, tuple) - assert len(result) == 3 - assert result[0].dtype == np.dtype("int") - - @pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences") - def test_sample_output_type_in_combination(self): - """Test the return type and shape of sampling multiple works - in combination with expvals and vars""" - n_sample = 10 - - dev = qml.device("default.qubit", wires=3, shots=n_sample) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(): - return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)), qml.sample(qml.PauliZ(2)) - - result = circuit() - - # If all the dimensions are equal the result will end up to be a proper rectangular array - assert len(result) == 3 - assert isinstance(result[0], np.ndarray) - assert isinstance(result[1], np.ndarray) - assert result[2].dtype == np.dtype("int") - assert np.array_equal(result[2].shape, (n_sample,)) - - def test_not_an_observable(self): - """Test that a UserWarning is raised if the provided - argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2, shots=10) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.52, wires=0) - return qml.sample(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - - with pytest.warns(UserWarning, match="Prod might not be hermitian."): - _ = circuit() - - def test_observable_return_type_is_sample(self): - """Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`""" - n_shots = 10 - dev = qml.device("default.qubit", wires=1, shots=n_shots) - - @qml.qnode(dev) - def circuit(): - res = qml.sample(qml.PauliZ(0)) - assert res.return_type is Sample - return res - - circuit() - - def test_providing_observable_and_wires(self): - """Test that a ValueError is raised if both an observable is provided and wires are specified""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - return qml.sample(qml.PauliZ(0), wires=[0, 1]) - - with pytest.raises( - ValueError, - match="Cannot specify the wires to sample if an observable is provided." - " The wires to sample will be determined directly from the observable.", - ): - _ = circuit() - - def test_providing_no_observable_and_no_wires(self): - """Test that we can provide no observable and no wires to sample function""" - dev = qml.device("default.qubit", wires=2, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - res = qml.sample() - assert res.obs is None - assert res.wires == qml.wires.Wires([]) - return res - - circuit() - - def test_providing_no_observable_and_no_wires_shot_vector(self): - """Test that we can provide no observable and no wires to sample - function when using a shot vector""" - num_wires = 2 - - shots1 = 1 - shots2 = 10 - shots3 = 1000 - dev = qml.device("default.qubit", wires=num_wires, shots=[shots1, shots2, shots3]) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - qml.CNOT(wires=[0, 1]) - return qml.sample() - - res = circuit() - - assert isinstance(res, tuple) - - expected_shapes = [(num_wires,), (shots2, num_wires), (shots3, num_wires)] - assert len(res) == len(expected_shapes) - assert all(r.shape == exp_shape for r, exp_shape in zip(res, expected_shapes)) - - # assert first wire is always the same as second - # pylint: disable=unsubscriptable-object - assert np.all(res[0][0] == res[0][1]) - assert np.all(res[1][:, 0] == res[1][:, 1]) - assert np.all(res[2][:, 0] == res[2][:, 1]) - - def test_providing_no_observable_and_wires(self): - """Test that we can provide no observable but specify wires to the sample function""" - wires = [0, 2] - wires_obj = qml.wires.Wires(wires) - dev = qml.device("default.qubit", wires=3, shots=1000) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - res = qml.sample(wires=wires) - - assert res.obs is None - assert res.wires == wires_obj - return res - - circuit() - - @pytest.mark.parametrize( - "obs,exp", - [ - # Single observables - (None, int), # comp basis samples - (qml.PauliX(0), int), - (qml.PauliY(0), int), - (qml.PauliZ(0), int), - (qml.Hadamard(0), int), - (qml.Identity(0), int), - (qml.Hermitian(np.diag([1, 2]), 0), float), - (qml.Hermitian(np.diag([1.0, 2.0]), 0), float), - # Tensor product observables - ( - qml.PauliX("c") - @ qml.PauliY("a") - @ qml.PauliZ(1) - @ qml.Hadamard("wire1") - @ qml.Identity("b"), - int, - ), - (qml.Projector([0, 1], wires=[0, 1]) @ qml.PauliZ(2), float), - (qml.Hermitian(np.array(np.eye(2)), wires=[0]) @ qml.PauliZ(2), float), - ( - qml.Projector([0, 1], wires=[0, 1]) @ qml.Hermitian(np.array(np.eye(2)), wires=[2]), - float, - ), - ], - ) - def test_numeric_type(self, obs, exp): - """Test that the numeric type is correct.""" - res = qml.sample(obs) if obs is not None else qml.sample() - assert res.numeric_type is exp - - def test_shape_no_shots_error(self): - """Test that the appropriate error is raised with no shots are specified""" - dev = qml.device("default.qubit", wires=2, shots=None) - shots = Shots(None) - mp = qml.sample() - - with pytest.raises( - MeasurementShapeError, match="Shots are required to obtain the shape of the measurement" - ): - _ = mp.shape(dev, shots) - - @pytest.mark.parametrize( - "obs", - [ - None, - qml.PauliZ(0), - qml.Hermitian(np.diag([1, 2]), 0), - qml.Hermitian(np.diag([1.0, 2.0]), 0), - ], - ) - def test_shape(self, obs): - """Test that the shape is correct.""" - shots = 10 - dev = qml.device("default.qubit", wires=3, shots=shots) - res = qml.sample(obs) if obs is not None else qml.sample() - expected = (shots,) if obs is not None else (shots, 3) - assert res.shape(dev, Shots(shots)) == expected - - @pytest.mark.parametrize("n_samples", (1, 10)) - def test_shape_wires(self, n_samples): - """Test that the shape is correct when wires are provided.""" - dev = qml.device("default.qubit", wires=3, shots=n_samples) - mp = qml.sample(wires=(0, 1)) - assert mp.shape(dev, Shots(n_samples)) == (n_samples, 2) if n_samples != 1 else (2,) - - @pytest.mark.parametrize( - "obs", - [ - None, - qml.PauliZ(0), - qml.Hermitian(np.diag([1, 2]), 0), - qml.Hermitian(np.diag([1.0, 2.0]), 0), - ], - ) - def test_shape_shot_vector(self, obs): - """Test that the shape is correct with the shot vector too.""" - shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) - res = qml.sample(obs) if obs is not None else qml.sample() - expected = ((), (2,), (3,)) if obs is not None else ((3,), (2, 3), (3, 3)) - assert res.shape(dev, Shots(shot_vector)) == expected - - def test_shape_shot_vector_obs(self): - """Test that the shape is correct with the shot vector and a observable too.""" - shot_vec = (2, 2) - dev = qml.device("default.qubit", wires=3, shots=shot_vec) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(wires=0) - qml.PauliZ(0) - return qml.sample(qml.PauliZ(0)) - - binned_samples = circuit() - - assert isinstance(binned_samples, tuple) - assert len(binned_samples) == len(shot_vec) - # pylint: disable=unsubscriptable-object - assert binned_samples[0].shape == (shot_vec[0],) - - def test_sample_empty_wires(self): - """Test that using ``qml.sample`` with an empty wire list raises an error.""" - with pytest.raises(ValueError, match="Cannot set an empty list of wires."): - qml.sample(wires=[]) - - @pytest.mark.parametrize("shots", [2, 100]) - def test_sample_no_arguments(self, shots): - """Test that using ``qml.sample`` with no arguments returns the samples of all wires.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.Identity(wires=list(range(3))) - return qml.sample() - - res = circuit() - - # pylint: disable=comparison-with-callable - assert res.shape == (shots, 3) - - def test_new_sample_with_operator_with_no_eigvals(self): - """Test that calling process with an operator that has no eigvals defined raises an error.""" - - class DummyOp(Operator): # pylint: disable=too-few-public-methods - num_wires = 1 - - with pytest.raises(EigvalsUndefinedError, match="Cannot compute samples of"): - qml.sample(op=DummyOp(0)).process_samples(samples=np.array([[1, 0]]), wire_order=[0]) - - -@pytest.mark.jax -@pytest.mark.parametrize("samples", (1, 10)) -def test_jitting_with_sampling_on_subset_of_wires(samples): - """Test case covering bug in Issue #3904. Sampling should be jit-able - when sampling occurs on a subset of wires. The bug was occuring due an improperly - set shape method.""" - import jax - - jax.config.update("jax_enable_x64", True) - - dev = qml.device("default.qubit", wires=3, shots=samples) - - @qml.qnode(dev, interface="jax") - def circuit(x): - qml.RX(x, wires=0) - return qml.sample(wires=(0, 1)) - - results = jax.jit(circuit)(jax.numpy.array(0.123, dtype=jax.numpy.float64)) - - expected = (2,) if samples == 1 else (samples, 2) - assert results.shape == expected - assert ( - circuit._qfunc_output.shape(dev, Shots(samples)) == (samples, 2) if samples != 1 else (2,) - ) diff --git a/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py deleted file mode 100644 index abc709071e1..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_shots_default_qubit_2.py +++ /dev/null @@ -1,252 +0,0 @@ -# Copyright 2018-2023 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 :mod:`pennylane.shots`. -""" - -import copy -import pytest - -from pennylane.measurements import Shots, ShotCopies - -ERROR_MSG = "Shots must be a single positive integer, a tuple" - - -class TestShotCopies: - """Test that the ShotCopies class displays well.""" - - sc_data = (ShotCopies(1, 1), ShotCopies(100, 1), ShotCopies(100, 2), ShotCopies(10, 100)) - - str_data = ( - "1 shots", - "100 shots", - "100 shots x 2", - "10 shots x 100", - ) - - @pytest.mark.parametrize("expected_str, sc", zip(str_data, sc_data)) - def test_str(self, expected_str, sc): - """Test the str method works well""" - assert expected_str == str(sc) - - repr_data = ( - "ShotCopies(1 shots x 1)", - "ShotCopies(100 shots x 1)", - "ShotCopies(100 shots x 2)", - "ShotCopies(10 shots x 100)", - ) - - @pytest.mark.parametrize("expected_str, sc", zip(repr_data, sc_data)) - def test_repr(self, expected_str, sc): - """Test the repr method works well""" - assert expected_str == repr(sc) - - -class TestShotsConstruction: - """Tests the Shots class.""" - - def test_copy(self): - """Tests that creating a Shots from another Shots instance returns the same instance.""" - x = Shots(123) - y = Shots(x) - assert y is x - assert y._frozen # pylint:disable=protected-access - - z = copy.copy(x) - assert z is x - assert z._frozen # pylint:disable=protected-access - - def test_deepcopy(self): - x = Shots([1, 1, 2, 3]) - y = copy.deepcopy(x) - assert y is x - assert y._frozen # pylint:disable=protected-access - - def test_None(self): - """Tests the constructor when shots is None.""" - shots1 = Shots(None) - shots2 = Shots() # this also defaults to None - assert shots1.shot_vector == () - assert shots2.shot_vector == () - assert shots1.total_shots is None - assert shots2.total_shots is None - - def test_int(self): - """Tests the constructor when shots is an int.""" - shots = Shots(100) - assert shots.shot_vector == (ShotCopies(100, 1),) - assert shots.total_shots == 100 - - def test_tuple(self): - """Tests the constructor when shots is a tuple.""" - shots = Shots((5, 6)) - assert shots.shot_vector == (ShotCopies(5, 1), ShotCopies(6, 1)) - assert shots.total_shots == 11 - assert isinstance(shots.shot_vector, tuple) - - shot_data = ( - Shots(None), - Shots(10), - Shots((1, 10, 100)), - Shots((1, 10, 10, 100, 100, 100)), - ) - - str_data = ( - "Shots(total=None)", - "Shots(total=10)", - "Shots(total=111, vector=[1 shots, 10 shots, 100 shots])", - "Shots(total=321, vector=[1 shots, 10 shots x 2, 100 shots x 3])", - ) - - @pytest.mark.parametrize("expected_str, shots_obj", zip(str_data, shot_data)) - def test_str(self, expected_str, shots_obj): - """Test that the string representation is correct.""" - assert expected_str == str(shots_obj) - - repr_data = ( - "Shots(total_shots=None, shot_vector=())", - "Shots(total_shots=10, shot_vector=(ShotCopies(10 shots x 1),))", - "Shots(total_shots=111, shot_vector=(ShotCopies(1 shots x 1), " - "ShotCopies(10 shots x 1), ShotCopies(100 shots x 1)))", - "Shots(total_shots=321, shot_vector=(ShotCopies(1 shots x 1), " - "ShotCopies(10 shots x 2), ShotCopies(100 shots x 3)))", - ) - - @pytest.mark.parametrize("expected_str, shots_obj", zip(repr_data, shot_data)) - def test_repr(self, expected_str, shots_obj): - """Test that the repr is correct""" - assert expected_str == repr(shots_obj) - - def test_eq(self): - """Test that the equality function behaves correctly""" - for s in self.shot_data: - assert s == copy.copy(s) - assert s == Shots(s.shot_vector if s.shot_vector else None) - - def test_eq_edge_case(self): - """Test edge cases for equality function are correct""" - assert Shots((1, 2)) != Shots((2, 1)) - assert Shots((1, 10, 1)) != Shots((1, 1, 10)) - assert Shots((5, 5)) != Shots(10) - assert Shots((1, 2, (10, 2))) == Shots((1, 2, 10, 10)) - - def test_hash(self): - """Test that the hash function behaves correctly""" - for s in self.shot_data: - hash_s = hash(s) - assert hash_s == hash(copy.copy(s)) - assert hash_s == hash(Shots(s.shot_vector if s.shot_vector else None)) - - @pytest.mark.parametrize( - "shots, expected", - [ - (100, [100]), - ([(100, 1)], [100]), - ([(100, 2)], [100, 100]), - ([100, 200], [100, 200]), - ([(100, 2), 200], [100, 100, 200]), - ([(100, 3), 200, (300, 2)], [100, 100, 100, 200, 300, 300]), - ], - ) - def test_iter(self, shots, expected): - """Test that iteration over Shots works correctly""" - actual = list(Shots(shots)) - assert actual == expected - - def test_sequence_all_tuple(self): - """Tests that a sequence of tuples is allowed.""" - shots = Shots([(1, 2), (1, 5), (3, 4)]) - assert shots.shot_vector == (ShotCopies(1, 7), ShotCopies(3, 4)) - assert shots.total_shots == 19 - assert isinstance(shots.shot_vector, tuple) - - @pytest.mark.parametrize( - "shot_list,expected,total", - [ - ( - [1, 3, 3, 4, 4, 4, 3], - (ShotCopies(1, 1), ShotCopies(3, 2), ShotCopies(4, 3), ShotCopies(3, 1)), - 22, - ), - ([5, 5, 5], (ShotCopies(5, 3),), 15), - ([1, (4, 2)], (ShotCopies(1, 1), ShotCopies(4, 2)), 9), - ((5,), (ShotCopies(5, 1),), 5), - ((5, 6, 7), (ShotCopies(5, 1), ShotCopies(6, 1), ShotCopies(7, 1)), 18), - (((5, 6)), (ShotCopies(5, 1), ShotCopies(6, 1)), 11), - (((5, 6),), (ShotCopies(5, 6),), 30), - (((5, 6), 7), (ShotCopies(5, 6), ShotCopies(7, 1)), 37), - ((5, (6, 7)), (ShotCopies(5, 1), ShotCopies(6, 7)), 47), - (((5, 6), (7, 8)), (ShotCopies(5, 6), ShotCopies(7, 8)), 86), - ], - ) - def test_sequence(self, shot_list, expected, total): - """Tests the constructor when shots is a Sequence[int].""" - shots = Shots(shot_list) - assert shots.shot_vector == expected - assert shots.total_shots == total - - @pytest.mark.parametrize("shot_arg", ["123", [1.1, 2], [-1, 2], 1.5, (1.1, 2)]) - def test_other_fails(self, shot_arg): - """Tests that all other values for shots is not allowed.""" - with pytest.raises(ValueError, match=ERROR_MSG): - _ = Shots(shot_arg) - - def test_zero_shots_fails(self): - with pytest.raises(ValueError, match=ERROR_MSG): - _ = Shots(0) - - -class TestProperties: - """Tests various properties of the Shots class.""" - - @pytest.mark.parametrize( - "shots,expected", - [ - (None, False), - (1, True), - ([1, 2], True), - ([1, (2, 3)], True), - ], - ) - def test_bool_dunder(self, shots, expected): - """Tests the Truthy/Falsy values of various Shots objects.""" - assert bool(Shots(shots)) is expected - - def test_Shots_frozen_after_init(self): - """Tests that Shots instances are frozen after creation.""" - shots = Shots(10) - with pytest.raises(AttributeError, match="Shots is an immutable class"): - shots.total_shots = 20 - - @pytest.mark.parametrize( - "shots,expected", [(None, False), (100, False), ([1, 2], True), [[100], False]] - ) - def test_has_partitioned_shots(self, shots, expected): - """Tests the has_partitioned_shots property.""" - assert Shots(shots).has_partitioned_shots is expected - - @pytest.mark.parametrize( - "shots, expected", - [ - (None, 0), - (10, 1), - ([10, 10], 2), - ([10, 10, 20], 3), - ([100, (10, 3)], 4), - ([(10, 3), (20, 2)], 5), - ], - ) - def test_num_copies(self, shots, expected): - """Tests the num_copies property.""" - assert Shots(shots).num_copies == expected diff --git a/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py deleted file mode 100644 index fddd47d9f3a..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_state_default_qubit_2.py +++ /dev/null @@ -1,796 +0,0 @@ -# Copyright 2018-2020 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 state module""" -import numpy as np -import pytest - -import pennylane as qml -from pennylane import numpy as pnp -from pennylane.devices import DefaultQubit -from pennylane.measurements import State, StateMP, Shots, density_matrix, expval, state -from pennylane.math.quantum import reduce_statevector, reduce_dm -from pennylane.math.matrix_manipulation import _permute_dense_matrix - -# pylint: disable=no-member, comparison-with-callable, import-outside-toplevel - - -class TestStateMP: - """Tests for the State measurement process.""" - - @pytest.mark.parametrize( - "vec", - [ - np.array([0.6, 0.8j]), - np.eye(4)[3], - np.array([0.48j, 0.48, -0.64j, 0.36]), - ], - ) - def test_process_state_vector(self, vec): - """Test the processing of a state vector.""" - - mp = StateMP(wires=None) - assert mp.return_type == State - assert mp.numeric_type is complex - - processed = mp.process_state(vec, None) - assert qml.math.allclose(processed, vec) - - @pytest.mark.parametrize( - "vec, wires", - [ - (np.array([0.6, 0.8j]), [0]), - (np.eye(4, dtype=np.complex64)[3], [0]), - (np.array([0.48j, 0.48, -0.64j, 0.36]), [0, 1]), - (np.array([0.48j, 0.48, -0.64j, 0.36]), [0]), - ], - ) - def test_process_state_matrix_from_vec(self, vec, wires): - """Test the processing of a state vector into a matrix.""" - - mp = StateMP(wires=wires) - assert mp.return_type == State - assert mp.numeric_type is complex - - num_wires = int(np.log2(len(vec))) - processed = mp.process_state(vec, list(range(num_wires))) - assert qml.math.shape(processed) == (2 ** len(wires), 2 ** len(wires)) - if len(wires) == num_wires: - exp = np.outer(vec, vec.conj()) - else: - exp = reduce_statevector(vec, wires) - assert qml.math.allclose(processed, exp) - - @pytest.mark.xfail(reason="StateMP.process_state no longer supports density matrix parameters") - @pytest.mark.parametrize( - "mat, wires", - [ - (np.eye(4, dtype=np.complex64) / 4, [0]), - (np.eye(4, dtype=np.complex64) / 4, [1, 0]), - (np.outer([0.6, 0.8j], [0.6, -0.8j]), [0]), - (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [0, 1]), - (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [0]), - (np.outer([0.36j, 0.48, 0.64, 0.48j], [-0.36j, 0.48, 0.64, -0.48j]), [1]), - ], - ) - def test_process_state_matrix_from_matrix(self, mat, wires): - """Test the processing of a density matrix into a matrix.""" - - mp = StateMP(wires=wires) - assert mp.return_type == State - assert mp.numeric_type is complex - - num_wires = int(np.log2(len(mat))) - order = list(range(num_wires)) - processed = mp.process_state(mat, order) - assert qml.math.shape(processed) == (2 ** len(wires), 2 ** len(wires)) - if len(wires) == num_wires: - exp = _permute_dense_matrix(mat, wires, order, None) - else: - exp = reduce_dm(mat, wires) - assert qml.math.allclose(processed, exp) - - -class TestState: - """Tests for the state function""" - - @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): - """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(): - qml.Identity(wires=list(range(wires))) - op(0) - return state() - - state_val = func() - assert state_val.shape == (2**wires,) - assert state_val.dtype == dtype - - def test_return_type_is_state(self): - """Test that the return type of the observable is State""" - - dev = qml.device("default.qubit", wires=1) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - return state() - - func() - obs = func.qtape.observables - assert len(obs) == 1 - assert obs[0].return_type is State - - @pytest.mark.parametrize("wires", range(2, 5)) - def test_state_correct_ghz(self, wires): - """Test that the correct state is returned when the circuit prepares a GHZ state""" - - dev = qml.device("default.qubit", wires=wires) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=0) - for i in range(wires - 1): - qml.CNOT(wires=[i, i + 1]) - return state() - - state_val = func() - assert np.allclose(np.sum(np.abs(state_val) ** 2), 1) - assert np.allclose(state_val[0], 1 / np.sqrt(2)) - assert np.allclose(state_val[-1], 1 / np.sqrt(2)) - - def test_return_with_other_types_works(self): - """Test that no exception is raised when a state is returned along with another return - type""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=0) - return state(), expval(qml.PauliZ(1)) - - res = func() - assert isinstance(res, tuple) - assert np.allclose(res[0], np.array([1, 0, 1, 0]) / np.sqrt(2)) - assert np.isclose(res[1], 1) - - @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""" - - dev = qml.device("default.qubit", wires=wires) - - weights = np.random.random( - qml.templates.StronglyEntanglingLayers.shape(n_layers=3, n_wires=wires) - ) - - @qml.qnode(dev) - def func(): - qml.templates.StronglyEntanglingLayers(weights, wires=range(wires)) - return state() - - state_val = func() - scripts, _, _ = dev.preprocess(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): - """Test that the state correctly outputs in the tensorflow interface""" - import tensorflow as tf - - dev = qml.device("default.qubit", wires=4) - - @qml.qnode(dev, interface="tf") - def func(): - op(0) - op(0) - for i in range(4): - qml.Hadamard(i) - return state() - - state_expected = 0.25 * tf.ones(16) - state_val = func() - - assert isinstance(state_val, tf.Tensor) - assert state_val.dtype == tf.complex128 if op is qml.PauliY else tf.float64 - assert np.allclose(state_expected, state_val.numpy()) - assert state_val.shape == (16,) - - @pytest.mark.torch - @pytest.mark.parametrize("op", [qml.PauliX, qml.PauliY]) - def test_interface_torch(self, op): - """Test that the state correctly outputs in the torch interface""" - import torch - - dev = qml.device("default.qubit", wires=4) - - @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 - state_expected = 0.25 * torch.ones(16, dtype=dtype) - state_val = func() - - assert isinstance(state_val, torch.Tensor) - assert state_val.dtype == dtype - assert torch.allclose(state_expected, state_val) - assert state_val.shape == (16,) - - @pytest.mark.autograd - def test_jacobian_not_supported(self): - """Test if an error is raised if the jacobian method is called via qml.grad""" - dev = qml.device("default.qubit", wires=4) - - @qml.qnode(dev, diff_method="parameter-shift") - def func(x): - for i in range(4): - qml.RX(x, wires=i) - return state() - - d_func = qml.jacobian(func) - - with pytest.raises( - ValueError, - match=( - "Computing the gradient of circuits that return the state with the " - "parameter-shift rule gradient transform is not supported" - ), - ): - d_func(pnp.array(0.1, requires_grad=True)) - - def test_no_state_capability(self, monkeypatch): - """Test if an error is raised for devices that are not capable of returning the state. - This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit.legacy", wires=1) - capabilities = dev.capabilities().copy() - capabilities["returns_state"] = False - - @qml.qnode(dev) - def func(): - return state() - - with monkeypatch.context() as m: - m.setattr(DefaultQubit, "capabilities", lambda *args, **kwargs: capabilities) - with pytest.raises(qml.QuantumFunctionError, match="The current device is not capable"): - func() - - def test_state_not_supported(self): - """Test if an error is raised for devices inheriting from the base Device class, - which do not currently support returning the state""" - dev = qml.device("default.gaussian", wires=1) - - @qml.qnode(dev) - def func(): - return state() - - with pytest.raises(qml.QuantumFunctionError, match="Returning the state is not supported"): - func() - - @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) - def test_default_qubit(self, diff_method): - """Test that the returned state is equal to the expected returned state for all of - PennyLane's built in statevector devices""" - - dev = qml.device("default.qubit", wires=4) - - @qml.qnode(dev, diff_method=diff_method) - def func(): - for i in range(4): - qml.Hadamard(i) - return state() - - state_val = func() - state_expected = 0.25 * np.ones(16) - - assert np.allclose(state_val, state_expected) - - @pytest.mark.tf - @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) - def test_default_qubit_tf(self, diff_method): - """Test that the returned state is equal to the expected returned state for all of - PennyLane's built in statevector devices""" - - dev = qml.device("default.qubit.tf", wires=4) - - @qml.qnode(dev, diff_method=diff_method) - def func(): - for i in range(4): - qml.Hadamard(i) - return state() - - state_val = func() - state_expected = 0.25 * np.ones(16) - - assert np.allclose(state_val, state_expected) - - @pytest.mark.autograd - @pytest.mark.parametrize("diff_method", ["best", "finite-diff", "parameter-shift"]) - def test_default_qubit_autograd(self, diff_method): - """Test that the returned state is equal to the expected returned state for all of - PennyLane's built in statevector devices""" - - dev = qml.device("default.qubit.autograd", wires=4) - - @qml.qnode(dev, diff_method=diff_method) - def func(): - for i in range(4): - qml.Hadamard(i) - return state() - - state_val = func() - state_expected = 0.25 * np.ones(16) - - assert np.allclose(state_val, state_expected) - - @pytest.mark.tf - def test_gradient_with_passthru_tf(self): - """Test that the gradient of the state is accessible when using default.qubit.tf with the - backprop diff_method.""" - import tensorflow as tf - - dev = qml.device("default.qubit.tf", wires=1) - - @qml.qnode(dev, interface="tf", diff_method="backprop") - def func(x): - qml.RY(x, wires=0) - return state() - - x = tf.Variable(0.1, dtype=tf.float64) - - with tf.GradientTape() as tape: - result = func(x) - - grad = tape.jacobian(result, x) - expected = tf.stack([-0.5 * tf.sin(x / 2), 0.5 * tf.cos(x / 2)]) - assert np.allclose(grad, expected) - - @pytest.mark.autograd - def test_gradient_with_passthru_autograd(self): - """Test that the gradient of the state is accessible when using default.qubit.autograd - with the backprop diff_method.""" - - dev = qml.device("default.qubit.autograd", wires=1) - - @qml.qnode(dev, interface="autograd", diff_method="backprop") - def func(x): - qml.RY(x, wires=0) - return state() - - x = pnp.array(0.1, requires_grad=True) - - def loss_fn(x): - res = func(x) - return pnp.real(res) # This errors without the real. Likely an issue with complex - # numbers in autograd - - d_loss_fn = qml.jacobian(loss_fn) - - grad = d_loss_fn(x) - expected = np.array([-0.5 * np.sin(x / 2), 0.5 * np.cos(x / 2)]) - assert np.allclose(grad, expected) - - @pytest.mark.parametrize("wires", [[0, 2, 3, 1], ["a", -1, "b", 1000]]) - def test_custom_wire_labels(self, wires): - """Test the state when custom wire labels are used""" - dev = qml.device("default.qubit", wires=wires) - - @qml.qnode(dev, diff_method="parameter-shift") - def func(): - for i in range(4): - qml.Hadamard(wires[i]) - return state() - - state_expected = 0.25 * np.ones(16) - state_val = func() - - assert np.allclose(state_expected, state_val) - - @pytest.mark.parametrize("shots", [None, 1, 10]) - def test_shape(self, shots): - """Test that the shape is correct for qml.state.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - res = qml.state() - assert res.shape(dev, Shots(shots)) == (2**3,) - - @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) - def test_shape_shot_vector(self, s_vec): - """Test that the shape is correct for qml.state with the shot vector too.""" - dev = qml.device("default.qubit", wires=3, shots=s_vec) - res = qml.state() - assert res.shape(dev, Shots(s_vec)) == ((2**3,), (2**3,), (2**3,)) - - def test_numeric_type(self): - """Test that the numeric type of state measurements.""" - assert qml.state().numeric_type == complex - assert qml.density_matrix(wires=[0, 1]).numeric_type == complex - - -class TestDensityMatrix: - """Tests for the density matrix function""" - - # pylint: disable=too-many-public-methods - - @pytest.mark.parametrize("wires", range(2, 5)) - @pytest.mark.parametrize("op,dtype", [(qml.PauliX, np.float64), (qml.PauliY, np.complex128)]) - def test_density_matrix_shape_and_dtype(self, op, dtype, wires): - """Test that the density matrix is of correct size and dtype for a - trivial circuit""" - - dev = qml.device("default.qubit", wires=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 - - def test_return_type_is_state(self): - """Test that the return type of the observable is State""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - return density_matrix(0) - - func() - obs = func.qtape.observables - assert len(obs) == 1 - assert obs[0].return_type is State - - @pytest.mark.torch - @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_torch(self, diff_method): - """Test that the correct density matrix is returned using torch interface.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface="torch", diff_method=diff_method) - def func(): - qml.Hadamard(wires=0) - return qml.density_matrix(wires=0) - - density_mat = 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_mat) - - @pytest.mark.jax - @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_jax(self, diff_method): - """Test that the correct density matrix is returned using JAX interface.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface="jax", diff_method=diff_method) - def func(): - qml.Hadamard(wires=0) - return qml.density_matrix(wires=0) - - density_mat = 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_mat) - - @pytest.mark.tf - @pytest.mark.parametrize("diff_method", [None, "backprop"]) - def test_correct_density_matrix_tf(self, diff_method): - """Test that the correct density matrix is returned using the TensorFlow interface.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface="tf", diff_method=diff_method) - def func(): - qml.Hadamard(wires=0) - return qml.density_matrix(wires=0) - - density_mat = 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_mat) - - def test_correct_density_matrix_product_state_first(self): - """Test that the correct density matrix is returned when - tracing out a product state""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=1) - qml.PauliY(wires=0) - return density_matrix(0) - - density_first = func() - expected = np.array([[0.0 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 1.0 + 0.0j]]) - - assert np.allclose(expected, density_first) - - def test_correct_density_matrix_product_state_second(self): - """Test that the correct density matrix is returned when - tracing out a product state""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=1) - qml.PauliY(wires=0) - return density_matrix(1) - - density_second = 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.parametrize("return_wire_order", ([0, 1], [1, 0])) - def test_correct_density_matrix_product_state_both(self, return_wire_order): - """Test that the correct density matrix is returned - for a full product state on two wires.""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=1) - qml.PauliY(wires=0) - return density_matrix(return_wire_order) - - density_both = func() - single_statevectors = [[0, 1j], [1 / np.sqrt(2), 1 / np.sqrt(2)]] - expected_statevector = np.kron(*[single_statevectors[w] for w in return_wire_order]) - expected = np.outer(expected_statevector.conj(), expected_statevector) - - assert np.allclose(expected, density_both) - - def test_correct_density_matrix_three_wires_first_two(self): - """Test that the correct density matrix is returned for an example with three wires, - and tracing out the third wire.""" - - dev = qml.device("default.qubit", wires=3) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=1) - qml.PauliY(wires=0) - return density_matrix([0, 1]) - - density_full = func() - expected = np.array( - [ - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j, 0.5 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j, 0.5 + 0.0j], - ] - ) - assert np.allclose(expected, density_full) - - def test_correct_density_matrix_three_wires_last_two(self): - """Test that the correct density matrix is returned for an example with three wires, - and tracing out the first wire.""" - - dev = qml.device("default.qubit", wires=3) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - qml.Hadamard(1) - qml.CNOT(wires=[1, 2]) - return qml.density_matrix(wires=[1, 2]) - - density = func() - expected = np.array( - [ - [ - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - ] - ] - ) - - assert np.allclose(expected, density) - - @pytest.mark.parametrize( - "return_wire_order", ([0], [1], [2], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2, 0], [2, 1, 0]) - ) - def test_correct_density_matrix_three_wires_product(self, return_wire_order): - """Test that the correct density matrix is returned for an example with - three wires and a product state, tracing out various combinations.""" - - dev = qml.device("default.qubit", wires=3) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - qml.PauliX(1) - qml.PauliZ(2) - return density_matrix(return_wire_order) - - density_full = func() - - single_states = [[1 / np.sqrt(2), 1 / np.sqrt(2)], [0, 1], [1, 0]] - if len(return_wire_order) == 1: - exp_statevector = np.array(single_states[return_wire_order[0]]) - elif len(return_wire_order) == 2: - i, j = return_wire_order - exp_statevector = np.kron(single_states[i], single_states[j]) - elif len(return_wire_order) == 3: - i, j, k = return_wire_order - exp_statevector = np.kron(np.kron(single_states[i], single_states[j]), single_states[k]) - - expected = np.outer(exp_statevector.conj(), exp_statevector) - assert np.allclose(expected, density_full) - - def test_correct_density_matrix_mixed_state(self): - """Test that the correct density matrix for an example with a mixed state""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - qml.CNOT(wires=[0, 1]) - return qml.density_matrix(wires=[1]) - - density = func() - - assert np.allclose(np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]), density) - - def test_correct_density_matrix_all_wires(self): - """Test that the correct density matrix is returned when all wires are given""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(0) - qml.CNOT(wires=[0, 1]) - return qml.density_matrix(wires=[0, 1]) - - density = func() - expected = np.array( - [ - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - ] - ) - - assert np.allclose(expected, density) - - def test_return_with_other_types_works(self): - """Test that no exception is raised when a state is returned along with another return - type""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires=0) - return density_matrix(0), expval(qml.PauliZ(1)) - - res = func() - assert isinstance(res, tuple) - assert np.allclose(res[0], np.ones((2, 2)) / 2) - assert np.isclose(res[1], 1) - - def test_no_state_capability(self, monkeypatch): - """Test if an error is raised for devices that are not capable of returning - the density matrix. This is tested by changing the capability of default.qubit""" - dev = qml.device("default.qubit.legacy", wires=2) - capabilities = dev.capabilities().copy() - capabilities["returns_state"] = False - - @qml.qnode(dev) - def func(): - return density_matrix(0) - - with monkeypatch.context() as m: - m.setattr(DefaultQubit, "capabilities", lambda *args, **kwargs: capabilities) - with pytest.raises( - qml.QuantumFunctionError, - match="The current device is not capable" " of returning the state", - ): - func() - - def test_density_matrix_not_supported(self): - """Test if an error is raised for devices inheriting from the base Device class, - which do not currently support returning the state""" - dev = qml.device("default.gaussian", wires=2) - - @qml.qnode(dev) - def func(): - return density_matrix(0) - - with pytest.raises(qml.QuantumFunctionError, match="Returning the state is not supported"): - func() - - @pytest.mark.parametrize("wires", [[0, 2], ["a", -1]]) - def test_custom_wire_labels(self, wires): - """Test that the correct density matrix for an example with a mixed - state when using custom wires""" - - dev = qml.device("default.qubit", wires=wires) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires[0]) - qml.CNOT(wires=[wires[0], wires[1]]) - return qml.density_matrix(wires=wires[1]) - - density = func() - expected = np.array([[0.5 + 0.0j, 0.0 + 0.0j], [0.0 + 0.0j, 0.5 + 0.0j]]) - - assert np.allclose(expected, density) - - @pytest.mark.parametrize("wires", [[3, 1], ["b", 1000]]) - def test_custom_wire_labels_all_wires(self, wires): - """Test that the correct density matrix for an example with a mixed - state when using custom wires""" - dev = qml.device("default.qubit", wires=wires) - - @qml.qnode(dev) - def func(): - qml.Hadamard(wires[0]) - qml.CNOT(wires=[wires[0], wires[1]]) - return qml.density_matrix(wires=[wires[0], wires[1]]) - - density = func() - - assert np.allclose( - np.array( - [ - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j], - [0.5 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.5 + 0.0j], - ] - ), - density, - ) - - @pytest.mark.parametrize("shots", [None, 1, 10]) - def test_shape(self, shots): - """Test that the shape is correct for qml.density_matrix.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - res = qml.density_matrix(wires=[0, 1]) - assert res.shape(dev, Shots(shots)) == (2**2, 2**2) - - @pytest.mark.parametrize("s_vec", [(3, 2, 1), (1, 5, 10), (3, 1, 20)]) - def test_shape_shot_vector(self, s_vec): - """Test that the shape is correct for qml.density_matrix with the shot vector too.""" - dev = qml.device("default.qubit", wires=3, shots=s_vec) - res = qml.density_matrix(wires=[0, 1]) - assert res.shape(dev, Shots(s_vec)) == ( - (2**2, 2**2), - (2**2, 2**2), - (2**2, 2**2), - ) diff --git a/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py deleted file mode 100644 index d377f7a2e1a..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_var_default_qubit_2.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2018-2020 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 var module""" -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import Variance, Shots - - -class TestVar: - """Tests for the var function""" - - @pytest.mark.parametrize("shots", [None, 10000, [10000, 10000]]) - def test_value(self, tol, shots): - """Test that the var function works""" - dev = qml.device("default.qubit", wires=2, shots=shots) - - @qml.qnode(dev, diff_method="parameter-shift") - def circuit(x): - qml.RX(x, wires=0) - return qml.var(qml.PauliZ(0)) - - x = 0.54 - res = circuit(x) - expected = [np.sin(x) ** 2, np.sin(x) ** 2] if isinstance(shots, list) else np.sin(x) ** 2 - atol = tol if shots is None else 0.05 - rtol = 0 if shots is None else 0.05 - - assert np.allclose(res, expected, atol=atol, rtol=rtol) - r_dtype = np.float64 - if isinstance(res, tuple): - assert res[0].dtype == r_dtype - assert res[1].dtype == r_dtype - else: - assert res.dtype == r_dtype - - def test_not_an_observable(self): - """Test that a UserWarning is raised if the provided - argument might not be hermitian.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - qml.RX(0.52, wires=0) - return qml.var(qml.prod(qml.PauliX(0), qml.PauliZ(0))) - - with pytest.warns(UserWarning, match="Prod might not be hermitian."): - _ = circuit() - - def test_observable_return_type_is_variance(self): - """Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - res = qml.var(qml.PauliZ(0)) - assert res.return_type is Variance - return res - - circuit() - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_numeric_type(self, obs): - """Test that the numeric type is correct.""" - res = qml.var(obs) - assert res.numeric_type is float - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_shape(self, obs): - """Test that the shape is correct.""" - dev = qml.device("default.qubit", wires=1) - res = qml.var(obs) - # pylint: disable=use-implicit-booleaness-not-comparison - assert res.shape(dev, Shots(None)) == () - assert res.shape(dev, Shots(100)) == () - - @pytest.mark.parametrize( - "obs", - [qml.PauliZ(0), qml.Hermitian(np.diag([1, 2]), 0), qml.Hermitian(np.diag([1.0, 2.0]), 0)], - ) - def test_shape_shot_vector(self, obs): - """Test that the shape is correct with the shot vector too.""" - res = qml.var(obs) - shot_vector = (1, 2, 3) - dev = qml.device("default.qubit", wires=3, shots=shot_vector) - assert res.shape(dev, Shots(shot_vector)) == ((), (), ()) - - @pytest.mark.parametrize("state", [np.array([0, 0, 0]), np.array([1, 0, 0, 0, 0, 0, 0, 0])]) - @pytest.mark.parametrize("shots", [None, 1000, [1000, 10000]]) - def test_projector_var(self, state, shots): - """Tests that the variance of a ``Projector`` object is computed correctly.""" - dev = qml.device("default.qubit", wires=3, shots=shots) - - @qml.qnode(dev) - def circuit(): - qml.Hadamard(0) - return qml.var(qml.Projector(state, wires=range(3))) - - res = circuit() - expected = [0.25, 0.25] if isinstance(shots, list) else 0.25 - - assert np.allclose(res, expected, atol=0.02, rtol=0.02) - - def test_permuted_wires(self): - """Test that the variance of an operator with permuted wires is the same.""" - obs = qml.prod(qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)), qml.s_prod(3, qml.PauliZ("h"))) - obs_2 = qml.prod( - qml.s_prod(3, qml.PauliZ("h")), qml.PauliZ(8), qml.s_prod(2, qml.PauliZ(10)) - ) - - dev = qml.device("default.qubit", wires=["h", 8, 10]) - - @qml.qnode(dev) - def circuit(): - qml.RX(1.23, wires=["h"]) - qml.RY(2.34, wires=[8]) - return qml.var(obs) - - @qml.qnode(dev) - def circuit2(): - qml.RX(1.23, wires=["h"]) - qml.RY(2.34, wires=[8]) - return qml.var(obs_2) - - assert circuit() == circuit2() diff --git a/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py b/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py deleted file mode 100644 index c494073d777..00000000000 --- a/tests/measurements/default_qubit_2_integration/test_vn_entropy_default_qubit_2.py +++ /dev/null @@ -1,405 +0,0 @@ -# Copyright 2018-2020 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 vn_entropy module""" -import copy - -import numpy as np -import pytest - -import pennylane as qml -from pennylane.measurements import VnEntropy, Shots -from pennylane.measurements.vn_entropy import VnEntropyMP -from pennylane.wires import Wires - -# pylint: disable=too-many-arguments, no-member - - -def expected_entropy_ising_xx(param): - """ - Return the analytical entropy for the IsingXX. - """ - eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eigs = [eig_1, eig_2] - eigs = [eig for eig in eigs if eig > 0] - - expected_entropy = eigs * np.log(eigs) - - expected_entropy = -np.sum(expected_entropy) - return expected_entropy - - -def expected_entropy_grad_ising_xx(param): - """ - Return the analytical gradient entropy for the IsingXX. - """ - eig_1 = (1 + np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eig_2 = (1 - np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2)) / 2 - eigs = [eig_1, eig_2] - eigs = np.maximum(eigs, 1e-08) - - return -( - (np.log(eigs[0]) + 1) - * (np.sin(param / 2) ** 3 * np.cos(param / 2) - np.sin(param / 2) * np.cos(param / 2) ** 3) - / np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2) - ) - ( - (np.log(eigs[1]) + 1) - * ( - np.sin(param / 2) - * np.cos(param / 2) - * (np.cos(param / 2) ** 2 - np.sin(param / 2) ** 2) - ) - / np.sqrt(1 - 4 * np.cos(param / 2) ** 2 * np.sin(param / 2) ** 2) - ) - - -class TestInitialization: - """Unit tests for the ``qml.vn_entropy`` function.""" - - @pytest.mark.all_interfaces - @pytest.mark.parametrize( - "state_vector,expected", - [([1.0, 0.0, 0.0, 1.0] / qml.math.sqrt(2), qml.math.log(2)), ([1.0, 0.0, 0.0, 0.0], 0)], - ) - @pytest.mark.parametrize("interface", ["autograd", "jax", "tf", "torch"]) - def test_vn_entropy(self, interface, state_vector, expected): - """Tests the output of qml.vn_entropy""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface) - def circuit(): - qml.StatePrep(state_vector, wires=[0, 1]) - return qml.vn_entropy(wires=0) - - assert qml.math.allclose(circuit(), expected) - - def test_queue(self): - """Test that the right measurement class is queued.""" - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev) - def circuit(): - return qml.vn_entropy(wires=0, log_base=2) - - circuit() - - assert isinstance(circuit.tape[0], VnEntropyMP) - - def test_copy(self): - """Test that the ``__copy__`` method also copies the ``log_base`` information.""" - meas = qml.vn_entropy(wires=0, log_base=2) - meas_copy = copy.copy(meas) - assert meas_copy.log_base == 2 - assert meas_copy.wires == Wires(0) - - def test_properties(self): - """Test that the properties are correct.""" - meas = qml.vn_entropy(wires=0) - assert meas.numeric_type == float - assert meas.return_type == VnEntropy - - @pytest.mark.parametrize("shots, shape", [(None, ()), (10, ()), ((1, 10), ((), ()))]) - def test_shape(self, shots, shape): - """Test the ``shape`` method.""" - meas = qml.vn_entropy(wires=0) - dev = qml.device("default.qubit", wires=1, shots=shots) - - assert meas.shape(dev, Shots(shots)) == shape - - -class TestIntegration: - """Integration tests for the vn_entropy measurement function.""" - - parameters = np.linspace(0, 2 * np.pi, 10) - - devices = ["default.qubit", "default.mixed", "lightning.qubit"] - - single_wires_list = [ - [0], - [1], - ] - - base = [2, np.exp(1), 10] - - check_state = [True, False] - - devices = ["default.qubit", "default.mixed"] - diff_methods = ["backprop", "finite-diff"] - - @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.""" - dev = qml.device("default.qubit", wires=2, shots=shots) - - @qml.qnode(device=dev) - def circuit(x): - qml.Hadamard(wires=[0]) - qml.CRX(x, wires=[0, 1]) - return qml.vn_entropy(wires=[0]) - - with pytest.raises(qml.DeviceError, match="Circuits with finite shots must only contain"): - circuit(0.5) - - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("base", base) - def test_IsingXX_qnode_entropy(self, param, wires, device, base): - """Test entropy for a QNode numpy.""" - - dev = qml.device(device, wires=2) - - @qml.qnode(dev) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - entropy = circuit_entropy(param) - - expected_entropy = expected_entropy_ising_xx(param) / np.log(base) - assert qml.math.allclose(entropy, expected_entropy) - - @pytest.mark.autograd - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("diff_method", diff_methods) - def test_IsingXX_qnode_entropy_grad(self, param, wires, base, diff_method): - """Test entropy for a QNode gradient with autograd.""" - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, diff_method=diff_method) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - grad_entropy = qml.grad(circuit_entropy)(param) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) - assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) - - @pytest.mark.torch - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("interface", ["torch"]) - def test_IsingXX_qnode_torch_entropy(self, param, wires, device, base, interface): - """Test entropy for a QNode with torch interface.""" - import torch - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - entropy = circuit_entropy(torch.tensor(param)) - - expected_entropy = expected_entropy_ising_xx(param) / np.log(base) - - assert qml.math.allclose(entropy, expected_entropy) - - @pytest.mark.torch - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("diff_method", diff_methods) - def test_IsingXX_qnode_entropy_grad_torch(self, param, wires, base, diff_method): - """Test entropy for a QNode gradient with torch.""" - import torch - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface="torch", diff_method=diff_method) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) - - param = torch.tensor(param, dtype=torch.float64, requires_grad=True) - entropy = circuit_entropy(param) - entropy.backward() - grad_entropy = param.grad - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) - - @pytest.mark.tf - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("interface", ["tf"]) - def test_IsingXX_qnode_tf_entropy(self, param, wires, device, base, interface): - """Test entropy for a QNode with tf interface.""" - import tensorflow as tf - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - entropy = circuit_entropy(tf.Variable(param)) - - expected_entropy = expected_entropy_ising_xx(param) / np.log(base) - - assert qml.math.allclose(entropy, expected_entropy) - - @pytest.mark.tf - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["tf"]) - def test_IsingXX_qnode_entropy_grad_tf(self, param, wires, base, diff_method, interface): - """Test entropy for a QNode gradient with tf.""" - import tensorflow as tf - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - param = tf.Variable(param) - with tf.GradientTape() as tape: - entropy = circuit_entropy(param) - - grad_entropy = tape.gradient(entropy, param) - - grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - assert qml.math.allclose(grad_entropy, grad_expected_entropy, atol=tol) - - @pytest.mark.jax - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("interface", ["jax"]) - def test_IsingXX_qnode_jax_entropy(self, param, wires, device, base, interface): - """Test entropy for a QNode with jax interface.""" - import jax.numpy as jnp - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - entropy = circuit_entropy(jnp.array(param)) - - expected_entropy = expected_entropy_ising_xx(param) / np.log(base) - - assert qml.math.allclose(entropy, expected_entropy) - - @pytest.mark.jax - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax"]) - def test_IsingXX_qnode_entropy_grad_jax(self, param, wires, base, diff_method, interface): - """Test entropy for a QNode gradient with Jax.""" - import jax - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - grad_entropy = jax.grad(circuit_entropy)(jax.numpy.array(param)) - grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) - - # higher tolerance for finite-diff method - tol = 1e-8 if diff_method == "backprop" else 1e-5 - - assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=tol) - - @pytest.mark.jax - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("device", devices) - @pytest.mark.parametrize("interface", ["jax"]) - def test_IsingXX_qnode_jax_jit_entropy(self, param, wires, base, device, interface): - """Test entropy for a QNode with jax-jit interface.""" - import jax - import jax.numpy as jnp - - dev = qml.device(device, wires=2) - - @qml.qnode(dev, interface=interface) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - entropy = jax.jit(circuit_entropy)(jnp.array(param)) - - expected_entropy = expected_entropy_ising_xx(param) / np.log(base) - - assert qml.math.allclose(entropy, expected_entropy) - - @pytest.mark.jax - @pytest.mark.parametrize("wires", single_wires_list) - @pytest.mark.parametrize("param", parameters) - @pytest.mark.parametrize("base", base) - @pytest.mark.parametrize("diff_method", diff_methods) - @pytest.mark.parametrize("interface", ["jax-jit"]) - def test_IsingXX_qnode_entropy_grad_jax_jit(self, param, wires, base, diff_method, interface): - """Test entropy for a QNode gradient with Jax-jit.""" - import jax - - dev = qml.device("default.qubit", wires=2) - - @qml.qnode(dev, interface=interface, diff_method=diff_method) - def circuit_entropy(x): - qml.IsingXX(x, wires=[0, 1]) - return qml.vn_entropy(wires=wires, log_base=base) - - grad_entropy = jax.jit(jax.grad(circuit_entropy))(jax.numpy.array(param)) - - grad_expected_entropy = expected_entropy_grad_ising_xx(param) / np.log(base) - - assert qml.math.allclose(grad_entropy, grad_expected_entropy, rtol=1e-04, atol=1e-05) - - def test_qnode_entropy_custom_wires(self): - """Test that entropy can be returned with custom wires.""" - - dev = qml.device("default.qubit", wires=["a", 1]) - - @qml.qnode(dev) - def circuit_entropy(x): - qml.IsingXX(x, wires=["a", 1]) - return qml.vn_entropy(wires=["a"]) - - assert np.isclose(circuit_entropy(0.1), expected_entropy_ising_xx(0.1)) From ca03c82c25eafe4ea488d5e6164841c5790aaf6a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 6 Sep 2023 23:58:29 -0400 Subject: [PATCH 44/78] put back other things already on master --- pennylane/interfaces/execution.py | 1 - pennylane/measurements/probs.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pennylane/interfaces/execution.py b/pennylane/interfaces/execution.py index 345a96ca216..ad4b343deec 100644 --- a/pennylane/interfaces/execution.py +++ b/pennylane/interfaces/execution.py @@ -254,7 +254,6 @@ def inner_execute(tapes: Sequence[QuantumTape], **_) -> ResultBatch: tapes = tuple(qml.transforms.convert_to_numpy_parameters(t) for t in tapes) return cached_device_execution(tapes) - # TODO: set as pure_callback if interface is jax-jit return inner_execute diff --git a/pennylane/measurements/probs.py b/pennylane/measurements/probs.py index dcdb4daa164..b8024208db9 100644 --- a/pennylane/measurements/probs.py +++ b/pennylane/measurements/probs.py @@ -269,12 +269,11 @@ def marginal_prob(self, prob, wire_order, batch_size): return prob # determine which subsystems are to be summed over - self_wires = self.wires or qml.wires.Wires(wire_order) - inactive_wires = Wires.unique_wires([wire_order, self_wires]) + inactive_wires = Wires.unique_wires([wire_order, self.wires]) # translate to wire labels used by device wire_map = dict(zip(wire_order, range(len(wire_order)))) - mapped_wires = [wire_map[w] for w in self_wires] + mapped_wires = [wire_map[w] for w in self.wires] inactive_wires = [wire_map[w] for w in inactive_wires] # reshape the probability so that each axis corresponds to a wire From a5f2f599dd0814b5c1dbcffd476e1926c23fe508 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 7 Sep 2023 00:35:57 -0400 Subject: [PATCH 45/78] fix broken tests --- tests/logging/test_logging_autograd.py | 4 ++-- tests/ops/qubit/test_parametric_ops.py | 3 +++ tests/test_qubit_device.py | 6 ++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/logging/test_logging_autograd.py b/tests/logging/test_logging_autograd.py index a325a578f42..e410a043e9f 100644 --- a/tests/logging/test_logging_autograd.py +++ b/tests/logging/test_logging_autograd.py @@ -88,7 +88,7 @@ def circuit(params): ( "pennylane.interfaces.execution", [ - "device= Date: Thu, 7 Sep 2023 18:23:08 -0400 Subject: [PATCH 46/78] fix fisher test --- pennylane/qinfo/transforms.py | 4 +++- tests/qinfo/test_fisher.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pennylane/qinfo/transforms.py b/pennylane/qinfo/transforms.py index 16831ccf73a..be51ba27379 100644 --- a/pennylane/qinfo/transforms.py +++ b/pennylane/qinfo/transforms.py @@ -640,7 +640,9 @@ def circ(params): """ - if qnode.device.shots is not None and isinstance(qnode.device, DefaultQubit): + if qnode.device.shots and isinstance( + qnode.device, (DefaultQubit, qml.devices.experimental.Device) + ): def wrapper(*args0, **kwargs0): return 4 * metric_tensor(qnode, *args, **kwargs)(*args0, **kwargs0) diff --git a/tests/qinfo/test_fisher.py b/tests/qinfo/test_fisher.py index 0fc96ddabf1..6a69f2a1908 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) From 8b46f45966122f01577cd830569def30145fe2f7 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 7 Sep 2023 18:24:44 -0400 Subject: [PATCH 47/78] actually use new device --- tests/qinfo/test_fisher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/qinfo/test_fisher.py b/tests/qinfo/test_fisher.py index 6a69f2a1908..7ccae1e9e29 100644 --- a/tests/qinfo/test_fisher.py +++ b/tests/qinfo/test_fisher.py @@ -150,8 +150,8 @@ def test_quantum_fisher_info(self): n_wires = 2 - dev = qml.device("default.qubit.legacy", wires=n_wires) - dev_hard = qml.device("default.qubit.legacy", wires=n_wires + 1, shots=1000) + dev = qml.device("default.qubit", wires=n_wires) + dev_hard = qml.device("default.qubit", wires=n_wires + 1, shots=1000) def qfunc(params): qml.RX(params[0], wires=0) @@ -163,7 +163,7 @@ def qfunc(params): circ_hard = qml.QNode(qfunc, dev_hard) QFIM_hard = quantum_fisher(circ_hard)(params) - QFIM1_hard = 4.0 * qml.metric_tensor(circ_hard)(params) # pylint:disable=not-callable + QFIM1_hard = 4.0 * qml.metric_tensor(circ_hard)(params) circ = qml.QNode(qfunc, dev) QFIM = quantum_fisher(circ)(params) From ae4f13b7c9a519c6149e89964ebd9e638899a3ac Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 7 Sep 2023 22:33:08 -0400 Subject: [PATCH 48/78] remove unneeded skips from tests --- tests/gradients/core/test_jvp.py | 2 -- tests/gradients/core/test_pulse_generator_gradient.py | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/gradients/core/test_jvp.py b/tests/gradients/core/test_jvp.py index de1af8f1f63..ac973027534 100644 --- a/tests/gradients/core/test_jvp.py +++ b/tests/gradients/core/test_jvp.py @@ -496,8 +496,6 @@ def test_multiple_expectation_values(self, tol, batch_dim): with multiple expval outputs""" if batch_dim is not None: pytest.skip(msg="JVP computation of batched tapes is disallowed, see #4462") - if batch_dim == 1: - pytest.skip(msg="batch dimension of 1 gets squeezed out") dev = qml.device("default.qubit", wires=2) x = 0.543 if batch_dim is None else 0.543 * np.arange(1, 1 + batch_dim) y = -0.654 diff --git a/tests/gradients/core/test_pulse_generator_gradient.py b/tests/gradients/core/test_pulse_generator_gradient.py index 2426ba114a7..3396fe02210 100644 --- a/tests/gradients/core/test_pulse_generator_gradient.py +++ b/tests/gradients/core/test_pulse_generator_gradient.py @@ -1383,9 +1383,6 @@ def test_advanced_qnode(self, dev_name): import jax import jax.numpy as jnp - if dev_name == "default.qubit": - pytest.skip("num_executions is not correct") - jax.config.update("jax_enable_x64", True) params = [jnp.array(0.21), jnp.array(-0.171), jnp.array([0.05, 0.03, -0.1])] @@ -1408,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( From 6cb266c9f8b6fc4621a0e274266dbec6b31ccbc7 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 15:33:07 -0400 Subject: [PATCH 49/78] try to run qnn tests with new device --- tests/qnn/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qnn/conftest.py b/tests/qnn/conftest.py index 858a5819c26..8fb292a10ac 100644 --- a/tests/qnn/conftest.py +++ b/tests/qnn/conftest.py @@ -24,7 +24,7 @@ def get_circuit(n_qubits, output_dim, interface): """Fixture for getting a sample quantum circuit with a controllable qubit number and output dimension. Returns both the circuit and the shape of the weights.""" - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), @@ -60,7 +60,7 @@ def get_circuit_dm(n_qubits, output_dim, interface): dimension for density matrix return type. Returns both the circuit and the shape of the weights. """ - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), From b8699627f4a59e04dda51bd581db0fe9d4d12a8d Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 15:35:17 -0400 Subject: [PATCH 50/78] add xfail for now --- tests/test_return_types_qnode.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_return_types_qnode.py b/tests/test_return_types_qnode.py index 3074c3fa7a5..f41d76c6d8d 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -37,6 +37,7 @@ def qutrit_ansatz(x): class TestIntegrationSingleReturn: """Test that single measurements return behavior does not change.""" + @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires): """Return state with default.qubit.""" From b9107637605c684a40bdc88a4796db147bdf9283 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 15:58:00 -0400 Subject: [PATCH 51/78] check out qinfo transforms file from master --- pennylane/qinfo/transforms.py | 329 +++++++++++++++++++++------------- 1 file changed, 209 insertions(+), 120 deletions(-) diff --git a/pennylane/qinfo/transforms.py b/pennylane/qinfo/transforms.py index be51ba27379..a737eecb5e1 100644 --- a/pennylane/qinfo/transforms.py +++ b/pennylane/qinfo/transforms.py @@ -14,30 +14,30 @@ """QNode transforms for the quantum information quantities.""" # pylint: disable=import-outside-toplevel, not-callable import functools -from typing import Sequence, Callable +from typing import Callable, Sequence import pennylane as qml -from pennylane.devices import DefaultQubit -from pennylane.measurements import StateMP +from pennylane.devices import DefaultQubit, DefaultMixed +from pennylane.measurements import StateMP, DensityMatrixMP +from pennylane.tape import QuantumTape from pennylane.transforms import adjoint_metric_tensor, metric_tensor from pennylane.transforms.core import transform -def _get_qnode_wires(qnode): - return qnode.device.wires if isinstance(qnode.device, qml.Device) else qnode.tape.wires - - -def reduced_dm(qnode, wires): +@transform +def reduced_dm(tape: QuantumTape, wires, **kwargs) -> (Sequence[QuantumTape], Callable): """Compute the reduced density matrix from a :class:`~.QNode` returning :func:`~pennylane.state`. Args: - qnode (QNode): A :class:`~.QNode` returning :func:`~pennylane.state`. + tape (QuantumTape): A :class:`~.QuantumTape` returning :func:`~pennylane.state`. wires (Sequence(int)): List of wires in the considered subsystem. Returns: - func: Function which wraps the QNode and accepts the same arguments. When called, - this function will return the density matrix. + pennylane.QNode or qfunc or tuple[List[.QuantumTape], Callable]: If a QNode + is passed, it returns a QNode with the transform added to its transform program. + If a tape is passed, returns a tuple containing a list of quantum tapes to be + evaluated, and a function to be applied to these tape executions. **Example** @@ -46,44 +46,67 @@ def reduced_dm(qnode, wires): import numpy as np dev = qml.device("default.qubit", wires=2) + @qml.qnode(dev) def circuit(x): - qml.IsingXX(x, wires=[0,1]) - return qml.state() + qml.IsingXX(x, wires=[0,1]) + return qml.state() - >>> reduced_dm(circuit, wires=[0])(np.pi/2) - [[0.5+0.j 0.+0.j] - [0.+0.j 0.5+0.j]] + >>> transformed_circuit = reduced_dm(circuit, wires=[0]) + >>> transformed_circuit(np.pi/2) + tensor([[0.5+0.j, 0. +0.j], + [0. +0.j, 0.5+0.j]], requires_grad=True) .. seealso:: :func:`pennylane.density_matrix` and :func:`pennylane.math.reduce_dm` """ + # device_wires is provided by the custom QNode transform + all_wires = kwargs.get("device_wires", tape.wires) + wire_map = {w: i for i, w in enumerate(all_wires)} + indices = [wire_map[w] for w in wires] + + measurements = tape.measurements + if len(measurements) != 1 or not isinstance(measurements[0], StateMP): + raise ValueError("The qfunc measurement needs to be State.") + + def processing_fn(res): + # device is provided by the custom QNode transform + device = kwargs.get("device", None) + c_dtype = device.C_DTYPE if device else "complex128" + + # determine the density matrix + dm_func = ( + qml.math.reduce_dm + if isinstance(measurements[0], DensityMatrixMP) or isinstance(device, DefaultMixed) + else qml.math.reduce_statevector + ) + density_matrix = dm_func(res[0], indices=indices, c_dtype=c_dtype) - def wrapper(*args, **kwargs): - qnode.construct(args, kwargs) - measurements = qnode.tape.measurements - if len(measurements) != 1 or not isinstance(measurements[0], StateMP): - raise ValueError("The qfunc measurement needs to be State.") + return density_matrix - # determine if the measurement is a state vector or a density matrix - # TODO: once we separate StateMP and DensityMatrixMP, we can replace this - # line with isinstance checks - dm_measurement = measurements[0].wires or "mixed" in qnode.device.name - dm_func = qml.math.reduce_statevector if not dm_measurement else qml.math.reduce_dm - - # TODO: optimize given the wires by creating a tape with relevant operations - state_built = qnode(*args, **kwargs) - wire_map = {w: i for i, w in enumerate(_get_qnode_wires(qnode))} - indices = [wire_map[w] for w in wires] - density_matrix = dm_func( - state_built, indices=indices, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") + return [tape], processing_fn + + +@reduced_dm.custom_qnode_transform +def _reduced_dm_qnode(self, qnode, targs, tkwargs): + if tkwargs.get("device", False): + raise ValueError( + "Cannot provide a 'device' value directly to the reduced_dm decorator when " + "transforming a QNode." + ) + if tkwargs.get("device_wires", None): + raise ValueError( + "Cannot provide a 'device_wires' value directly to the reduced_dm decorator when " + "transforming a QNode." ) - return density_matrix - return wrapper + tkwargs.setdefault("device", qnode.device) + tkwargs.setdefault("device_wires", qnode.device.wires) + return self.default_qnode_transform(qnode, targs, tkwargs) -def purity(qnode, wires): - r"""Compute the purity of a :class:`~.QNode` returning :func:`~pennylane.state`. +@transform +def purity(tape: QuantumTape, wires, **kwargs) -> (Sequence[QuantumTape], Callable): + r"""Compute the purity of a :class:`~.QuantumTape` returning :func:`~pennylane.state`. .. math:: \gamma = \text{Tr}(\rho^2) @@ -96,12 +119,14 @@ def purity(qnode, wires): the overall state, include all wires in the ``wires`` argument. Args: - qnode (pennylane.QNode): A :class:`.QNode` objeect returning a :func:`~pennylane.state`. + tape (pennylane.tape.QuantumTape): A :class:`.QuantumTape` objeect returning a :func:`~pennylane.state`. wires (Sequence(int)): List of wires in the considered subsystem. Returns: - function: A function that computes the purity of the wrapped circuit and accepts the same - arguments. + pennylane.QNode or qfunc or tuple[List[.QuantumTape], Callable]: If a QNode + is passed, it returns a QNode with the transform added to its transform program. + If a tape is passed, returns a tuple containing a list of quantum tapes to be + evaluated, and a function to be applied to these tape executions. **Example** @@ -131,49 +156,70 @@ def circuit(x): .. seealso:: :func:`pennylane.math.purity` """ + # device_wires is provided by the custom QNode transform + all_wires = kwargs.get("device_wires", tape.wires) + wire_map = {w: i for i, w in enumerate(all_wires)} + indices = [wire_map[w] for w in wires] + + # Check measurement + measurements = tape.measurements + if len(measurements) != 1 or not isinstance(measurements[0], StateMP): + raise ValueError("The qfunc return type needs to be a state.") + + def processing_fn(res): + # device is provided by the custom QNode transform + device = kwargs.get("device", None) + c_dtype = device.C_DTYPE if device else "complex128" + + # determine the density matrix + density_matrix = ( + res[0] + if isinstance(measurements[0], DensityMatrixMP) or isinstance(device, DefaultMixed) + else qml.math.dm_from_state_vector(res[0], c_dtype=c_dtype) + ) - def wrapper(*args, **kwargs): - # Construct tape - qnode.construct(args, kwargs) - - # Check measurement - measurements = qnode.tape.measurements - if len(measurements) != 1 or not isinstance(measurements[0], StateMP): - raise ValueError("The qfunc return type needs to be a state.") - - # determine if the measurement is a state vector or a density matrix - # TODO: once we separate StateMP and DensityMatrixMP, we can replace this - # line with isinstance checks - dm_measurement = measurements[0].wires or "mixed" in qnode.device.name + return qml.math.purity(density_matrix, indices, c_dtype=c_dtype) - state_built = qnode(*args, **kwargs) + return [tape], processing_fn - if not dm_measurement: - state_built = qml.math.dm_from_state_vector(state_built) - wire_map = {w: i for i, w in enumerate(_get_qnode_wires(qnode))} - indices = [wire_map[w] for w in wires] - return qml.math.purity( - state_built, indices, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") +@purity.custom_qnode_transform +def _purity_qnode(self, qnode, targs, tkwargs): + if tkwargs.get("device", False): + raise ValueError( + "Cannot provide a 'device' value directly to the purity decorator when " + "transforming a QNode." + ) + if tkwargs.get("device_wires", None): + raise ValueError( + "Cannot provide a 'device_wires' value directly to the purity decorator when " + "transforming a QNode." ) - return wrapper + tkwargs.setdefault("device", qnode.device) + tkwargs.setdefault("device_wires", qnode.device.wires) + return self.default_qnode_transform(qnode, targs, tkwargs) -def vn_entropy(qnode, wires, base=None): - r"""Compute the Von Neumann entropy from a :class:`.QNode` returning a :func:`~pennylane.state`. +@transform +def vn_entropy( + tape: QuantumTape, wires: Sequence[int], base: float = None, **kwargs +) -> (Sequence[QuantumTape], Callable): + r"""Compute the Von Neumann entropy from a :class:`.QuantumTape` returning a :func:`~pennylane.state`. .. math:: S( \rho ) = -\text{Tr}( \rho \log ( \rho )) Args: - qnode (tensor_like): A :class:`.QNode` returning a :func:`~pennylane.state`. + tape (.QuantumTape): A :class:`.QuantumTape` returning a :func:`~pennylane.state`. wires (Sequence(int)): List of wires in the considered subsystem. base (float): Base for the logarithm, default is None the natural logarithm is used in this case. Returns: - function: A function that computes the Von Neumann entropy of the considered subsystem - for the wrapped circuit and accepts the same arguments. + pennylane.QNode or qfunc or tuple[List[.QuantumTape], Callable]: If a QNode + is passed, it returns a QNode with the transform added to its transform program. + If a tape is passed, returns a tuple containing a list of quantum tapes to be + evaluated, and a function to be applied to these tape executions. **Example** @@ -188,58 +234,72 @@ def circuit(x): return qml.state() >>> vn_entropy(circuit, wires=[0])(np.pi/2) - 0.6931472 + 0.6931471805599453 The function is differentiable with backpropagation for all interfaces, e.g.: >>> param = np.array(np.pi/4, requires_grad=True) >>> qml.grad(vn_entropy(circuit, wires=[0]))(param) - 0.6232252401402305 + tensor(0.62322524, requires_grad=True) .. seealso:: :func:`pennylane.math.vn_entropy` and :func:`pennylane.vn_entropy` """ + # device_wires is provided by the custom QNode transform + all_wires = kwargs.get("device_wires", tape.wires) + wire_map = {w: i for i, w in enumerate(all_wires)} + indices = [wire_map[w] for w in wires] - def wrapper(*args, **kwargs): - # If pure state directly return 0. - qnode.construct(args, kwargs) - qnode_wires = _get_qnode_wires(qnode) - wire_map = {w: i for i, w in enumerate(qnode_wires)} - indices = [wire_map[w] for w in wires] - if len(wires) == len(qnode_wires): - measurements = qnode.tape.measurements - if len(measurements) != 1 or not isinstance(measurements[0], StateMP): - raise ValueError("The qfunc return type needs to be a state.") - - # determine if the measurement is a state vector or a density matrix - # TODO: once we separate StateMP and DensityMatrixMP, we can replace this - # line with isinstance checks - dm_measurement = measurements[0].wires or "mixed" in qnode.device.name - - if not dm_measurement: - # if state vector, the entropy is 0 + measurements = tape.measurements + if len(measurements) != 1 or not isinstance(measurements[0], StateMP): + raise ValueError("The qfunc return type needs to be a state.") + + def processing_fn(res): + # device is provided by the custom QNode transform + device = kwargs.get("device", None) + c_dtype = device.C_DTYPE if device else "complex128" + + # determine if the measurement is a state vector or a density matrix + if not isinstance(measurements[0], DensityMatrixMP) and not isinstance( + device, DefaultMixed + ): # Compute entropy from state vector + if len(wires) == len(all_wires): + # The subsystem has all wires, so the entropy is 0 return 0.0 - density_matrix = qnode(*args, **kwargs) - entropy = qml.math.vn_entropy( - density_matrix, - indices, - base, - c_dtype=getattr(qnode.device, "C_DTYPE", "complex128"), - ) + density_matrix = qml.math.dm_from_state_vector(res[0], c_dtype=c_dtype) + entropy = qml.math.vn_entropy(density_matrix, indices, base, c_dtype=c_dtype) return entropy - density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode_wires) - density_matrix = density_matrix_qnode(*args, **kwargs) - entropy = qml.math.vn_entropy( - density_matrix, indices, base, c_dtype=getattr(qnode.device, "C_DTYPE", "complex128") - ) + # Compute entropy from density matrix + entropy = qml.math.vn_entropy(res[0], indices, base, c_dtype) return entropy - return wrapper + return [tape], processing_fn + + +@vn_entropy.custom_qnode_transform +def _vn_entropy_qnode(self, qnode, targs, tkwargs): + if tkwargs.get("device", False): + raise ValueError( + "Cannot provide a 'device' value directly to the vn_entropy decorator when " + "transforming a QNode." + ) + if tkwargs.get("device_wires", None): + raise ValueError( + "Cannot provide a 'device_wires' value directly to the vn_entropy decorator when " + "transforming a QNode." + ) + tkwargs.setdefault("device", qnode.device) + tkwargs.setdefault("device_wires", qnode.device.wires) + return self.default_qnode_transform(qnode, targs, tkwargs) -def mutual_info(qnode, wires0, wires1, base=None): - r"""Compute the mutual information from a :class:`.QNode` returning a :func:`~pennylane.state`: + +@transform +def mutual_info( + tape: QuantumTape, wires0: Sequence[int], wires1: Sequence[int], base: float = None, **kwargs +) -> (Sequence[QuantumTape], Callable): + r"""Compute the mutual information from a :class:`.QuantumTape` returning a :func:`~pennylane.state`: .. math:: @@ -258,8 +318,10 @@ def mutual_info(qnode, wires0, wires1, base=None): base (float): Base for the logarithm. If None, the natural logarithm is used. Returns: - function: A function that computes the mutual information from the output state - of the QNode and accepts the same arguments. + pennylane.QNode or qfunc or tuple[List[.QuantumTape], Callable]: If a QNode + is passed, it returns a QNode with the transform added to its transform program. + If a tape is passed, returns a tuple containing a list of quantum tapes to be + evaluated, and a function to be applied to these tape executions. **Example** @@ -282,26 +344,55 @@ def circuit(x): >>> mutual_info_circuit(x) 0.3325090393262875 >>> qml.grad(mutual_info_circuit)(np.array(0.4, requires_grad=True)) - 1.2430067731198946 + tensor(1.24300677, requires_grad=True) .. seealso:: :func:`~.qinfo.vn_entropy`, :func:`pennylane.math.mutual_info` and :func:`pennylane.mutual_info` """ - - def wrapper(*args, **kwargs): - qnode_wires = ( - qnode.device.wires - if isinstance(qnode.device, qml.Device) - else qml.tape.make_qscript(qnode.func)(*args, **kwargs).wires + # device_wires is provided by the custom QNode transform + all_wires = kwargs.get("device_wires", tape.wires) + wire_map = {w: i for i, w in enumerate(all_wires)} + indices0 = [wire_map[w] for w in wires0] + indices1 = [wire_map[w] for w in wires1] + + # Check measurement + measurements = tape.measurements + if len(measurements) != 1 or not isinstance(measurements[0], StateMP): + raise ValueError("The qfunc return type needs to be a state.") + + def processing_fn(res): + # device is provided by the custom QNode transform + device = kwargs.get("device", None) + c_dtype = device.C_DTYPE if device else "complex128" + + density_matrix = ( + res[0] + if isinstance(measurements[0], DensityMatrixMP) or isinstance(device, DefaultMixed) + else qml.math.dm_from_state_vector(res[0], c_dtype=c_dtype) + ) + entropy = qml.math.mutual_info( + density_matrix, indices0, indices1, base=base, c_dtype=c_dtype ) - wire_map = {w: i for i, w in enumerate(qnode_wires)} - indices0 = [wire_map[w] for w in wires0] - indices1 = [wire_map[w] for w in wires1] - density_matrix_qnode = qml.qinfo.reduced_dm(qnode, qnode_wires) - density_matrix = density_matrix_qnode(*args, **kwargs) - entropy = qml.math.mutual_info(density_matrix, indices0, indices1, base=base) return entropy - return wrapper + return [tape], processing_fn + + +@mutual_info.custom_qnode_transform +def _mutual_info_qnode(self, qnode, targs, tkwargs): + if tkwargs.get("device", False): + raise ValueError( + "Cannot provide a 'device' value directly to the mutual_info decorator when " + "transforming a QNode." + ) + if tkwargs.get("device_wires", None): + raise ValueError( + "Cannot provide a 'device_wires' value directly to the mutual_info decorator when " + "transforming a QNode." + ) + + tkwargs.setdefault("device", qnode.device) + tkwargs.setdefault("device_wires", qnode.device.wires) + return self.default_qnode_transform(qnode, targs, tkwargs) # TODO: create qml.math.jacobian and replace it here @@ -640,9 +731,7 @@ def circ(params): """ - if qnode.device.shots and isinstance( - qnode.device, (DefaultQubit, qml.devices.experimental.Device) - ): + if qnode.device.shots is not None and isinstance(qnode.device, DefaultQubit): def wrapper(*args0, **kwargs0): return 4 * metric_tensor(qnode, *args, **kwargs)(*args0, **kwargs0) From 872323848b7ef8691442486e9f50bf22d6b90e95 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 16:00:08 -0400 Subject: [PATCH 52/78] add back DQ2 support --- pennylane/qinfo/transforms.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pennylane/qinfo/transforms.py b/pennylane/qinfo/transforms.py index a737eecb5e1..d3a8d2e1d81 100644 --- a/pennylane/qinfo/transforms.py +++ b/pennylane/qinfo/transforms.py @@ -71,7 +71,7 @@ def circuit(x): def processing_fn(res): # device is provided by the custom QNode transform device = kwargs.get("device", None) - c_dtype = device.C_DTYPE if device else "complex128" + c_dtype = getattr(device, "C_DTYPE", "complex128") # determine the density matrix dm_func = ( @@ -169,7 +169,7 @@ def circuit(x): def processing_fn(res): # device is provided by the custom QNode transform device = kwargs.get("device", None) - c_dtype = device.C_DTYPE if device else "complex128" + c_dtype = getattr(device, "C_DTYPE", "complex128") # determine the density matrix density_matrix = ( @@ -256,7 +256,7 @@ def circuit(x): def processing_fn(res): # device is provided by the custom QNode transform device = kwargs.get("device", None) - c_dtype = device.C_DTYPE if device else "complex128" + c_dtype = getattr(device, "C_DTYPE", "complex128") # determine if the measurement is a state vector or a density matrix if not isinstance(measurements[0], DensityMatrixMP) and not isinstance( @@ -362,7 +362,7 @@ def circuit(x): def processing_fn(res): # device is provided by the custom QNode transform device = kwargs.get("device", None) - c_dtype = device.C_DTYPE if device else "complex128" + c_dtype = getattr(device, "C_DTYPE", "complex128") density_matrix = ( res[0] @@ -731,7 +731,9 @@ def circ(params): """ - if qnode.device.shots is not None and isinstance(qnode.device, DefaultQubit): + if qnode.device.shots and isinstance( + qnode.device, (DefaultQubit, qml.devices.experimental.DefaultQubit2) + ): def wrapper(*args0, **kwargs0): return 4 * metric_tensor(qnode, *args, **kwargs)(*args0, **kwargs0) From 4a92d44c1a4ceb432f6ebcc85d50ab368668d3f4 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 16:26:39 -0400 Subject: [PATCH 53/78] clean up tests to what they used to be with latest changes --- tests/measurements/test_classical_shadow.py | 4 ---- tests/measurements/test_measurements.py | 3 --- tests/measurements/test_mutual_info.py | 2 -- tests/measurements/test_probs.py | 1 - tests/measurements/test_sample.py | 1 - tests/measurements/test_state.py | 13 ------------- tests/measurements/test_vn_entropy.py | 2 -- tests/qinfo/test_fidelity.py | 2 -- tests/qinfo/test_trace_distance.py | 1 - tests/test_return_types_qnode.py | 1 - tests/transforms/test_hamiltonian_expand.py | 8 ++++++-- 11 files changed, 6 insertions(+), 32 deletions(-) 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..896717834b6 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,7 +560,6 @@ 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.""" 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 bf3b21b71e5..a07785a691d 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -226,7 +226,6 @@ 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): @@ -276,7 +275,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""" @@ -293,7 +291,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""" @@ -339,7 +336,6 @@ def func(): 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): @@ -559,7 +555,6 @@ 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)]) @@ -644,7 +639,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): @@ -683,7 +677,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""" @@ -721,7 +714,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""" @@ -763,7 +755,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 @@ -814,7 +805,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.""" @@ -901,7 +891,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]) ) @@ -979,7 +968,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""" @@ -1007,7 +995,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/qinfo/test_fidelity.py b/tests/qinfo/test_fidelity.py index d685d39e45c..90c59386d00 100644 --- a/tests/qinfo/test_fidelity.py +++ b/tests/qinfo/test_fidelity.py @@ -101,7 +101,6 @@ def circuit0(x): @qml.qnode(dev) def circuit1(): - qml.Identity(0) return qml.state() fid = qml.qinfo.fidelity(circuit0, circuit1, wires0=[0], wires1=[0])((np.pi)) @@ -114,7 +113,6 @@ def test_fidelity_qnodes_state_rx(self, device): @qml.qnode(dev) def circuit0(): - qml.Identity(0) return qml.state() @qml.qnode(dev) diff --git a/tests/qinfo/test_trace_distance.py b/tests/qinfo/test_trace_distance.py index 280b774f000..892000a9737 100644 --- a/tests/qinfo/test_trace_distance.py +++ b/tests/qinfo/test_trace_distance.py @@ -71,7 +71,6 @@ def circuit0(x): @qml.qnode(dev) def circuit1(): - qml.Identity(0) return qml.state() td = qml.qinfo.trace_distance(circuit0, circuit1, wires0=[0], wires1=[0])(np.pi, None) diff --git a/tests/test_return_types_qnode.py b/tests/test_return_types_qnode.py index f41d76c6d8d..3074c3fa7a5 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -37,7 +37,6 @@ def qutrit_ansatz(x): class TestIntegrationSingleReturn: """Test that single measurements return behavior does not change.""" - @pytest.mark.xfail(reason="until DQ2 port") @pytest.mark.parametrize("wires", test_wires) def test_state_default(self, wires): """Return state with default.qubit.""" diff --git a/tests/transforms/test_hamiltonian_expand.py b/tests/transforms/test_hamiltonian_expand.py index 7763bd4d257..688d231f4f5 100644 --- a/tests/transforms/test_hamiltonian_expand.py +++ b/tests/transforms/test_hamiltonian_expand.py @@ -295,8 +295,6 @@ def test_hamiltonian_dif_tensorflow(self): with AnnotatedQueue() as s_tape1: qml.PauliX(0) - for i in range(4): - qml.Identity(i) S1 = qml.s_prod(1.5, qml.prod(qml.PauliZ(0), qml.PauliZ(1))) qml.expval(S1) qml.expval(S1) @@ -407,6 +405,9 @@ 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(qscript) + assert len(processed) == 1 + qscript = processed[0] tapes, fn = sum_expand(qscript) results = dev.execute(tapes) expval = fn(results) @@ -417,6 +418,9 @@ 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(qscript) + assert len(processed) == 1 + qscript = processed[0] tapes, fn = sum_expand(qscript, group=False) results = dev.execute(tapes) expval = fn(results) From c6eb716a4a49efb45ab3d90d38ae1e53be1e32c1 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 11 Sep 2023 17:10:26 -0400 Subject: [PATCH 54/78] fix more tests with latest changes to master --- pennylane/tape/qscript.py | 6 ++---- tests/qnn/conftest.py | 4 ++-- tests/tape/test_qscript.py | 11 +++++------ tests/tape/test_tape.py | 13 +++++-------- .../test_mottonen_state_prep.py | 4 ++-- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/pennylane/tape/qscript.py b/pennylane/tape/qscript.py index 113880bb006..7112357322f 100644 --- a/pennylane/tape/qscript.py +++ b/pennylane/tape/qscript.py @@ -793,11 +793,9 @@ def shape(self, device): if isinstance(device, qml.devices.experimental.Device): # MP.shape (called below) takes 2 arguments: `device` and `shots`. # With the new device interface, shots are stored on tapes rather than the device - # As well, MP.shape needs the device largely to see the device wires, and this is - # also stored on tapes in the new device interface. TODO: refactor MP.shape to accept - # `wires` instead of device (not currently done because probs.shape uses device.cutoff) + # TODO: refactor MP.shape to accept `wires` instead of device (not currently done + # because probs.shape uses device.cutoff) shots = self.shots - device = self else: shots = ( Shots(device._raw_shot_sequence) diff --git a/tests/qnn/conftest.py b/tests/qnn/conftest.py index 8fb292a10ac..858a5819c26 100644 --- a/tests/qnn/conftest.py +++ b/tests/qnn/conftest.py @@ -24,7 +24,7 @@ def get_circuit(n_qubits, output_dim, interface): """Fixture for getting a sample quantum circuit with a controllable qubit number and output dimension. Returns both the circuit and the shape of the weights.""" - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), @@ -60,7 +60,7 @@ def get_circuit_dm(n_qubits, output_dim, interface): dimension for density matrix return type. Returns both the circuit and the shape of the weights. """ - dev = qml.device("default.qubit", wires=n_qubits) + dev = qml.device("default.qubit.legacy", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), diff --git a/tests/tape/test_qscript.py b/tests/tape/test_qscript.py index 1297f1a8534..9e5dbca64bc 100644 --- a/tests/tape/test_qscript.py +++ b/tests/tape/test_qscript.py @@ -903,16 +903,13 @@ def test_diagonalizing_gates_not_queued(self): (qml.var(qml.PauliZ(0)), ()), (qml.probs(wires=[0]), (2,)), (qml.probs(wires=[0, 1]), (4,)), - (qml.state(), (2,)), + (qml.state(), (8,)), # Assumes 3-qubit device (qml.density_matrix(wires=[0, 1]), (4, 4)), ( qml.sample(qml.PauliZ(0)), None, ), # Shape is None because the expected shape is in the test case - ( - qml.sample(wires=[0, 1, 2]), - None, - ), # Shape is None because the expected shape is in the test case + (qml.sample(), None), # Shape is None because the expected shape is in the test case (qml.mutual_info(wires0=[0], wires1=[1]), ()), (qml.vn_entropy(wires=[0, 1]), ()), ] @@ -1290,7 +1287,9 @@ def test_multi_measure_sample_wires_shot_vector(self): ops = [qml.RY(0.3, 0), qml.RX(0.2, 0)] qs = QuantumScript(ops, [qml.sample()] * num_samples, shots=shots) - expected = tuple(tuple(() if s == 1 else (s,) for _ in range(num_samples)) for s in shots) + expected = tuple( + tuple((3,) if s == 1 else (s, 3) for _ in range(num_samples)) for s in shots + ) res = qs.shape(dev) assert res == expected diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index 770a896733e..180c7d5a4ca 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -1813,16 +1813,13 @@ def cost(tape, dev): (qml.var(qml.PauliZ(0)), ()), (qml.probs(wires=[0]), (2,)), (qml.probs(wires=[0, 1]), (4,)), - (qml.state(), (2,)), + (qml.state(), (8,)), # Assumes 3-qubit device (qml.density_matrix(wires=[0, 1]), (4, 4)), ( qml.sample(qml.PauliZ(0)), None, ), # Shape is None because the expected shape is in the test case - ( - qml.sample(wires=[0, 1, 2]), - None, - ), # Shape is None because the expected shape is in the test case + (qml.sample(), None), # Shape is None because the expected shape is in the test case ] multi_measurements = [ @@ -2227,7 +2224,7 @@ def circuit(a, b): result = circuit(0.3, 0.2) # Double-check the domain of the QNode output - assert np.issubdtype(result[0].dtype, float) # pylint:disable=unsubscriptable-object + assert np.issubdtype(result[0].dtype, float) assert circuit.qtape.numeric_type is float @pytest.mark.autograd @@ -2254,8 +2251,8 @@ def circuit(a, b): result = circuit(0, 3) assert isinstance(result, tuple) assert len(result) == 2 - assert result[0].dtype == float # pylint:disable=no-member - assert result[1].dtype == int # pylint:disable=no-member + assert result[0].dtype == float + assert result[1].dtype == int assert circuit.qtape.numeric_type == (float, int) 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 16fa2273e9e..f7ac7bb3844 100644 --- a/tests/templates/test_state_preparations/test_mottonen_state_prep.py +++ b/tests/templates/test_state_preparations/test_mottonen_state_prep.py @@ -125,7 +125,7 @@ class TestDecomposition: def test_state_preparation_fidelity(self, tol, state_vector, wires, target_state): """Tests that the template produces correct states with high fidelity.""" - @qml.qnode(qml.device("default.qubit")) + @qml.qnode(qml.device("default.qubit", wires=3)) def circuit(): qml.MottonenStatePreparation(state_vector, wires) return ( @@ -214,7 +214,7 @@ def test_state_preparation_probability_distribution( ): """Tests that the template produces states with correct probability distribution.""" - @qml.qnode(qml.device("default.qubit")) + @qml.qnode(qml.device("default.qubit", wires=3)) def circuit(): qml.MottonenStatePreparation(state_vector, wires) return ( From b2615002e11fb2115bec4fe526d76bbe58d47a92 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 10:02:58 -0400 Subject: [PATCH 55/78] fix other template tests --- tests/templates/test_embeddings/test_basis.py | 3 +-- tests/templates/test_layers/test_random.py | 15 ++++++++------- .../test_basis_state_prep.py | 15 ++++++++------- .../test_subroutines/test_basis_rotation.py | 2 +- tests/templates/test_subroutines/test_kupccgsd.py | 15 ++++++++------- tests/templates/test_subroutines/test_uccsd.py | 15 ++++++++------- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tests/templates/test_embeddings/test_basis.py b/tests/templates/test_embeddings/test_basis.py index 5eb16f3d3b3..158448338bc 100644 --- a/tests/templates/test_embeddings/test_basis.py +++ b/tests/templates/test_embeddings/test_basis.py @@ -237,8 +237,7 @@ def test_jax_jit(self, tol): features = jnp.array([0, 1, 0]) - # use legacy device until qml.state is fixed - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_layers/test_random.py b/tests/templates/test_layers/test_random.py index b634d8ab7b9..37014185720 100644 --- a/tests/templates/test_layers/test_random.py +++ b/tests/templates/test_layers/test_random.py @@ -130,23 +130,24 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = np.random.random(size=(1, 3)) - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @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_state_preparations/test_basis_state_prep.py b/tests/templates/test_state_preparations/test_basis_state_prep.py index 7b66b11b0d1..b63b01a33f7 100644 --- a/tests/templates/test_state_preparations/test_basis_state_prep.py +++ b/tests/templates/test_state_preparations/test_basis_state_prep.py @@ -134,23 +134,24 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" basis_state = [0, 1, 0] - dev = qml.device("default.qubit.legacy", wires=3) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k"]) + dev = qml.device("default.qubit", wires=3) + dev2 = qml.device("default.qubit", wires=["z", "a", "k"]) @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_subroutines/test_basis_rotation.py b/tests/templates/test_subroutines/test_basis_rotation.py index 2203196ec33..f969e001ba7 100644 --- a/tests/templates/test_subroutines/test_basis_rotation.py +++ b/tests/templates/test_subroutines/test_basis_rotation.py @@ -459,7 +459,7 @@ def test_tf(self, tol): ] ) - dev = qml.device("default.qubit.legacy", wires=3) + dev = qml.device("default.qubit", wires=3) circuit = qml.QNode(circuit_template, dev) circuit2 = qml.QNode(circuit_decomposed, dev) diff --git a/tests/templates/test_subroutines/test_kupccgsd.py b/tests/templates/test_subroutines/test_kupccgsd.py index 3a8786876c1..4a1801985ae 100644 --- a/tests/templates/test_subroutines/test_kupccgsd.py +++ b/tests/templates/test_subroutines/test_kupccgsd.py @@ -125,8 +125,8 @@ def test_custom_wire_labels(self, tol): weights = np.random.random(size=(1, 6)) - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -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"), diff --git a/tests/templates/test_subroutines/test_uccsd.py b/tests/templates/test_subroutines/test_uccsd.py index e9bbca83147..22ed28965b3 100644 --- a/tests/templates/test_subroutines/test_uccsd.py +++ b/tests/templates/test_subroutines/test_uccsd.py @@ -150,8 +150,8 @@ def test_custom_wire_labels(self, tol): """Test that template can deal with non-numeric, nonconsecutive wire labels.""" weights = [0.1, 0.2] - dev = qml.device("default.qubit.legacy", wires=4) - dev2 = qml.device("default.qubit.legacy", wires=["z", "a", "k", "e"]) + dev = qml.device("default.qubit", wires=4) + dev2 = qml.device("default.qubit", wires=["z", "a", "k", "e"]) @qml.qnode(dev) def circuit(): @@ -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: From 32130914ab873c266f70627ce9c80a7a18d4a448 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 10:36:31 -0400 Subject: [PATCH 56/78] copy return types test for DQ2 --- tests/test_return_types_dq2.py | 1266 ++++++++++++++++++++++++++++++ tests/test_return_types_qnode.py | 21 - 2 files changed, 1266 insertions(+), 21 deletions(-) create mode 100644 tests/test_return_types_dq2.py diff --git a/tests/test_return_types_dq2.py b/tests/test_return_types_dq2.py new file mode 100644 index 00000000000..dee3cc4d549 --- /dev/null +++ b/tests/test_return_types_dq2.py @@ -0,0 +1,1266 @@ +# 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]]) + @pytest.mark.xfail + 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 3074c3fa7a5..5bd73f808d1 100644 --- a/tests/test_return_types_qnode.py +++ b/tests/test_return_types_qnode.py @@ -1347,27 +1347,6 @@ def circuit(x): assert isinstance(t, (np.ndarray, np.float64)) assert t.shape == () - @pytest.mark.parametrize("device", devices) - def test_array_multiple(self, device): - """Return PennyLane array of multiple measurements""" - if device == "default.qutrit": - pytest.skip("Non-commuting observables don't work correctly for qutrits yet.") - - dev = qml.device(device, wires=2) - func = qubit_ansatz if device != "default.qutrit" else qutrit_ansatz - obs = qml.PauliZ(1) if device != "default.qutrit" else qml.GellMann(1, 3) - - def circuit(x): - func(x) - return qml.numpy.array([qml.expval(obs), qml.probs(wires=[0, 1])]) - - qnode = qml.QNode(circuit, dev, diff_method=None) - res = qnode(0.5) - - assert isinstance(res, qml.numpy.ndarray) - assert res[0].shape == () - assert res[1].shape == (4,) if device != "default.qutrit" else (9,) - @pytest.mark.parametrize("device", devices) @pytest.mark.parametrize("comp_basis_sampling", [qml.sample(), qml.counts()]) def test_sample_counts_no_obs(self, device, comp_basis_sampling): From c45997eb3c8b4016391151b7c8b87fd84354fdce Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 11:13:50 -0400 Subject: [PATCH 57/78] fix preprocess changes --- tests/measurements/test_measurements.py | 3 ++- tests/measurements/test_state.py | 3 ++- tests/templates/test_subroutines/test_qpe.py | 8 ++++---- tests/transforms/test_hamiltonian_expand.py | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/measurements/test_measurements.py b/tests/measurements/test_measurements.py index 896717834b6..945ace9dd5a 100644 --- a/tests/measurements/test_measurements.py +++ b/tests/measurements/test_measurements.py @@ -565,7 +565,8 @@ def test_custom_measurement(self): 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_state.py b/tests/measurements/test_state.py index a07785a691d..619eaa1b158 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -307,7 +307,8 @@ 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()) diff --git a/tests/templates/test_subroutines/test_qpe.py b/tests/templates/test_subroutines/test_qpe.py index 06354012851..8037ae9c7b3 100644 --- a/tests/templates/test_subroutines/test_qpe.py +++ b/tests/templates/test_subroutines/test_qpe.py @@ -99,7 +99,7 @@ def test_phase_estimated(self, phase): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tapes, _, _ = dev.preprocess(tape) + tapes, _ = dev.preprocess()[0]([tape]) assert len(tapes) == 1 res = dev.execute(tapes)[0].flatten() @@ -151,7 +151,7 @@ def test_phase_estimated_two_qubit(self): qml.probs(estimation_wires) tape = qml.tape.QuantumScript.from_queue(q) - tapes, _, _ = dev.preprocess(tape) + tapes, _ = dev.preprocess()[0]([tape]) assert len(tapes) == 1 res = dev.execute(tapes)[0].flatten() @@ -197,7 +197,7 @@ def test_phase_estimated_single_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tapes, _, _ = dev.preprocess(tape) + tapes, _ = dev.preprocess()[0]([tape]) res = dev.execute(tapes)[0].flatten() assert len(tapes) == 1 @@ -240,7 +240,7 @@ def test_phase_estimated_ops(self, param): prep=[qml.StatePrep(eig_vec, wires=target_wires)], ) - tapes, _, _ = dev.preprocess(tape) + tapes, _ = dev.preprocess()[0]([tape]) assert len(tapes) == 1 res = dev.execute(tapes)[0].flatten() diff --git a/tests/transforms/test_hamiltonian_expand.py b/tests/transforms/test_hamiltonian_expand.py index 688d231f4f5..28544b6c9c1 100644 --- a/tests/transforms/test_hamiltonian_expand.py +++ b/tests/transforms/test_hamiltonian_expand.py @@ -405,7 +405,7 @@ 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(qscript) + processed, _ = dev.preprocess()[0]([qscript]) assert len(processed) == 1 qscript = processed[0] tapes, fn = sum_expand(qscript) @@ -418,7 +418,7 @@ 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(qscript) + processed, _ = dev.preprocess()[0]([qscript]) assert len(processed) == 1 qscript = processed[0] tapes, fn = sum_expand(qscript, group=False) From d2e0925fa909993c98e66515af80fe7f30d65e2e Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 11:20:41 -0400 Subject: [PATCH 58/78] patch in device wires for jax jit test --- .../test_jax_jit_qnode_default_qubit_2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py b/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py index 3e337200de7..e15e14bc19c 100644 --- a/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py +++ b/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py @@ -1223,6 +1223,8 @@ def test_state(self, dev, diff_method, grad_on_execution, interface, tol): x = jax.numpy.array(0.543) y = jax.numpy.array(-0.654) + if not dev.wires: + dev._wires = qml.wires.Wires([0, 1]) # pylint:disable=protected-access @qnode( dev, diff_method=diff_method, interface=interface, grad_on_execution=grad_on_execution @@ -1235,7 +1237,7 @@ def circuit(x, y): def cost_fn(x, y): res = circuit(x, y) - assert res.dtype is np.dtype("complex128") # pylint:disable=no-member + assert res.dtype is np.dtype("complex128") probs = jax.numpy.abs(res) ** 2 return probs[0] + probs[2] From c49fa53d0db00c262d0043f19ff156d0a2c07498 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 12:21:37 -0400 Subject: [PATCH 59/78] fix drawer usage of DQ2 preprocess --- pennylane/drawer/draw.py | 7 +++++-- tests/test_return_types_dq2.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pennylane/drawer/draw.py b/pennylane/drawer/draw.py index 379916b0886..560b6e4df5b 100644 --- a/pennylane/drawer/draw.py +++ b/pennylane/drawer/draw.py @@ -244,7 +244,8 @@ def wrapper(*args, **kwargs): qnode.device, qml.devices.experimental.Device ): qnode.construct(args, kwargs) - tapes = qnode.device.preprocess(qnode.tape) + program, _ = qnode.device.preprocess() + tapes = program([qnode.tape]) _wire_order = wire_order or qnode.tape.wires else: original_expansion_strategy = getattr(qnode, "expansion_strategy", None) @@ -546,7 +547,9 @@ def wrapper(*args, **kwargs_qnode): qnode.device, qml.devices.experimental.Device ): qnode.construct(args, kwargs) - tape = qnode.device.preprocess(qnode.tape)[0][0] + program, _ = qnode.device.preprocess() + tapes, _ = program([qnode.tape]) + tape = tapes[0] _wire_order = wire_order or qnode.tape.wires else: original_expansion_strategy = getattr(qnode, "expansion_strategy", None) diff --git a/tests/test_return_types_dq2.py b/tests/test_return_types_dq2.py index dee3cc4d549..f6f1a425b35 100644 --- a/tests/test_return_types_dq2.py +++ b/tests/test_return_types_dq2.py @@ -1250,7 +1250,7 @@ def test_entropy_no_custom_wires(self): tape = qml.tape.QuantumScript.from_queue(q) res = qml.execute(tapes=[tape], device=dev, gradient_fn=None) - assert res == [0] + assert res == (0,) def test_custom_wire_labels_error(self): """Tests that an error is raised when mutual information is measured @@ -1263,4 +1263,4 @@ def test_custom_wire_labels_error(self): tape = qml.tape.QuantumScript.from_queue(q) res = qml.execute(tapes=[tape], device=dev, gradient_fn=None) - assert res == [0] + assert res == (0,) From 5c9faebf5cf595e7204eb835cfb3e6fb3f4d20af Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 13:11:48 -0400 Subject: [PATCH 60/78] check out amplitude from master --- pennylane/templates/embeddings/amplitude.py | 24 ++++++--------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index a8fe61d7c6a..96009db8d2a 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -18,7 +18,6 @@ import numpy as np import pennylane as qml -from pennylane.operation import AnyWires, StatePrepBase from pennylane.ops import StatePrep from pennylane.wires import Wires @@ -26,7 +25,7 @@ TOLERANCE = 1e-10 -class AmplitudeEmbedding(StatePrepBase): +class AmplitudeEmbedding(StatePrep): r"""Encodes :math:`2^n` features into the amplitude vector of :math:`n` qubits. By setting ``pad_with`` to a real or complex number, ``features`` is automatically padded to dimension @@ -120,29 +119,18 @@ def circuit(f=None): """ - num_wires = AnyWires - grad_method = None - def __init__(self, features, wires, pad_with=None, normalize=False, id=None): + # pylint:disable=bad-super-call wires = Wires(wires) self.pad_with = pad_with self.normalize = normalize features = self._preprocess(features, wires, pad_with, normalize) - super().__init__(features, wires=wires, id=id) - - @property - def num_params(self): - return 1 - - @property - def ndim_params(self): - return (1,) - - def state_vector(self, wire_order=None): - return StatePrep(self.data[0], wires=self.wires).state_vector(wire_order=wire_order) + super(StatePrep, self).__init__(features, wires=wires, id=id) @staticmethod - def compute_decomposition(features, wires): # pylint: disable=arguments-differ + def compute_decomposition( + features, wires + ): # pylint: disable=arguments-differ,arguments-renamed r"""Representation of the operator as a product of other operators. .. math:: O = O_1 O_2 \dots O_n. From 4d8fe20910b7086834a0ebffc7bbb399282332c5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 13:14:38 -0400 Subject: [PATCH 61/78] see if torch qcut issue magically fixed in CI --- tests/transforms/test_qcut.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/transforms/test_qcut.py b/tests/transforms/test_qcut.py index af107ddc140..4438afefc8a 100644 --- a/tests/transforms/test_qcut.py +++ b/tests/transforms/test_qcut.py @@ -4020,9 +4020,7 @@ def test_simple_cut_circuit_torch_trace(self, mocker, use_opt_einsum): import torch - # TODO: this passes with default.qubit locally, but fails on CI - # possibly an architecture-specific issue - dev = qml.device("default.qubit.legacy", wires=2) + dev = qml.device("default.qubit", wires=2) @qml.qnode(dev, interface="torch") def circuit(x): From d99dc18c92f3600923d7e5c6c92b81798d361e23 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 13 Sep 2023 16:40:49 -0400 Subject: [PATCH 62/78] Revert "see if torch qcut issue magically fixed in CI" This reverts commit 4d8fe20910b7086834a0ebffc7bbb399282332c5. --- tests/transforms/test_qcut.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/transforms/test_qcut.py b/tests/transforms/test_qcut.py index 4438afefc8a..af107ddc140 100644 --- a/tests/transforms/test_qcut.py +++ b/tests/transforms/test_qcut.py @@ -4020,7 +4020,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): From e2a6eb74a68d37e9aee873c9c31cebede806164a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 14 Sep 2023 22:36:36 -0400 Subject: [PATCH 63/78] little improvements and coverage --- pennylane/optimize/spsa.py | 12 +++++++----- tests/transforms/test_hamiltonian_expand.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pennylane/optimize/spsa.py b/pennylane/optimize/spsa.py index a8313735640..1f6c08bd516 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) + 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/tests/transforms/test_hamiltonian_expand.py b/tests/transforms/test_hamiltonian_expand.py index 28544b6c9c1..886623740fd 100644 --- a/tests/transforms/test_hamiltonian_expand.py +++ b/tests/transforms/test_hamiltonian_expand.py @@ -414,6 +414,16 @@ def test_sums(self, qscript, output): 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)) + @pytest.mark.parametrize(("qscript", "output"), zip(SUM_QSCRIPTS, SUM_OUTPUTS)) def test_sums_no_grouping(self, qscript, output): """Tests that the sum_expand transform returns the correct value From df680e7d32e0021d0d47a6d8c40af49f85f106f4 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Thu, 14 Sep 2023 23:41:30 -0400 Subject: [PATCH 64/78] don't xfail tests unnecessarily --- tests/test_return_types_dq2.py | 1 - tests/transforms/test_metric_tensor.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_return_types_dq2.py b/tests/test_return_types_dq2.py index f6f1a425b35..3acae93dc59 100644 --- a/tests/test_return_types_dq2.py +++ b/tests/test_return_types_dq2.py @@ -524,7 +524,6 @@ def circuit(x): 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]]) - @pytest.mark.xfail def test_density_matrix(self, shot_vector, wires, device): """Test a density matrix measurement.""" dev = qml.device(device, wires=3, shots=shot_vector) diff --git a/tests/transforms/test_metric_tensor.py b/tests/transforms/test_metric_tensor.py index 2b36fd01d14..1b4c6db5807 100644 --- a/tests/transforms/test_metric_tensor.py +++ b/tests/transforms/test_metric_tensor.py @@ -1747,7 +1747,6 @@ def circuit_multi_block(x, z): assert len(recwarn) == 0 -@pytest.mark.xfail(reason="The new default.qubit does not enforce tape wires") def test_raises_circuit_that_uses_missing_wire(): """Test that an error in the original circuit is reraised properly and not caught. This avoids accidentally catching relevant errors, which can lead to a recursion error.""" @@ -1763,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) From 52f78909279d7cc44b3d52c1b843e398737e66c2 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 15 Sep 2023 12:59:51 -0400 Subject: [PATCH 65/78] fix up some tests after merge --- pennylane/optimize/spsa.py | 2 +- tests/test_debugging.py | 31 ++++++++++++++++--------------- tests/transforms/test_qcut.py | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pennylane/optimize/spsa.py b/pennylane/optimize/spsa.py index 1f6c08bd516..a3a1e5faae8 100644 --- a/pennylane/optimize/spsa.py +++ b/pennylane/optimize/spsa.py @@ -266,7 +266,7 @@ def compute_grad(self, objective_fn, args, kwargs): 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) + 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: diff --git a/tests/test_debugging.py b/tests/test_debugging.py index 9e4e98a9e06..0787be5bf92 100644 --- a/tests/test_debugging.py +++ b/tests/test_debugging.py @@ -54,30 +54,31 @@ 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.""" + if method == "adjoint": + pytest.xfail(reason="New Default Qubit does not yet support Snapshot with adjoint.") 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/transforms/test_qcut.py b/tests/transforms/test_qcut.py index 92d3ec12d8c..d6c87fd4191 100644 --- a/tests/transforms/test_qcut.py +++ b/tests/transforms/test_qcut.py @@ -4638,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, qml.devices.experimental.Device)) + isinstance(devices, (qml.Device, qml.devices.Device)) and imbalance_tolerance is None and num_fragments_probed is None ): From 0b49d18ecd878edd59aa8dfce34bc4d78ee8f24a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 15 Sep 2023 14:43:34 -0400 Subject: [PATCH 66/78] fix unrelated mpl bug --- tests/drawer/test_tape_mpl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drawer/test_tape_mpl.py b/tests/drawer/test_tape_mpl.py index 3571b450ca3..a029aa48d79 100644 --- a/tests/drawer/test_tape_mpl.py +++ b/tests/drawer/test_tape_mpl.py @@ -521,7 +521,7 @@ def test_nested_control_values_bool(self): def check_tape_controlled_qubit_unitary(self, tape): """Checks the control symbols for a tape with some version of a controlled qubit unitary.""" - _, ax = tape_mpl(tape, style=None) # set style to None to use plt.rcParams values + _, ax = tape_mpl(tape, style="rcParams") # use plt.rcParams values layer = 0 # 5 wires -> 4 control, 1 target From 31a10600977156229b10aaaf556a404a40b30da5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 15 Sep 2023 16:05:31 -0400 Subject: [PATCH 67/78] reject backprop with interface=None; fix docs tests --- pennylane/devices/default_qubit.py | 1 + pennylane/qnode.py | 4 +- tests/docs/test_supported_confs.py | 127 +++++++++++++++-------------- 3 files changed, 72 insertions(+), 60 deletions(-) diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py index e908996d879..99736206c42 100644 --- a/pennylane/devices/default_qubit.py +++ b/pennylane/devices/default_qubit.py @@ -177,6 +177,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/qnode.py b/pennylane/qnode.py index cccecc36485..641b1836d16 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/tests/docs/test_supported_confs.py b/tests/docs/test_supported_confs.py index 3d8ffe43861..adc59d396dd 100644 --- a/tests/docs/test_supported_confs.py +++ b/tests/docs/test_supported_confs.py @@ -15,7 +15,7 @@ match the supported configurations in the code. A configuration is specified by: - 1. The quantum device, e.g. "default.qubit.legacy" + 1. The quantum device, e.g. "default.qubit" 2. The interface, e.g. "jax" 3. The differentiation method, e.g. "parameter-shift" 4. The return value of the QNode, e.g. qml.expval() or qml.probs() @@ -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.legacy"] interfaces = [None, "autograd", "jax", "tf", "torch"] diff_interfaces = ["autograd", "jax", "tf", "torch"] shots_list = [None, 100] @@ -113,7 +111,7 @@ def get_qnode(interface, diff_method, return_type, shots, wire_specs): """ device_wires, wire_labels, single_meas_wire, multi_meas_wire = wire_specs - dev = qml.device("default.qubit.legacy", wires=device_wires, shots=shots) + dev = qml.device("default.qubit", wires=device_wires, shots=shots) # pylint: disable=too-many-return-statements @qml.qnode(dev, interface=interface, diff_method=diff_method) @@ -264,9 +262,9 @@ class TestSupportedConfs: @pytest.mark.parametrize("shots", shots_list) @pytest.mark.parametrize("wire_specs", wire_specs_list) def test_all_device(self, interface, return_type, shots, wire_specs): - """Test diff_method=device raises an error for all interfaces for default.qubit.legacy""" + """Test diff_method=device raises an error for all interfaces for default.qubit""" msg = ( - "The default.qubit.legacy device does not provide a native " + "The default.qubit.2 device does not provide a native " "method for computing the jacobian." ) @@ -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.legacy 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\.2 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( From 253e61dbcad4baaee52476ab3f5944ede800eb0a Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Fri, 15 Sep 2023 16:15:39 -0400 Subject: [PATCH 68/78] fix DQ2 backprop validation test --- tests/devices/experimental/test_default_qubit_2.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/devices/experimental/test_default_qubit_2.py b/tests/devices/experimental/test_default_qubit_2.py index 7d78f470aea..ca9747f8628 100644 --- a/tests/devices/experimental/test_default_qubit_2.py +++ b/tests/devices/experimental/test_default_qubit_2.py @@ -352,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 @@ -367,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() From 274c9fa04a1b252259d578f74b911466494a85b9 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Mon, 18 Sep 2023 13:51:00 -0400 Subject: [PATCH 69/78] remove old note on return system --- pennylane/devices/device_api.py | 3 --- 1 file changed, 3 deletions(-) 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:: From 8c10163f7ed73666cf17966b68d7068f2c77b1a5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 12:24:39 -0400 Subject: [PATCH 70/78] skip Snapshot for adjoint execution backwards pass --- pennylane/devices/qubit/adjoint_jacobian.py | 2 ++ tests/test_debugging.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) 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/tests/test_debugging.py b/tests/test_debugging.py index 0787be5bf92..1f95d33e3ee 100644 --- a/tests/test_debugging.py +++ b/tests/test_debugging.py @@ -58,8 +58,6 @@ def circuit(): def test_default_qubit2(self, method): """Test that multiple snapshots are returned correctly on the new state-vector simulator.""" - if method == "adjoint": - pytest.xfail(reason="New Default Qubit does not yet support Snapshot with adjoint.") dev = qml.device("default.qubit") # TODO: add additional QNode test once the new device supports it From 75cc45d8c89ef73d0833e99908a9727b5d84dfd5 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 12:34:58 -0400 Subject: [PATCH 71/78] rename default.qubit.2 to default.qubit --- pennylane/devices/default_qubit.py | 2 +- tests/devices/experimental/test_default_qubit_2.py | 2 +- tests/docs/test_supported_confs.py | 4 ++-- tests/logging/test_logging_autograd.py | 4 ++-- tests/qnn/test_keras.py | 2 +- tests/qnn/test_qnn_torch.py | 2 +- tests/transforms/test_specs.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pennylane/devices/default_qubit.py b/pennylane/devices/default_qubit.py index 99736206c42..d07aad163ca 100644 --- a/pennylane/devices/default_qubit.py +++ b/pennylane/devices/default_qubit.py @@ -142,7 +142,7 @@ def f(x): @property def name(self): """The name of the device.""" - return "default.qubit.2" + return "default.qubit" def __init__(self, wires=None, shots=None, seed="global", max_workers=None) -> None: super().__init__(wires=wires, shots=shots) diff --git a/tests/devices/experimental/test_default_qubit_2.py b/tests/devices/experimental/test_default_qubit_2.py index ca9747f8628..3919aeee127 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(): diff --git a/tests/docs/test_supported_confs.py b/tests/docs/test_supported_confs.py index adc59d396dd..84e38b40822 100644 --- a/tests/docs/test_supported_confs.py +++ b/tests/docs/test_supported_confs.py @@ -264,7 +264,7 @@ class TestSupportedConfs: def test_all_device(self, interface, return_type, shots, wire_specs): """Test diff_method=device raises an error for all interfaces for default.qubit""" msg = ( - "The default.qubit.2 device does not provide a native " + "The default.qubit device does not provide a native " "method for computing the jacobian." ) @@ -277,7 +277,7 @@ def test_none_backprop(self, return_type, wire_specs): """Test interface=None and diff_method=backprop raises an error""" with pytest.raises( QuantumFunctionError, - match=r"Device default\.qubit\.2 does not support backprop with .*gradient_method='backprop'.*interface=None", + match=r"Device default\.qubit does not support backprop with .*gradient_method='backprop'.*interface=None", ): get_qnode(None, "backprop", return_type, None, wire_specs) diff --git a/tests/logging/test_logging_autograd.py b/tests/logging/test_logging_autograd.py index 3e26b51459e..6dcafffb439 100644 --- a/tests/logging/test_logging_autograd.py +++ b/tests/logging/test_logging_autograd.py @@ -88,7 +88,7 @@ def circuit(params): ( "pennylane.interfaces.execution", [ - "device= Date: Tue, 19 Sep 2023 14:54:03 -0400 Subject: [PATCH 72/78] test qnn and hardwareHamiltonian with new device --- tests/pulse/test_hardware_hamiltonian.py | 10 +++++----- tests/qnn/conftest.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/pulse/test_hardware_hamiltonian.py b/tests/pulse/test_hardware_hamiltonian.py index 418d45fb0d0..09933ba2ccf 100644 --- a/tests/pulse/test_hardware_hamiltonian.py +++ b/tests/pulse/test_hardware_hamiltonian.py @@ -641,7 +641,7 @@ def fa(p, t): Ht = drive(amplitude=fa, phase=0, wires=1) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) @@ -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): @@ -683,7 +683,7 @@ def fc(p, t): H2 = drive(amplitude=fc, phase=3 * jnp.pi, wires=4) H3 = drive(amplitude=1.0, phase=0, wires=[3, 0]) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) @@ -726,7 +726,7 @@ def fb(p, t): H_drive = drive(amplitude=fa, phase=fb, wires=1) - dev = qml.device("default.qubit.legacy", wires=wires) + dev = qml.device("default.qubit", wires=wires) ts = jnp.array([0.0, 3.0]) H_obj = sum(qml.PauliZ(i) for i in range(2)) @@ -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/qnn/conftest.py b/tests/qnn/conftest.py index 858a5819c26..8fb292a10ac 100644 --- a/tests/qnn/conftest.py +++ b/tests/qnn/conftest.py @@ -24,7 +24,7 @@ def get_circuit(n_qubits, output_dim, interface): """Fixture for getting a sample quantum circuit with a controllable qubit number and output dimension. Returns both the circuit and the shape of the weights.""" - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), @@ -60,7 +60,7 @@ def get_circuit_dm(n_qubits, output_dim, interface): dimension for density matrix return type. Returns both the circuit and the shape of the weights. """ - dev = qml.device("default.qubit.legacy", wires=n_qubits) + dev = qml.device("default.qubit", wires=n_qubits) weight_shapes = { "w1": (3, n_qubits, 3), "w2": (1,), From 0f23793678cffc9a99986541960be755ac5a52b2 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 14:56:39 -0400 Subject: [PATCH 73/78] add link to changelog entry --- doc/releases/changelog-dev.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index c6d304c535d..122f31da3c6 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 🛠

From 37e5bead81d5b9801e66b1b0dd93c7387a13a027 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 15:42:24 -0400 Subject: [PATCH 74/78] fix state tests to not check custom dtype --- tests/measurements/test_state.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/measurements/test_state.py b/tests/measurements/test_state.py index 6b4724945d3..b24c538c23c 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -338,8 +338,7 @@ def func(): 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 @@ -347,8 +346,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() @@ -357,13 +354,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.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 @@ -371,13 +367,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() From 95ba06c1e0589b5872ae0e4e66255dde97796099 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 15:56:14 -0400 Subject: [PATCH 75/78] more state dtype fixes --- pennylane/measurements/state.py | 2 +- tests/measurements/test_state.py | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) 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/tests/measurements/test_state.py b/tests/measurements/test_state.py index b24c538c23c..ab306b5b01e 100644 --- a/tests/measurements/test_state.py +++ b/tests/measurements/test_state.py @@ -251,20 +251,18 @@ class TestState: """Tests for the state function""" @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""" @@ -589,8 +587,7 @@ class TestDensityMatrix: @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""" @@ -598,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): From 2de5990fa3b30ba1eb46b02ea50d6dbfe15ce84c Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 16:23:48 -0400 Subject: [PATCH 76/78] autoray dispatch to tf.size --- pennylane/math/single_dispatch.py | 1 + 1 file changed, 1 insertion(+) 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 --------------------------------- # From 9142944a0fb358264ac9fb828e8120e996456d83 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Tue, 19 Sep 2023 17:07:34 -0400 Subject: [PATCH 77/78] codecov happiness --- tests/math/test_functions.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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 From 032cd3bacb1d1d265e77ba909a073fc20c6cc4a1 Mon Sep 17 00:00:00 2001 From: Matthew Silverman Date: Wed, 20 Sep 2023 11:34:38 -0400 Subject: [PATCH 78/78] also add to breaking changes --- doc/releases/changelog-dev.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 35005e98107..d4d6d286e9e 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -185,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`.