Пример #1
0
    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)

        def func(x, y):
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.CNOT(wires=[0, 1])
            return 5

        qn = QNode(func, dev)

        with pytest.raises(qml.QuantumFunctionError,
                           match="must return either a single measurement"):
            qn(5, 1)

        def func(x, y):
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), 5

        qn = QNode(func, dev)

        with pytest.raises(qml.QuantumFunctionError,
                           match="must return either a single measurement"):
            qn(5, 1)
Пример #2
0
    def test_best_method(self, monkeypatch):
        """Test that the method for determining the best diff method
        for a given device and interface works correctly"""
        dev = qml.device("default.qubit", wires=1)
        monkeypatch.setitem(dev._capabilities, "passthru_interface",
                            "some_interface")
        monkeypatch.setitem(dev._capabilities, "provides_jacobian", True)

        # device is top priority
        res = QNode.get_best_method(dev, "another_interface")
        assert res == ("device", {}, dev)

        # backprop is next priority
        monkeypatch.setitem(dev._capabilities, "provides_jacobian", False)
        res = QNode.get_best_method(dev, "some_interface")
        assert res == ("backprop", {}, dev)

        # The next fallback is parameter-shift.
        res = QNode.get_best_method(dev, "another_interface")
        assert res == (qml.gradients.param_shift, {}, dev)

        # finally, if both fail, finite differences is the fallback
        def capabilities(cls):
            capabilities = cls._capabilities
            capabilities.update(model="None")
            return capabilities

        monkeypatch.setattr(qml.devices.DefaultQubit, "capabilities",
                            capabilities)
        res = QNode.get_best_method(dev, "another_interface")
        assert res == (qml.gradients.finite_diff, {}, dev)
Пример #3
0
    def test_correct_number_of_executions_torch(self):
        """Test that number of executions are tracked in the torch interface."""
        torch = pytest.importorskip("torch")

        def func():
            qml.Hadamard(wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=2)
        qn = QNode(func, dev, interface="torch")
        for i in range(2):
            qn()

        assert dev.num_executions == 2

        qn2 = QNode(func, dev, interface="torch")
        for i in range(3):
            qn2()

        assert dev.num_executions == 5

        # qubit of different interface
        qn3 = QNode(func, dev, interface="autograd")
        qn3()

        assert dev.num_executions == 6
Пример #4
0
    def test_validate_backprop_method_invalid_device(self):
        """Test that the method for validating the backprop diff method
        tape raises an exception if the device does not support backprop."""
        dev = qml.device("default.gaussian", wires=1)

        with pytest.raises(qml.QuantumFunctionError,
                           match="does not support native computations"):
            QNode._validate_backprop_method(dev, None)
Пример #5
0
    def test_validate_adjoint_invalid_device(self):
        """Test if a ValueError is raised when an invalid device is provided to
        _validate_adjoint_method"""

        dev = qml.device("default.gaussian", wires=1)

        with pytest.raises(ValueError,
                           match="The default.gaussian device does not"):
            QNode._validate_adjoint_method(dev)
Пример #6
0
    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)

        with pytest.warns(
                UserWarning,
                match=
                "Requested adjoint differentiation to be computed with finite shots."
        ):
            QNode._validate_adjoint_method(dev)
Пример #7
0
    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)
        test_interface = "something"

        monkeypatch.setitem(dev._capabilities, "passthru_interface",
                            test_interface)

        with pytest.raises(qml.QuantumFunctionError,
                           match=f"when using the {test_interface}"):
            QNode._validate_backprop_method(dev, None)
