Beispiel #1
0
    def test_set_and_get(self):
        """Test that the caching attribute can be set and accessed"""
        tape = QuantumTape()
        assert tape.caching == 0

        tape = QuantumTape(caching=10)
        assert tape.caching == 10
Beispiel #2
0
    def test_differentiable_expand(self, mocker, tol):
        """Test that operation and nested tapes expansion
        is differentiable"""
        spy = mocker.spy(QuantumTape, "jacobian")
        mock = mocker.patch.object(qml.operation.Operation, "do_check_domain",
                                   False)

        class U3(qml.U3):
            def expand(self):
                tape = QuantumTape()
                theta, phi, lam = self.data
                wires = self.wires
                tape._ops += [
                    qml.Rot(lam, theta, -lam, wires=wires),
                    qml.PhaseShift(phi + lam, wires=wires),
                ]
                return tape

        qtape = QuantumTape()

        dev = qml.device("default.qubit.tf", wires=1)
        a = np.array(0.1)
        p = tf.Variable([0.1, 0.2, 0.3], dtype=tf.float64)

        with tf.GradientTape() as tape:

            with qtape:
                qml.RX(a, wires=0)
                U3(p[0], p[1], p[2], wires=0)
                expval(qml.PauliX(0))

            qtape = qtape.expand()

            assert [i.name
                    for i in qtape.operations] == ["RX", "Rot", "PhaseShift"]
            assert np.all(
                qtape.get_parameters() == [a, p[2], p[0], -p[2], p[1] + p[2]])

            res = qtape.execute(device=dev)

        expected = tf.cos(a) * tf.cos(p[1]) * tf.sin(
            p[0]) + tf.sin(a) * (tf.cos(p[2]) * tf.sin(p[1]) +
                                 tf.cos(p[0]) * tf.cos(p[1]) * tf.sin(p[2]))
        assert np.allclose(res, expected, atol=tol, rtol=0)

        res = tape.jacobian(res, p)
        expected = np.array([
            tf.cos(p[1]) * (tf.cos(a) * tf.cos(p[0]) -
                            tf.sin(a) * tf.sin(p[0]) * tf.sin(p[2])),
            tf.cos(p[1]) * tf.cos(p[2]) * tf.sin(a) - tf.sin(p[1]) *
            (tf.cos(a) * tf.sin(p[0]) +
             tf.cos(p[0]) * tf.sin(a) * tf.sin(p[2])),
            tf.sin(a) * (tf.cos(p[0]) * tf.cos(p[1]) * tf.cos(p[2]) -
                         tf.sin(p[1]) * tf.sin(p[2])),
        ])
        assert np.allclose(res, expected, atol=tol, rtol=0)
        spy.assert_not_called()
Beispiel #3
0
    def test_sampling(self):
        """Test that the tape correctly marks itself as returning samples"""
        with QuantumTape() as tape:
            expval(qml.PauliZ(wires=1))

        assert not tape.is_sampled

        with QuantumTape() as tape:
            sample(qml.PauliZ(wires=0))

        assert tape.is_sampled
Beispiel #4
0
    def test_nested_tape(self):
        """Test that a nested tape properly expands"""
        with QuantumTape() as tape1:
            with QuantumTape() as tape2:
                op1 = qml.RX(0.543, wires=0)
                op2 = qml.RY(0.1, wires=0)

        assert tape1.num_params == 2
        assert tape1.operations == [tape2]

        new_tape = tape1.expand()
        assert new_tape.num_params == 2
        assert len(new_tape.operations) == 2
        assert isinstance(new_tape.operations[0], qml.RX)
        assert isinstance(new_tape.operations[1], qml.RY)
