Beispiel #1
0
    def construct(self, args, kwargs):
        """New quantum tape construct method, that performs
        the transform on the tape in a define-by-run manner"""

        # the following global variable is defined simply for testing
        # purposes, so that we can easily extract the transformed operations
        # for verification.
        global t_op

        t_op = []

        QNode.construct(self, args, kwargs)

        new_ops = []
        for o in self.qtape.operations:
            # here, we loop through all tape operations, and make
            # the transformation if a RY gate is encountered.
            if isinstance(o, qml.RY):
                t_op.append(
                    qml.RX(-a * framework.cos(o.data[0]), wires=o.wires))
                new_ops.append(t_op[-1])
            else:
                new_ops.append(o)

        self.qtape._ops = new_ops
        self.qtape._update()
Beispiel #2
0
    def test_qnode(self, mocker, tol):
        """Test that specifying diff_method allows the reversible
        method to be selected"""
        args = np.array([0.54, 0.1, 0.5], requires_grad=True)
        dev = qml.device("default.qubit", wires=2)

        def circuit(x, y, z):
            qml.Hadamard(wires=0)
            qml.RX(0.543, wires=0)
            qml.CNOT(wires=[0, 1])

            qml.Rot(x, y, z, wires=0)

            qml.Rot(1.3, -2.3, 0.5, wires=[0])
            qml.RZ(-0.5, wires=0)
            qml.RY(0.5, wires=1)
            qml.CNOT(wires=[0, 1])

            return expval(qml.PauliX(0) @ qml.PauliZ(1))

        qnode1 = QNode(circuit, dev, diff_method="reversible")
        spy = mocker.spy(ReversibleTape, "analytic_pd")

        grad_fn = qml.grad(qnode1)
        grad_A = grad_fn(*args)

        spy.assert_called()
        assert isinstance(qnode1.qtape, ReversibleTape)

        qnode2 = QNode(circuit, dev, diff_method="finite-diff")
        grad_fn = qml.grad(qnode2)
        grad_F = grad_fn(*args)

        assert not isinstance(qnode2.qtape, ReversibleTape)
        assert np.allclose(grad_A, grad_F, atol=tol, rtol=0)
Beispiel #3
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)

        # backprop is given priority
        res = QNode.get_best_method(dev, "some_interface")
        assert res == (QuantumTape, None, "backprop")

        # device is the next priority
        res = QNode.get_best_method(dev, "another_interface")
        assert res == (QuantumTape, "another_interface", "device")

        # The next fallback is parameter-shift.
        monkeypatch.setitem(dev._capabilities, "provides_jacobian", False)
        res = QNode.get_best_method(dev, "another_interface")
        assert res == (QubitParamShiftTape, "another_interface", "best")

        # 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 == (QuantumTape, "another_interface", "numeric")
Beispiel #4
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 expval(qml.PauliZ(0)), 5

        qn = QNode(func, dev)

        with pytest.raises(qml.QuantumFunctionError,
                           match="must return either a single measurement"):
            qn(5, 1)
Beispiel #5
0
    def test_gradient_repeated_gate_parameters(self, mocker, tol):
        """Tests that repeated use of a free parameter in a
        multi-parameter gate yield correct gradients."""
        dev = qml.device("default.qubit", wires=1)
        params = np.array([0.8, 1.3], requires_grad=True)

        def circuit(params):
            qml.RX(np.array(np.pi / 4, requires_grad=False), wires=[0])
            qml.Rot(params[1], params[0], 2 * params[0], wires=[0])
            return expval(qml.PauliX(0))

        spy_numeric = mocker.spy(QuantumTape, "numeric_pd")
        spy_analytic = mocker.spy(ReversibleTape, "analytic_pd")

        cost = QNode(circuit, dev, diff_method="finite-diff")
        grad_fn = qml.grad(cost)
        grad_F = grad_fn(params)

        spy_numeric.assert_called()
        spy_analytic.assert_not_called()

        cost = QNode(circuit, dev, diff_method="reversible")
        grad_fn = qml.grad(cost)
        grad_A = grad_fn(params)

        spy_analytic.assert_called()

        # the different methods agree
        assert np.allclose(grad_A, grad_F, atol=tol, rtol=0)
Beispiel #6
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.qubit", wires=1)

        with pytest.raises(qml.QuantumFunctionError,
                           match="does not support native computations"):
            QNode._validate_backprop_method(dev, None)
Beispiel #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)
Beispiel #8
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._get_parameter_shift_tape(dev)
Beispiel #9
0
    def test_invalid_interface(self):
        """Test that an exception is raised for an invalid interface"""
        dev = qml.device("default.qubit", wires=1)

        with pytest.raises(qml.QuantumFunctionError,
                           match="Unknown interface"):
            QNode(None, dev, interface="something")