Пример #8
0
    def test_qnode_print(self):
        """Test that printing a QNode object yields the right information."""
        dev = qml.device("default.qubit", wires=1)

        def func(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        qn = QNode(func, dev)

        assert (
            qn.__repr__() ==
            "<QNode: wires=1, device='default.qubit.autograd', interface='autograd', diff_method='best'>"
        )
Пример #9
0
    def test_parameter_shift_tape_unknown_model(self, monkeypatch):
        """Test that an unknown model raises an exception"""
        def capabilities(cls):
            capabilities = cls._capabilities
            capabilities.update(model="None")
            return capabilities

        monkeypatch.setattr(qml.devices.DefaultQubit, "capabilities",
                            capabilities)
        dev = qml.device("default.qubit", wires=1)

        with pytest.raises(qml.QuantumFunctionError,
                           match="does not support the parameter-shift rule"):
            QNode._validate_parameter_shift(dev)
Пример #10
0
    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)
        test_interface = "something"

        orig_capabilities = dev.capabilities().copy()
        orig_capabilities["passthru_devices"] = {
            test_interface: "default.gaussian"
        }
        monkeypatch.setattr(dev, "capabilities", lambda: orig_capabilities)

        with pytest.raises(qml.QuantumFunctionError,
                           match=r"when using the \['something'\] interface"):
            QNode._validate_backprop_method(dev, "another_interface")
Пример #11
0
    def test_basic_tape_construction(self, tol):
        """Test that a quantum tape is properly constructed"""
        dev = qml.device("default.qubit", wires=2)

        def func(x, y):
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        qn = QNode(func, dev)

        x = 0.12
        y = 0.54

        res = qn(x, y)

        assert isinstance(qn.qtape, JacobianTape)
        assert len(qn.qtape.operations) == 3
        assert len(qn.qtape.observables) == 1
        assert qn.qtape.num_params == 2

        expected = qn.qtape.execute(dev)
        assert np.allclose(res, expected, atol=tol, rtol=0)

        # when called, a new quantum tape is constructed
        old_tape = qn.qtape
        res2 = qn(x, y)

        assert np.allclose(res, res2, atol=tol, rtol=0)
        assert qn.qtape is not old_tape
Пример #12
0
 def test_parameter_shift_cv_device(self):
     """Test that the _validate_parameter_shift method
     returns the correct gradient transform for cv devices."""
     dev = qml.device("default.gaussian", wires=1)
     gradient_fn = QNode._validate_parameter_shift(dev)
     assert gradient_fn[0] is qml.gradients.param_shift_cv
     assert gradient_fn[1] == {"dev": dev}
Пример #13
0
    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)

        with pytest.raises(
                qml.QuantumFunctionError,
                match="Differentiation method hello not recognized"):
            QNode(dummyfunc, dev, diff_method="hello")
Пример #14
0
    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)

        with pytest.raises(
                qml.QuantumFunctionError,
                match=
                "does not provide a native method for computing the jacobian",
        ):
            QNode._validate_device_method(dev)

        monkeypatch.setitem(dev._capabilities, "provides_jacobian", True)
        method, diff_options, device = QNode._validate_device_method(dev)

        assert method == "device"
        assert device is dev
Пример #15
0
    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)

        with pytest.raises(
                qml.QuantumFunctionError,
                match=
                "Differentiation method 5 must be a gradient transform or a string",
        ):
            QNode(dummyfunc, dev, diff_method=5)
Пример #16
0
    def test_operator_all_wires(self, monkeypatch, tol):
        """Test that an operator that must act on all wires
        does, or raises an error."""
        monkeypatch.setattr(qml.RX, "num_wires", qml.operation.AllWires)

        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=2)
        qnode = QNode(circuit, dev)

        with pytest.raises(qml.QuantumFunctionError,
                           match="Operator RX must act on all wires"):
            qnode(0.5)

        dev = qml.device("default.qubit", wires=1)
        qnode = QNode(circuit, dev)
        assert np.allclose(qnode(0.5), np.cos(0.5), atol=tol, rtol=0)