Beispiel #5
0
    def test_nesting_and_decomposition(self):
        """Test an example that contains nested tapes and operation decompositions."""

        with QuantumTape() as tape:
            qml.BasisState(np.array([1, 1]), wires=[0, "a"])

            with QuantumTape() as tape2:
                qml.Rot(0.543, 0.1, 0.4, wires=0)

            qml.CNOT(wires=[0, "a"])
            qml.RY(0.2, wires="a")
            probs(wires=0), probs(wires="a")

        new_tape = tape.expand()
        assert len(new_tape.operations) == 5
 def cost(a, b, device):
     with AutogradInterface.apply(QuantumTape()) as tape:
         qml.RY(a, wires=0)
         qml.RX(b, wires=0)
         expval(qml.PauliZ(0))
     assert tape.trainable_params == {0}
     return tape.execute(device)
 def cost(a, b, c, device):
     with QuantumTape() as tape:
         qml.RY(a * c, wires=0)
         qml.RZ(b, wires=0)
         qml.RX(c + c**2 + np.sin(a), wires=0)
         expval(qml.PauliZ(0))
     return tape.execute(device)
 def cost(a, b, device):
     with QuantumTape() as tape:
         qml.RY(a, wires=0)
         qml.RX(b, wires=0)
         expval(qml.PauliZ(0))
         expval(qml.PauliY(0))
     return tape.execute(device)
    def test_jacobian(self, mocker, tol):
        """Test jacobian calculation"""
        spy = mocker.spy(QuantumTape, "jacobian")
        a = np.array(0.1, requires_grad=True)
        b = np.array(0.2, requires_grad=True)

        def cost(a, b, device):
            with QuantumTape() as tape:
                qml.RY(a, wires=0)
                qml.RX(b, wires=0)
                expval(qml.PauliZ(0))
                expval(qml.PauliY(0))
            return tape.execute(device)

        dev = qml.device("default.qubit.autograd", wires=2)
        res = qml.jacobian(cost)(a, b, device=dev)
        spy.assert_not_called()
        assert res.shape == (2, 2)

        # compare to standard tape jacobian
        with QuantumTape() as tape:
            qml.RY(a, wires=0)
            qml.RX(b, wires=0)
            expval(qml.PauliZ(0))
            expval(qml.PauliY(0))

        expected = tape.jacobian(dev)
        assert expected.shape == (2, 2)
        assert np.allclose(res, expected, atol=tol, rtol=0)
Beispiel #10
0
    def test_jacobian(self, mocker, tol):
        """Test jacobian calculation"""
        spy = mocker.spy(QuantumTape, "jacobian")
        a = tf.Variable(0.1, dtype=tf.float64)
        b = tf.Variable(0.2, dtype=tf.float64)

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

        with tf.GradientTape() as tape:
            with TFInterface.apply(QuantumTape()) as qtape:
                qml.RY(a, wires=0)
                qml.RX(b, wires=1)
                qml.CNOT(wires=[0, 1])
                expval(qml.PauliZ(0))
                expval(qml.PauliY(1))

            assert qtape.trainable_params == {0, 1}
            res = qtape.execute(dev)

        assert isinstance(res, tf.Tensor)
        assert res.shape == (2, )

        expected = [tf.cos(a), -tf.cos(a) * tf.sin(b)]
        assert np.allclose(res, expected, atol=tol, rtol=0)

        res = tape.jacobian(res, [a, b])
        expected = [[-tf.sin(a), tf.sin(a) * tf.sin(b)],
                    [0, -tf.cos(a) * tf.cos(b)]]
        assert np.allclose(res, expected, atol=tol, rtol=0)

        spy.assert_called()
Beispiel #11
0
    def test_classical_processing(self, mocker, tol):
        """Test classical processing within the quantum tape"""
        spy = mocker.spy(QuantumTape, "jacobian")

        a = tf.Variable(0.1, dtype=tf.float64)
        b = tf.constant(0.2, dtype=tf.float64)
        c = tf.Variable(0.3, dtype=tf.float64)

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

        with tf.GradientTape() as tape:
            with QuantumTape() as qtape:
                qml.RY(a * c, wires=0)
                qml.RZ(b, wires=0)
                qml.RX(c + c**2 + tf.sin(a), wires=0)
                expval(qml.PauliZ(0))

            assert qtape.get_parameters() == [a * c, b, c + c**2 + tf.sin(a)]
            res = qtape.execute(dev)

        res = tape.jacobian(res, [a, b, c])
        assert isinstance(res[0], tf.Tensor)
        assert res[1] is None
        assert isinstance(res[2], tf.Tensor)

        spy.assert_not_called()
Beispiel #12
0
    def test_ragged_differentiation(self, tol):
        """Tests correct output shape and evaluation for a tape
        with prob and expval outputs"""
        dev = qml.device("default.qubit", wires=2)
        x = tf.Variable(0.543, dtype=tf.float64)
        y = tf.Variable(-0.654, dtype=tf.float64)

        with tf.GradientTape() as tape:
            with TFInterface.apply(QuantumTape()) as qtape:
                qml.RX(x, wires=[0])
                qml.RY(y, wires=[1])
                qml.CNOT(wires=[0, 1])
                expval(qml.PauliZ(0))
                probs(wires=[1])

            res = qtape.execute(dev)

        expected = np.array([
            tf.cos(x), (1 + tf.cos(x) * tf.cos(y)) / 2,
            (1 - tf.cos(x) * tf.cos(y)) / 2
        ])
        assert np.allclose(res, expected, atol=tol, rtol=0)

        res = tape.jacobian(res, [x, y])
        expected = np.array([
            [
                -tf.sin(x), -tf.sin(x) * tf.cos(y) / 2,
                tf.cos(y) * tf.sin(x) / 2
            ],
            [0, -tf.cos(x) * tf.sin(y) / 2,
             tf.cos(x) * tf.sin(y) / 2],
        ])
        assert np.allclose(res, expected, atol=tol, rtol=0)