Beispiel #10
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 expval(qml.PauliZ(0))

        qn = QNode(func, dev)

        x = 0.12
        y = 0.54

        res = qn(x, y)

        assert isinstance(qn.qtape, QuantumTape)
        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
Beispiel #11
0
    def test_unknown_diff_method(self):
        """Test that an exception is raised for an unknown differentiation method"""
        dev = qml.device("default.qubit", wires=1)

        with pytest.raises(
                qml.QuantumFunctionError,
                match="Differentiation method hello not recognized"):
            QNode(None, dev, diff_method="hello")
Beispiel #12
0
    def test_diff_method(self, mocker):
        """Test that a user-supplied diff-method correctly returns the right
        quantum tape, interface, and diff method."""
        dev = qml.device("default.qubit", wires=1)

        mock_best = mocker.patch("pennylane.beta.tapes.QNode.get_best_method")
        mock_best.return_value = 1, 2, 3

        mock_backprop = mocker.patch(
            "pennylane.beta.tapes.QNode._validate_backprop_method")
        mock_backprop.return_value = 4, 5, 6

        mock_device = mocker.patch(
            "pennylane.beta.tapes.QNode._validate_device_method")
        mock_device.return_value = 7, 8, 9

        qn = QNode(None, dev, diff_method="best")
        assert qn._tape == mock_best.return_value[0]
        assert qn.interface == mock_best.return_value[1]
        assert qn.diff_options["method"] == mock_best.return_value[2]

        qn = QNode(None, dev, diff_method="backprop")
        assert qn._tape == mock_backprop.return_value[0]
        assert qn.interface == mock_backprop.return_value[1]
        assert qn.diff_options["method"] == mock_backprop.return_value[2]
        mock_backprop.assert_called_once()

        qn = QNode(None, dev, diff_method="device")
        assert qn._tape == mock_device.return_value[0]
        assert qn.interface == mock_device.return_value[1]
        assert qn.diff_options["method"] == mock_device.return_value[2]
        mock_device.assert_called_once()

        qn = QNode(None, dev, diff_method="finite-diff")
        assert qn._tape == QuantumTape
        assert qn.diff_options["method"] == "numeric"

        qn = QNode(None, dev, diff_method="parameter-shift")
        assert qn._tape == QubitParamShiftTape
        assert qn.diff_options["method"] == "analytic"

        # check that get_best_method was only ever called once
        mock_best.assert_called_once()
Beispiel #13
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, None)

        monkeypatch.setitem(dev._capabilities, "provides_jacobian", True)
        tape_class, interface, method = QNode._validate_device_method(
            dev, "interface")

        assert tape_class is QuantumTape
        assert method == "device"
        assert interface == "interface"
Beispiel #14
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)

        tape_class, interface, method = QNode._validate_backprop_method(
            dev, test_interface)

        assert tape_class is QuantumTape
        assert method == "backprop"
        assert interface == None
Beispiel #15
0
    def test_consistent_measurement_order(self):
        """Test evaluation exceeds 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 = expval(qml.PauliZ(0))
            m2 = 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]
Beispiel #16
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 = expval(qml.PauliZ(0))
            return 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)
Beispiel #17
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 probs(wires=0), probs(wires=1)

        qn = QNode(func, dev, h=1e-8, order=2)
        assert qn.diff_options["h"] == 1e-8
        assert qn.diff_options["order"] == 2

        x = 0.12
        y = 0.54

        res = qn(x, y)
        jac = qn.qtape.jacobian(dev, params=[0.45, 0.1])

        assert jac.shape == (4, 2)
Beispiel #18
0
    def test_import_error(self, mocker):
        """Test that an exception is caught on import error"""
        mock = mocker.patch(
            "pennylane.beta.interfaces.torch.TorchInterface.apply")
        mock.side_effect = ImportError()

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

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

        with pytest.raises(
                qml.QuantumFunctionError,
                match=
                "PyTorch not found. Please install the latest version of PyTorch to enable the 'torch' interface",
        ):
            qn(0.1, 0.1)
Beispiel #19
0
 def test_parameter_shift_tape_qubit_device(self):
     """Test that the get_parameter_shift_method method correctly and
     returns the correct tape for qubit devices."""
     dev = qml.device("default.qubit", wires=1)
     tape_class = QNode._get_parameter_shift_tape(dev)
     assert tape_class is QubitParamShiftTape
Beispiel #20
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(None, None)