Beispiel #1
0
    def test_qnode_gradient_fanout(self, qubit_device_1_wire, tol):
        "Tests that the correct gradient is computed for qnodes which use the same parameter in multiple gates."

        def expZ(state):
            return np.abs(state[0])**2 - np.abs(state[1])**2

        extra_param = 0.31

        def circuit(reused_param, other_param):
            qml.RX(extra_param, wires=[0])
            qml.RY(reused_param, wires=[0])
            qml.RZ(other_param, wires=[0])
            qml.RX(reused_param, wires=[0])
            return qml.expval(qml.PauliZ(0))

        f = qml.QNode(circuit, qubit_device_1_wire)
        zero_state = np.array([1., 0.])

        for reused_p in thetas:
            reused_p = reused_p**3 / 19
            for other_p in thetas:
                other_p = other_p**2 / 11

                # autograd gradient
                grad = autograd.grad(f)
                grad_eval = grad(reused_p, other_p)

                # manual gradient
                grad_true0 = (expZ(Rx(reused_p) @ Rz(other_p) @ Ry(reused_p + np.pi / 2) @ Rx(extra_param) @ zero_state) \
                             -expZ(Rx(reused_p) @ Rz(other_p) @ Ry(reused_p - np.pi / 2) @ Rx(extra_param) @ zero_state)) / 2
                grad_true1 = (expZ(Rx(reused_p + np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state) \
                             -expZ(Rx(reused_p - np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state)) / 2
                grad_true = grad_true0 + grad_true1  # product rule

                assert grad_eval == pytest.approx(grad_true, abs=tol)
    def test_fanout_multiple_params(self, reused_p, other_p, tol):
        """Tests that the correct gradient is computed for qnodes which
        use the same parameter in multiple gates."""

        from gate_data import Rotx as Rx, Roty as Ry, Rotz as Rz

        def expZ(state):
            return np.abs(state[0]) ** 2 - np.abs(state[1]) ** 2

        extra_param = 0.31
        def circuit(reused_param, other_param):
            qml.RX(extra_param, wires=[0])
            qml.RY(reused_param, wires=[0])
            qml.RZ(other_param, wires=[0])
            qml.RX(reused_param, wires=[0])
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=1)
        f = QubitQNode(circuit, dev)
        zero_state = np.array([1., 0.])

        # analytic gradient
        grad_A = f.jacobian([reused_p, other_p])

        # manual gradient
        grad_true0 = (expZ(Rx(reused_p) @ Rz(other_p) @ Ry(reused_p + np.pi / 2) @ Rx(extra_param) @ zero_state) \
                     -expZ(Rx(reused_p) @ Rz(other_p) @ Ry(reused_p - np.pi / 2) @ Rx(extra_param) @ zero_state)) / 2
        grad_true1 = (expZ(Rx(reused_p + np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state) \
                     -expZ(Rx(reused_p - np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state)) / 2
        grad_true = grad_true0 + grad_true1 # product rule

        assert grad_A[0, 0] == pytest.approx(grad_true, abs=tol)
Beispiel #3
0
    def test_fanout_multiple_params(self, reused_p, other_p, tol, mocker, dev):
        """Tests that the correct gradient is computed for qnodes which
        use the same parameter in multiple gates."""

        from gate_data import Rotx as Rx, Roty as Ry, Rotz as Rz

        def expZ(state):
            return np.abs(state[0]) ** 2 - np.abs(state[1]) ** 2

        extra_param = np.array(0.31, requires_grad=False)

        @qnode(dev, diff_method="adjoint")
        def cost(p1, p2):
            qml.RX(extra_param, wires=[0])
            qml.RY(p1, wires=[0])
            qml.RZ(p2, wires=[0])
            qml.RX(p1, wires=[0])
            return qml.expval(qml.PauliZ(0))

        zero_state = np.array([1.0, 0.0])
        cost(reused_p, other_p)

        spy = mocker.spy(dev, "adjoint_jacobian")

        # analytic gradient
        grad_fn = qml.grad(cost)
        grad_D = grad_fn(reused_p, other_p)

        spy.assert_called_once()

        # manual gradient
        grad_true0 = (
            expZ(
                Rx(reused_p) @ Rz(other_p) @ Ry(reused_p + np.pi / 2) @ Rx(extra_param) @ zero_state
            )
            - expZ(
                Rx(reused_p) @ Rz(other_p) @ Ry(reused_p - np.pi / 2) @ Rx(extra_param) @ zero_state
            )
        ) / 2
        grad_true1 = (
            expZ(
                Rx(reused_p + np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state
            )
            - expZ(
                Rx(reused_p - np.pi / 2) @ Rz(other_p) @ Ry(reused_p) @ Rx(extra_param) @ zero_state
            )
        ) / 2
        expected = grad_true0 + grad_true1  # product rule

        assert np.allclose(grad_D[0], expected, atol=tol, rtol=0)
Beispiel #4
0
    def test_fanout_multiple_params(self, reused_p, other_p, tol):
        """Tests that the correct gradient is computed for qnodes which
        use the same parameter in multiple gates."""

        from gate_data import Rotx as Rx, Roty as Ry, Rotz as Rz

        def expZ(state):
            return np.abs(state[0])**2 - np.abs(state[1])**2

        dev = qml.device("default.qubit", wires=1)
        extra_param = np.array(0.31, requires_grad=False)

        @qnode(dev)
        def cost(p1, p2):
            qml.RX(extra_param, wires=[0])
            qml.RY(p1, wires=[0])
            qml.RZ(p2, wires=[0])
            qml.RX(p1, wires=[0])
            return expval(qml.PauliZ(0))

        zero_state = np.array([1.0, 0.0])

        # analytic gradient
        grad_fn = qml.grad(cost)
        grad_A = grad_fn(reused_p, other_p)

        # manual gradient
        grad_true0 = (expZ(
            Rx(reused_p) @ Rz(other_p) @ Ry(reused_p + np.pi / 2)
            @ Rx(extra_param) @ zero_state) - expZ(
                Rx(reused_p) @ Rz(other_p) @ Ry(reused_p - np.pi / 2)
                @ Rx(extra_param) @ zero_state)) / 2
        grad_true1 = (expZ(
            Rx(reused_p + np.pi / 2) @ Rz(other_p) @ Ry(reused_p)
            @ Rx(extra_param) @ zero_state) - expZ(
                Rx(reused_p - np.pi / 2) @ Rz(other_p) @ Ry(reused_p)
                @ Rx(extra_param) @ zero_state)) / 2
        expected = grad_true0 + grad_true1  # product rule

        assert np.allclose(grad_A[0], expected, atol=tol, rtol=0)