Beispiel #13
0
    def test_jacobian_dtype(self, tol):
        """Test calculating the jacobian with a different datatype. Here, we
        specify tf.float32, as opposed to the default value of tf.float64."""
        a = tf.Variable(0.1, dtype=tf.float32)
        b = tf.Variable(0.2, dtype=tf.float32)

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

        with tf.GradientTape() as tape:
            with TFInterface.apply(QuantumTape(), dtype=tf.float32) as qtape:
                qml.RY(a, wires=0)
                qml.RX(b, wires=1)
                qml.CNOT(wires=[0, 1])
                expval(qml.PauliZ(0))
                expval(qml.PauliY(1))

            assert qtape.trainable_params == {0, 1}
            res = qtape.execute(dev)

        assert isinstance(res, tf.Tensor)
        assert res.shape == (2, )
        assert res.dtype is tf.float32

        res = tape.jacobian(res, [a, b])
        assert [r.dtype is tf.float32 for r in res]
Beispiel #14
0
    def test_ragged_differentiation(self, tol):
        """Tests correct output shape and evaluation for a tape
        with prob and expval outputs"""
        dev = qml.device("default.qubit", wires=2)
        x_val = 0.543
        y_val = -0.654
        x = torch.tensor(x_val, requires_grad=True)
        y = torch.tensor(y_val, requires_grad=True)

        with TorchInterface.apply(QuantumTape()) as tape:
            qml.RX(x, wires=[0])
            qml.RY(y, wires=[1])
            qml.CNOT(wires=[0, 1])
            expval(qml.PauliZ(0))
            probs(wires=[1])

        res = tape.execute(dev)

        expected = np.array([
            np.cos(x_val),
            (1 + np.cos(x_val) * np.cos(y_val)) / 2,
            (1 - np.cos(x_val) * np.cos(y_val)) / 2,
        ])
        assert np.allclose(res.detach().numpy(), expected, atol=tol, rtol=0)

        loss = torch.sum(res)
        loss.backward()
        expected = np.array([
            -np.sin(x_val) + -np.sin(x_val) * np.cos(y_val) / 2 +
            np.cos(y_val) * np.sin(x_val) / 2,
            -np.cos(x_val) * np.sin(y_val) / 2 +
            np.cos(x_val) * np.sin(y_val) / 2,
        ])
        assert np.allclose(x.grad, expected[0], atol=tol, rtol=0)
        assert np.allclose(y.grad, expected[1], atol=tol, rtol=0)
Beispiel #15
0
    def test_classical_processing(self, tol):
        """Test classical processing within the quantum tape"""
        p_val = [0.1, 0.2]
        params = torch.tensor(p_val, requires_grad=True)

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

        with TorchInterface.apply(QuantumTape()) as tape:
            qml.RY(params[0] * params[1], wires=0)
            qml.RZ(0.2, wires=0)
            qml.RX(params[1] + params[1]**2 + torch.sin(params[0]), wires=0)
            expval(qml.PauliZ(0))

        assert tape.trainable_params == {0, 2}

        tape_params = [i.detach().numpy() for i in tape.get_parameters()]
        assert np.allclose(
            tape_params,
            [p_val[0] * p_val[1], p_val[1] + p_val[1]**2 + np.sin(p_val[0])],
            atol=tol,
            rtol=0,
        )

        res = tape.execute(dev)
        res.backward()

        assert isinstance(params.grad, torch.Tensor)
        assert params.shape == (2, )
        def cost_fn(a, p, device):
            tape = QuantumTape()

            with tape:
                qml.RX(a, wires=0)
                U3(*p, wires=0)
                expval(qml.PauliX(0))

            tape = tape.expand()

            assert [i.name
                    for i in tape.operations] == ["RX", "Rot", "PhaseShift"]
            assert np.all(
                tape.get_parameters() == [a, p[2], p[0], -p[2], p[1] + p[2]])

            return tape.execute(device=device)
