예제 #1
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)
        ]
예제 #2
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)
예제 #3
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)
예제 #4
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]]
예제 #5
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
        def cost(x, y, device):
            with 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])

            return tape.execute(device)
        def cost(x, y, device):
            with AutogradInterface.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])

            return tape.execute(device)
예제 #8
0
    def test_probability(self):
        """Probability is the expectation value of a
        higher order observable, and thus only supports numerical
        differentiation"""
        with CVParamShiftTape() as tape:
            qml.Rotation(0.543, wires=[0])
            qml.Squeezing(0.543, 0, wires=[0])
            probs(wires=0)

        assert tape._grad_method(0) == "F"
        assert tape._grad_method(1) == "F"
        assert tape._grad_method(2) == "F"
예제 #9
0
    def test_stopping_criterion(self):
        """Test that gates specified in the stop_at
        argument are not expanded."""
        with QuantumTape() as tape:
            qml.U3(0, 1, 2, wires=0)
            qml.Rot(3, 4, 5, wires=0)
            probs(wires=0), probs(wires="a")

        new_tape = tape.expand(stop_at=lambda obj: obj.name in ["Rot"])
        assert len(new_tape.operations) == 4
        assert "Rot" in [i.name for i in new_tape.operations]
        assert not "U3" in [i.name for i in new_tape.operations]
예제 #10
0
    def make_tape(self):
        params = [0.432, 0.123, 0.546, 0.32, 0.76]

        with QuantumTape() as tape:
            qml.RX(params[0], wires=0)
            qml.Rot(*params[1:4], wires=0)
            qml.CNOT(wires=[0, "a"])
            qml.RX(params[4], wires=4)
            expval(qml.PauliX(wires="a"))
            probs(wires=[0, "a"])

        return tape, params
예제 #11
0
    def test_probs_exception(self):
        """Tests that an exception is raised when probability
        is used with the ReversibleTape."""
        # TODO: remove this test when this support is added
        dev = qml.device("default.qubit", wires=2)

        with ReversibleTape() as tape:
            qml.PauliX(wires=0)
            qml.RX(0.542, wires=0)
            probs(wires=[0, 1])

        with pytest.raises(ValueError, match="Probability is not supported"):
            tape.jacobian(dev)
예제 #12
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
예제 #13
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"])
예제 #14
0
    def test_finite_diff(self, monkeypatch):
        """If an op has grad_method=F, this should be respected
        by the QubitParamShiftTape"""
        monkeypatch.setattr(qml.RX, "grad_method", "F")

        psi = np.array([1, 0, 1, 0]) / np.sqrt(2)

        with QubitParamShiftTape() as tape:
            qml.QubitStateVector(psi, wires=[0, 1])
            qml.RX(0.543, wires=[0])
            qml.RY(-0.654, wires=[1])
            qml.CNOT(wires=[0, 1])
            probs(wires=[0, 1])

        assert tape._grad_method(0) is None
        assert tape._grad_method(1) == "F"
        assert tape._grad_method(2) == "A"
예제 #15
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
예제 #16
0
    def test_ragged_differentiation(self, monkeypatch, tol):
        """Tests correct output shape and evaluation for a tape
        with prob and expval outputs"""
        dev = qml.device("default.qubit.tf", wires=2)
        x = tf.Variable(0.543, dtype=tf.float64)
        y = tf.Variable(-0.654, dtype=tf.float64)

        def _asarray(args, dtype=tf.float64):
            res = [tf.reshape(i, [-1]) for i in args]
            res = tf.concat(res, axis=0)
            return tf.cast(res, dtype=dtype)

        # The current DefaultQubitTF device provides an _asarray method that does
        # not work correctly for ragged arrays. For ragged arrays, we would like _asarray to
        # flatten the array. Here, we patch the _asarray method on the device to achieve this
        # behaviour; once the tape has moved from the beta folder, we should implement
        # this change directly in the device.
        monkeypatch.setattr(dev, "_asarray", _asarray)

        with tf.GradientTape() as tape:
            with 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)
