Пример #1
0
    def test_expval_and_variance(self, tol):
        """Test that the qnode works for a combination of expectation
        values and variances"""
        dev = qml.device("default.qubit", wires=3)

        def circuit(a, b, c):
            qml.RX(a, wires=0)
            qml.RY(b, wires=1)
            qml.CNOT(wires=[1, 2])
            qml.RX(c, wires=2)
            qml.CNOT(wires=[0, 1])
            qml.RZ(c, wires=2)
            return qml.var(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.var(
                qml.PauliZ(2))

        circuit = QubitQNode(circuit, dev)

        a = 0.54
        b = -0.423
        c = 0.123
        var = circuit(a, b, c)
        expected = np.array([
            np.sin(a)**2,
            np.cos(a) * np.cos(b),
            0.25 * (3 - 2 * np.cos(b)**2 * np.cos(2 * c) - np.cos(2 * b)),
        ])
        assert var == pytest.approx(expected, abs=tol)

        # # circuit jacobians
        gradA = circuit.jacobian([a, b, c], method="A")
        gradF = circuit.jacobian([a, b, c], method="F")
        expected = np.array([
            [2 * np.cos(a) * np.sin(a), -np.cos(b) * np.sin(a), 0],
            [
                0,
                -np.cos(a) * np.sin(b),
                0.5 *
                (2 * np.cos(b) * np.cos(2 * c) * np.sin(b) + np.sin(2 * b)),
            ],
            [0, 0, np.cos(b)**2 * np.sin(2 * c)],
        ]).T
        assert gradF == pytest.approx(expected, abs=tol)
        assert gradA == pytest.approx(expected, abs=tol)
Пример #2
0
    def test_differentiate_second_positional(self, tol):
        """Tests that the second positional arguments are differentiated."""
        def circuit3(a, b):
            qml.RX(b, wires=0)
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=2)
        circuit3 = QubitQNode(circuit3, dev)

        a = 0.7418
        b = -5.0
        circuit_output = circuit3(a, b)
        expected_output = np.cos(b)
        assert circuit_output == pytest.approx(expected_output, abs=tol)

        # circuit jacobians
        circuit_jacobian = circuit3.jacobian([a, b])
        expected_jacobian = np.array([[0, -np.sin(b)]])
        assert circuit_jacobian == pytest.approx(expected_jacobian, abs=tol)
Пример #3
0
    def test_involutory_variance(self, tol):
        """Tests qubit observable that are involutory"""
        def circuit(a):
            qml.RX(a, wires=0)
            return qml.var(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=1)
        circuit = QubitQNode(circuit, dev)

        a = 0.54
        var = circuit(a)
        expected = 1 - np.cos(a) ** 2
        assert var == pytest.approx(expected, abs=tol)

        # circuit jacobians
        gradA = circuit.jacobian([a], method="A")
        gradF = circuit.jacobian([a], method="F")
        expected = 2 * np.sin(a) * np.cos(a)
        assert gradF == pytest.approx(expected, abs=tol)
        assert gradA == pytest.approx(expected, abs=tol)
Пример #4
0
    def test_differentiate_all_positional(self, tol):
        """Tests that all positional arguments are differentiated."""
        def circuit1(a, b, c):
            qml.RX(a, wires=0)
            qml.RX(b, wires=1)
            qml.RX(c, wires=2)
            return tuple(qml.expval(qml.PauliZ(idx)) for idx in range(3))

        dev = qml.device("default.qubit", wires=3)
        circuit1 = QubitQNode(circuit1, dev)

        vals = np.array([np.pi, np.pi / 2, np.pi / 3])
        circuit_output = circuit1(*vals)
        expected_output = np.cos(vals)
        assert circuit_output == pytest.approx(expected_output, abs=tol)

        # circuit jacobians
        circuit_jacobian = circuit1.jacobian(vals)
        expected_jacobian = -np.diag(np.sin(vals))
        assert circuit_jacobian == pytest.approx(expected_jacobian, abs=tol)
Пример #5
0
    def test_parameter_multipliers(self, mult, tol):
        """Test that various types and values of scalar multipliers for differentiable
        qfunc parameters yield the correct gradients."""
        def circuit(x):
            qml.RY(mult * x, wires=[0])
            return qml.expval(qml.PauliX(0))

        dev = qml.device("default.qubit", wires=1)
        q = QubitQNode(circuit, dev)

        par = [0.1]

        # gradients
        exact = mult * np.cos(mult * np.array([par]))
        grad_F = q.jacobian(par, method="F")
        grad_A = q.jacobian(par, method="A")

        # different methods must agree
        assert grad_F == pytest.approx(exact, abs=tol)
        assert grad_A == pytest.approx(exact, abs=tol)