Beispiel #17
0
    def test_jacobian_dtype(self, tol):
        """Test calculating the jacobian with a different datatype"""
        a_val = 0.1
        b_val = 0.2

        a = torch.tensor(a_val, requires_grad=True, dtype=torch.float32)
        b = torch.tensor(b_val, requires_grad=True, dtype=torch.float32)

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

        with TorchInterface.apply(QuantumTape(), dtype=torch.float32) as tape:
            qml.RY(a, wires=0)
            qml.RX(b, wires=1)
            qml.CNOT(wires=[0, 1])
            expval(qml.PauliZ(0))
            expval(qml.PauliY(1))

        assert tape.trainable_params == {0, 1}
        res = tape.execute(dev)

        assert isinstance(res, torch.Tensor)
        assert res.shape == (2, )
        assert res.dtype is torch.float32

        loss = torch.sum(res)
        loss.backward()
        assert a.grad.dtype is torch.float32
        assert b.grad.dtype is torch.float32
Beispiel #18
0
    def test_measurement_expansion(self):
        """Test that measurement expansion works as expected"""
        with QuantumTape() as tape:
            # expands into 2 PauliX
            qml.BasisState(np.array([1, 1]), wires=[0, "a"])
            qml.CNOT(wires=[0, "a"])
            qml.RY(0.2, wires="a")
            probs(wires=0)
            # expands into RY on wire b
            expval(qml.PauliZ("a") @ qml.Hadamard("b"))
            # expands into QubitUnitary on wire 0
            var(qml.Hermitian(np.array([[1, 2], [2, 4]]), wires=[0]))

        new_tape = tape.expand(expand_measurements=True)

        assert len(new_tape.operations) == 6

        expected = [
            qml.operation.Probability, qml.operation.Expectation,
            qml.operation.Variance
        ]
        assert [
            m.return_type is r for m, r in zip(new_tape.measurements, expected)
        ]

        expected = [None, None, None]
        assert [m.obs is r for m, r in zip(new_tape.measurements, expected)]

        expected = [None, [1, -1, -1, 1], [0, 5]]
        assert [
            m.eigvals is r for m, r in zip(new_tape.measurements, expected)
        ]
Beispiel #19
0
    def test_parameter_transforms(self):
        """Test that inversion correctly changes trainable parameters"""
        init_state = np.array([1, 1])
        p = [0.1, 0.2, 0.3, 0.4]

        with QuantumTape() as tape:
            prep = qml.BasisState(init_state, wires=[0, "a"])
            ops = [
                qml.RX(p[0], wires=0),
                qml.Rot(*p[1:], wires=0).inv(),
                qml.CNOT(wires=[0, "a"])
            ]
            m1 = probs(wires=0)
            m2 = probs(wires="a")

        tape.trainable_params = {1, 2}
        tape.inv()

        # check that operation order is reversed
        assert tape.trainable_params == {1, 4}
        assert tape.get_parameters() == [p[1], p[0]]

        # undo the inverse
        tape.inv()
        assert tape.trainable_params == {1, 2}
        assert tape.get_parameters() == [p[0], p[1]]
        assert tape._ops == ops
Beispiel #20
0
    def test_graph_creation(self, mocker):
        """Test that the circuit graph is correctly created"""
        spy = mocker.spy(NewCircuitGraph, "__init__")

        with QuantumTape() as tape:
            op = qml.RX(1.0, wires=0)
            obs = qml.PauliZ(1)
            expval(obs)

        # graph has not yet been created
        assert tape._graph is None
        spy.assert_not_called()

        # requesting the graph creates it
        g = tape.graph
        assert g.operations == [op]
        assert g.observables == [obs]
        assert tape._graph is not None
        spy.assert_called_once()

        # calling the graph property again does
        # not reconstruct the graph
        g2 = tape.graph
        assert g2 is g
        spy.assert_called_once()
Beispiel #21
0
    def test_inverse(self):
        """Test that inversion works as expected"""
        init_state = np.array([1, 1])
        p = [0.1, 0.2, 0.3, 0.4]

        with QuantumTape() as tape:
            prep = qml.BasisState(init_state, wires=[0, "a"])
            ops = [
                qml.RX(p[0], wires=0),
                qml.Rot(*p[1:], wires=0).inv(),
                qml.CNOT(wires=[0, "a"])
            ]
            m1 = probs(wires=0)
            m2 = probs(wires="a")

        tape.inv()

        # check that operation order is reversed
        assert tape.operations == [prep] + ops[::-1]

        # check that operations are inverted
        assert ops[0].inverse
        assert not ops[1].inverse
        assert ops[2].inverse

        # check that parameter order has reversed
        print(tape.get_parameters())
        print([init_state, p[1], p[2], p[3], p[0]])
        assert tape.get_parameters() == [init_state, p[1], p[2], p[3], p[0]]