예제 #17
0
    def test_stopping_criterion_with_depth(self):
        """Test that gates specified in the stop_at
        argument are not expanded."""
        with QuantumTape() as tape:
            # Will be decomposed into PauliX(0), PauliX(0)
            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,
                               stop_at=lambda obj: obj.name in ["PauliX"])
        assert len(new_tape.operations) == 7
예제 #18
0
    def test_non_differentiable(self):
        """Test that a non-differentiable parameter is
        correctly marked"""
        psi = np.array([1, 0, 1, 0]) / np.sqrt(2)

        with QubitParamShiftTape() as tape:
            qml.QubitStateVector(psi, wires=[0, 1])
            qml.RX(0.543, wires=[0])
            qml.RY(-0.654, wires=[1])
            qml.CNOT(wires=[0, 1])
            probs(wires=[0, 1])

        assert tape._grad_method(0) is None
        assert tape._grad_method(1) == "A"
        assert tape._grad_method(2) == "A"

        tape._update_gradient_info()

        assert tape._par_info[0]["grad_method"] is None
        assert tape._par_info[1]["grad_method"] == "A"
        assert tape._par_info[2]["grad_method"] == "A"
예제 #19
0
    def test_probability_differentiation(self, tol):
        """Tests correct output shape and evaluation for a tape
        with multiple prob outputs"""

        dev = qml.device("default.qubit.tf", wires=2)
        x = tf.Variable(0.543, dtype=tf.float64)
        y = tf.Variable(-0.654, dtype=tf.float64)

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

            res = qtape.execute(dev)

        expected = np.array([
            [tf.cos(x / 2)**2, tf.sin(x / 2)**2],
            [(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) / 2, tf.sin(x) / 2],
                [-tf.sin(x) * tf.cos(y) / 2,
                 tf.cos(y) * tf.sin(x) / 2],
            ],
            [
                [0, 0],
                [-tf.cos(x) * tf.sin(y) / 2,
                 tf.cos(x) * tf.sin(y) / 2],
            ],
        ])
        assert np.allclose(res, expected, atol=tol, rtol=0)
예제 #20
0
    def test_prob_expectation_values(self, tol):
        """Tests correct output shape and evaluation for a tape
        with prob and expval outputs"""
        dev = qml.device("default.qubit", wires=2)
        x = 0.543
        y = -0.654

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

        res = tape.jacobian(dev, method="analytic")
        assert res.shape == (5, 2)

        expected = (np.array([
            [-2 * np.sin(x), 0],
            [
                -(np.cos(y / 2)**2 * np.sin(x)),
                -(np.cos(x / 2)**2 * np.sin(y)),
            ],
            [
                -(np.sin(x) * np.sin(y / 2)**2),
                (np.cos(x / 2)**2 * np.sin(y)),
            ],
            [
                (np.sin(x) * np.sin(y / 2)**2),
                (np.sin(x / 2)**2 * np.sin(y)),
            ],
            [
                (np.cos(y / 2)**2 * np.sin(x)),
                -(np.sin(x / 2)**2 * np.sin(y)),
            ],
        ]) / 2)

        assert np.allclose(res, expected, atol=tol, rtol=0)
예제 #21
0
    def make_tape(self):
        ops = []
        obs = []

        with QuantumTape() as tape:
            ops += [qml.RX(0.432, wires=0)]
            ops += [qml.Rot(0.543, 0, 0.23, wires=0)]
            ops += [qml.CNOT(wires=[0, "a"])]
            ops += [qml.RX(0.133, wires=4)]
            obs += [qml.PauliX(wires="a")]
            expval(obs[0])
            obs += [probs(wires=[0, "a"])]

        return tape, ops, obs
예제 #22
0
 def circuit(x, y):
     qml.RX(x, wires=[0])
     qml.RY(y, wires=[1])
     qml.CNOT(wires=[0, 1])
     return [expval(qml.PauliZ(0)), probs(wires=[1])]
예제 #23
0
 def circuit(x, y):
     qml.RX(x, wires=[0])
     qml.RY(y, wires=[1])
     qml.CNOT(wires=[0, 1])
     return probs(wires=[0]), probs(wires=[1])
예제 #24
0
 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)