Пример #6
0
    def test_fanout(self, tol):
        """Tests qubit observable with repeated parameters"""
        def circuit(a):
            qml.RX(a, wires=0)
            qml.RY(a, wires=0)
            return qml.var(qml.PauliZ(0))

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

        a = 0.54
        var = circuit(a)
        expected = 0.5 * np.sin(a) ** 2 * (np.cos(2 * a) + 3)
        assert var == pytest.approx(expected, abs=tol)

        # circuit jacobians
        gradA = circuit.jacobian([a], method="A")
        gradF = circuit.jacobian([a], method="F")
        expected = 4 * np.sin(a) * np.cos(a) ** 3
        assert gradA == pytest.approx(expected, abs=tol)
        assert gradF == pytest.approx(expected, abs=tol)
Пример #7
0
    def test_Rot_gradient(self, theta, tol):
        """Tests that the automatic gradient of a arbitrary Euler-angle-parameterized gate is correct."""
        def circuit(x, y, z):
            qml.Rot(x, y, z, wires=[0])
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=1)
        circuit = QubitQNode(circuit, dev)
        eye = np.eye(3)

        angle_inputs = np.array([theta, theta**3, np.sqrt(2) * theta])
        autograd_val = circuit.jacobian(angle_inputs)
        manualgrad_val = np.zeros((1, 3))

        for idx in range(3):
            onehot_idx = eye[idx]
            param1 = angle_inputs + np.pi / 2 * onehot_idx
            param2 = angle_inputs - np.pi / 2 * onehot_idx
            manualgrad_val[0, idx] = (circuit(*param1) - circuit(*param2)) / 2

        assert autograd_val == pytest.approx(manualgrad_val, abs=tol)
Пример #8
0
    def test_non_involutory_variance(self, tol):
        """Tests a qubit Hermitian observable that is not involutory"""
        A = np.array([[4, -1 + 6j], [-1 - 6j, 2]])

        def circuit(a):
            qml.RX(a, wires=0)
            return qml.var(qml.Hermitian(A, 0))

        dev = qml.device("default.qubit", wires=1)
        circuit = QubitQNode(circuit, dev)

        a = 0.54
        var = circuit(a)
        expected = (39 / 2) - 6 * np.sin(2 * a) + (35 / 2) * np.cos(2 * a)
        assert var == pytest.approx(expected, abs=tol)

        # circuit jacobians
        gradA = circuit.jacobian([a], method="A")
        gradF = circuit.jacobian([a], method="F")
        expected = -35 * np.sin(2 * a) - 12 * np.cos(2 * a)
        assert gradA == pytest.approx(expected, abs=tol)
        assert gradF == pytest.approx(expected, abs=tol)
Пример #9
0
    def test_differentiate_second_third_positional(self, tol):
        """Tests that the second and third positional arguments are differentiated."""

        def circuit4(a, b, c):
            qml.RX(b, wires=0)
            qml.RX(c, wires=1)
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        dev = qml.device("default.qubit", wires=2)
        circuit4 = QubitQNode(circuit4, dev)

        a = 0.7418
        b = -5.0
        c = np.pi / 7
        circuit_output = circuit4(a, b, c)
        expected_output = np.array([np.cos(b), np.cos(c)])
        assert circuit_output == pytest.approx(expected_output, abs=tol)

        # circuit jacobians
        circuit_jacobian = circuit4.jacobian([a, b, c])
        expected_jacobian = np.array([[0.0, -np.sin(b), 0.0], [0.0, 0.0, -np.sin(c)]])
        assert circuit_jacobian == pytest.approx(expected_jacobian, abs=tol)
Пример #10
0
    def test_gradient_gate_with_multiple_parameters(self, tol):
        """Tests that gates with multiple free parameters yield correct gradients."""
        par = [0.5, 0.3, -0.7]

        def qf(x, y, z):
            qml.RX(0.4, wires=[0])
            qml.Rot(x, y, z, wires=[0])
            qml.RY(-0.2, wires=[0])
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=1)
        q = QubitQNode(qf, dev)
        value = q(*par)
        grad_A = q.jacobian(par, method="A")
        grad_F = q.jacobian(par, method="F")

        # analytic method works for every parameter
        assert q.par_to_grad_method == {0: "A", 1: "A", 2: "A"}
        # gradient has the correct shape and every element is nonzero
        assert grad_A.shape == (1, 3)
        assert np.count_nonzero(grad_A) == 3
        # the different methods agree
        assert grad_A == pytest.approx(grad_F, abs=tol)