Beispiel #22
0
    def test_observable_with_no_measurement(self):
        """Test that an exception is raised if an observable is used without a measurement"""

        with pytest.raises(ValueError,
                           match="does not have a measurement type specified"):
            with QuantumTape() as tape:
                qml.RX(0.5, wires=0)
                qml.Hermitian(np.array([[0, 1], [1, 0]]), wires=1)
                expval(qml.PauliZ(wires=1))

        with pytest.raises(ValueError,
                           match="does not have a measurement type specified"):
            with QuantumTape() as tape:
                qml.RX(0.5, wires=0)
                qml.PauliX(wires=0) @ qml.PauliY(wires=1)
                expval(qml.PauliZ(wires=1))
Beispiel #23
0
    def test_multiple_contexts(self):
        """Test multiple contexts with a single tape."""
        ops = []
        obs = []

        with QuantumTape() as tape:
            ops += [qml.RX(0.432, wires=0)]

        a = qml.Rot(0.543, 0, 0.23, wires=1)
        b = qml.CNOT(wires=[2, "a"])

        with tape:
            ops += [qml.RX(0.133, wires=0)]
            obs += [qml.PauliX(wires="a")]
            expval(obs[0])
            obs += [probs(wires=[0, "a"])]

        assert len(tape.queue) == 5
        assert tape.operations == ops
        assert tape.observables == obs
        assert tape.output_dim == 5

        assert a not in tape.operations
        assert b not in tape.operations

        assert tape.wires == qml.wires.Wires([0, "a"])
Beispiel #24
0
    def test_depth_expansion(self):
        """Test expanding with depth=2"""
        with QuantumTape() as tape:
            # Will be decomposed into PauliX(0), PauliX(0)
            # Each PauliX will then be decomposed into PhaseShift, RX, PhaseShift.
            qml.BasisState(np.array([1, 1]), wires=[0, "a"])

            with QuantumTape() as tape2:
                # will be decomposed into a RZ, RY, RZ
                qml.Rot(0.543, 0.1, 0.4, wires=0)

            qml.CNOT(wires=[0, "a"])
            qml.RY(0.2, wires="a")
            probs(wires=0), probs(wires="a")

        new_tape = tape.expand(depth=2)
        assert len(new_tape.operations) == 11
        def cost(a, device):
            with AutogradInterface.apply(QuantumTape()) as qtape:
                qml.RY(a[0], wires=0)
                qml.RX(a[1], wires=0)
                expval(qml.PauliZ(0))

            qtape.jacobian_options = {"h": 1e-8, "order": 2}
            return qtape.execute(dev)
    def test_interface_str(self):
        """Test that the interface string is correctly identified as autograd"""
        with AutogradInterface.apply(QuantumTape()) as tape:
            qml.RX(0.5, wires=0)
            expval(qml.PauliX(0))

        assert tape.interface == "autograd"
        assert isinstance(tape, AutogradInterface)
        def cost(x, device):
            with AutogradInterface.apply(QuantumTape()) as tape:
                qml.Hadamard(wires=[0])
                qml.CNOT(wires=[0, 1])
                sample(qml.PauliZ(0))
                sample(qml.PauliX(1))

            return tape.execute(device)
Beispiel #28
0
 def test_state_preparation_error(self):
     """Test that an exception is raised if a state preparation comes
     after a quantum operation"""
     with pytest.raises(ValueError,
                        match="must occur prior to any quantum"):
         with QuantumTape() as tape:
             B = qml.PauliX(wires=0)
             qml.BasisState(np.array([0, 1]), wires=[0, 1])
        def cost(x, device):
            with QuantumTape() as tape:
                qml.Hadamard(wires=[0])
                qml.CNOT(wires=[0, 1])
                sample(qml.PauliZ(0))
                sample(qml.PauliX(1))

            return tape.execute(device)
Beispiel #30
0
def get_tape(caching):
    """Creates a simple quantum tape"""
    with QuantumTape(caching=caching) as tape:
        qml.QubitUnitary(np.eye(2), wires=0)
        qml.RX(0.1, wires=0)
        qml.RX(0.2, wires=1)
        qml.CNOT(wires=[0, 1])
        expval(qml.PauliZ(wires=1))
    return tape