Пример #17
0
    def test_integration(self):
        """Test if the error of the mitigated result is less than the error of the unmitigated
        result for a circuit with known expectation values"""
        from mitiq.zne.scaling import fold_global
        from mitiq.zne.inference import RichardsonFactory

        noise_strength = 0.05

        dev_noise_free = qml.device("default.mixed", wires=2)
        dev = qml.transforms.insert(qml.AmplitudeDamping, noise_strength)(dev_noise_free)

        n_wires = 2
        n_layers = 2

        shapes = qml.SimplifiedTwoDesign.shape(n_wires, n_layers)
        np.random.seed(0)
        w1, w2 = [np.random.random(s) for s in shapes]

        def circuit(w1, w2):
            qml.SimplifiedTwoDesign(w1, w2, wires=range(2))
            qml.adjoint(qml.SimplifiedTwoDesign)(w1, w2, wires=range(2))
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        exact_qnode = QNode(circuit, dev_noise_free)
        noisy_qnode = QNode(circuit, dev)

        @qml.transforms.mitigate_with_zne([1, 2, 3], fold_global, RichardsonFactory.extrapolate)
        @qnode(dev)
        def mitigated_qnode(w1, w2):
            qml.SimplifiedTwoDesign(w1, w2, wires=range(2))
            qml.adjoint(qml.SimplifiedTwoDesign)(w1, w2, wires=range(2))
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        exact_val = exact_qnode(w1, w2)
        noisy_val = noisy_qnode(w1, w2)
        mitigated_val = mitigated_qnode(w1, w2)

        mitigated_err = np.abs(exact_val - mitigated_val)
        noisy_err = np.abs(exact_val - noisy_val)

        assert np.allclose(exact_val, [1, 1])
        assert all(mitigated_err < noisy_err)
Пример #18
0
    def test_jacobian(self, tol):
        """Test the jacobian computation"""
        dev = qml.device("default.qubit", wires=2)

        def func(x, y):
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.CNOT(wires=[0, 1])
            return qml.probs(wires=0), qml.probs(wires=1)

        qn = QNode(func,
                   dev,
                   diff_method="finite-diff",
                   h=1e-8,
                   approx_order=2)
        assert qn.gradient_kwargs["h"] == 1e-8
        assert qn.gradient_kwargs["approx_order"] == 2

        jac = qn.gradient_fn(qn)(0.45, 0.1)
        assert jac.shape == (2, 2, 2)
Пример #19
0
    def test_correct_number_of_executions_autograd(self):
        """Test that number of executions are tracked in the autograd interface."""
        def func():
            qml.Hadamard(wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=2)
        qn = QNode(func, dev, interface="autograd")

        for i in range(2):
            qn()

        assert dev.num_executions == 2

        qn2 = QNode(func, dev, interface="autograd")
        for i in range(3):
            qn2()

        assert dev.num_executions == 5
Пример #20
0
    def test_invalid_interface(self):
        """Test that an exception is raised for an invalid interface"""
        dev = qml.device("default.qubit", wires=1)
        test_interface = "something"
        expected_error = (
            fr"Unknown interface {test_interface}\. Interface must be "
            r"one of \[None, 'autograd', 'numpy', 'jax', 'JAX', 'torch', 'pytorch', 'tf', 'tensorflow'\]\."
        )

        with pytest.raises(qml.QuantumFunctionError, match=expected_error):
            QNode(dummyfunc, dev, interface="something")
Пример #21
0
    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)

        mock_best = mocker.patch("pennylane.beta.QNode.get_best_method")
        mock_best.return_value = ("best", {}, dev)

        mock_backprop = mocker.patch(
            "pennylane.beta.QNode._validate_backprop_method")
        mock_backprop.return_value = ("backprop", {}, dev)

        mock_device = mocker.patch(
            "pennylane.beta.QNode._validate_device_method")
        mock_device.return_value = ("device", {}, dev)

        qn = QNode(dummyfunc, dev, diff_method="best")
        assert qn.diff_method == "best"
        assert qn.gradient_fn == "best"

        qn = QNode(dummyfunc, dev, diff_method="backprop")
        assert qn.diff_method == "backprop"
        assert qn.gradient_fn == "backprop"
        mock_backprop.assert_called_once()

        qn = QNode(dummyfunc, dev, diff_method="device")
        assert qn.diff_method == "device"
        assert qn.gradient_fn == "device"
        mock_device.assert_called_once()

        qn = QNode(dummyfunc, dev, diff_method="finite-diff")
        assert qn.diff_method == "finite-diff"
        assert qn.gradient_fn is qml.gradients.finite_diff

        qn = QNode(dummyfunc, dev, diff_method="parameter-shift")
        assert qn.diff_method == "parameter-shift"
        assert qn.gradient_fn is qml.gradients.param_shift

        # check that get_best_method was only ever called once
        mock_best.assert_called_once()
Пример #22
0
    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)
        test_interface = "something"
        monkeypatch.setitem(dev._capabilities, "passthru_interface",
                            test_interface)

        method, diff_options, device = QNode._validate_backprop_method(
            dev, "something")

        assert method == "backprop"
        assert device is dev
Пример #23
0
    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)
        test_interface = "something"

        orig_capabilities = dev.capabilities().copy()
        orig_capabilities["passthru_devices"] = {
            test_interface: "default.gaussian"
        }
        monkeypatch.setattr(dev, "capabilities", lambda: orig_capabilities)

        method, diff_options, device = QNode._validate_backprop_method(
            dev, test_interface)

        assert method == "backprop"
        assert isinstance(device, qml.devices.DefaultGaussian)
Пример #24
0
    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)

        def func(x, y):
            global op1, op2, op3, m1, m2
            op1 = qml.RX(x, wires=0)
            op2 = qml.RY(y, wires=1)
            op3 = qml.CNOT(wires=[0, 1])
            m1 = qml.expval(qml.PauliZ(0))
            m2 = qml.expval(qml.PauliX(1))
            return [m1, m2]

        qn = QNode(func, dev)
        qn(5, 1)  # evaluate the QNode
        assert qn.qtape.operations == [op1, op2, op3]
        assert qn.qtape.measurements == [m1, m2]
Пример #25
0
    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)

        def func(x, y):
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.CNOT(wires=[0, 1])
            m = qml.expval(qml.PauliZ(0))
            return qml.expval(qml.PauliX(1)), m

        qn = QNode(func, dev)

        with pytest.raises(
                qml.QuantumFunctionError,
                match=
                "measurements must be returned in the order they are measured",
        ):
            qn(5, 1)
Пример #26
0
    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)

        def circuit(a, shots=0):
            qml.RX(a, wires=shots)
            return qml.sample(qml.PauliZ(wires=0))

        with pytest.warns(
                UserWarning,
                match="The 'shots' argument name is reserved for overriding"):
            circuit = QNode(circuit, dev)

        assert len(circuit(0.8)) == 10
        assert circuit.qtape.operations[0].wires.labels == (0, )

        assert len(circuit(0.8, shots=1)) == 10
        assert circuit.qtape.operations[0].wires.labels == (1, )

        assert len(circuit(0.8, shots=0)) == 10
        assert circuit.qtape.operations[0].wires.labels == (0, )
Пример #27
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."""

        # Todo: use standard creation of qnode below for both asserts once we do not parse args to tensors any more
        dev = qml.device("default.qubit",
                         wires=[qml.numpy.array(0),
                                qml.numpy.array(1)],
                         shots=10)

        def circuit(a, shots):
            qml.RX(a, wires=shots)
            return qml.sample(qml.PauliZ(wires=qml.numpy.array(0)))

        # assert that warning is still raised
        with pytest.warns(
                UserWarning,
                match="The 'shots' argument name is reserved for overriding"):
            circuit = QNode(circuit, dev)

        assert len(circuit(0.8, 1)) == 10
        assert circuit.qtape.operations[0].wires.labels == (1, )

        dev = qml.device("default.qubit", wires=2, shots=10)

        with pytest.warns(
                UserWarning,
                match="The 'shots' argument name is reserved for overriding"):

            @qnode(dev)
            def circuit(a, shots):
                qml.RX(a, wires=shots)
                return qml.sample(qml.PauliZ(wires=0))

        assert len(circuit(0.8, shots=0)) == 10
        assert circuit.qtape.operations[0].wires.labels == (0, )
Пример #28
0
 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)
     gradient_fn = QNode._validate_parameter_shift(dev)
     assert gradient_fn[0] is qml.gradients.param_shift
Пример #29
0
 def test_invalid_device(self):
     """Test that an exception is raised for an invalid device"""
     with pytest.raises(qml.QuantumFunctionError, match="Invalid device"):
         QNode(dummyfunc, None)