def test_tf(self, tol):
        """Tests that the output of the parameter-shift CV transform
        can be executed using TF"""
        tf = pytest.importorskip("tensorflow")
        from pennylane.interfaces.tf import TFInterface

        dev = qml.device("default.gaussian", wires=1)
        params = tf.Variable([0.543, -0.654], dtype=tf.float64)

        with tf.GradientTape() as t:
            with TFInterface.apply(qml.tape.CVParamShiftTape()) as tape:
                qml.Squeezing(params[0], 0, wires=0)
                qml.Rotation(params[1], wires=0)
                qml.var(qml.X(wires=[0]))

            tapes, fn = qml.gradients.param_shift_cv(tape, dev)
            jac = fn([tp.execute(dev) for tp in tapes])
            res = jac[0, 1]

        r, phi = 1.0 * params

        expected = np.array([
            2 * np.exp(2 * r) * np.sin(phi)**2 -
            2 * np.exp(-2 * r) * np.cos(phi)**2,
            2 * np.sinh(2 * r) * np.sin(2 * phi),
        ])
        assert np.allclose(jac, expected, atol=tol, rtol=0)

        grad = t.jacobian(res, params)
        expected = np.array([
            4 * np.cosh(2 * r) * np.sin(2 * phi),
            4 * np.cos(2 * phi) * np.sinh(2 * r)
        ])
        assert np.allclose(grad, expected, atol=tol, rtol=0)
Beispiel #2
0
    def test_jacobian(self, mocker, tol):
        """Test jacobian calculation"""
        spy = mocker.spy(JacobianTape, "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(JacobianTape()) as qtape:
                qml.RY(a, wires=0)
                qml.RX(b, wires=1)
                qml.CNOT(wires=[0, 1])
                qml.expval(qml.PauliZ(0))
                qml.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 #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 = tf.Variable(0.543, dtype=tf.float64)
        y = tf.Variable(-0.654, dtype=tf.float64)

        with tf.GradientTape() as tape:
            with TFInterface.apply(JacobianTape()) as qtape:
                qml.RX(x, wires=[0])
                qml.RY(y, wires=[1])
                qml.CNOT(wires=[0, 1])
                qml.expval(qml.PauliZ(0))
                qml.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 #4
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(JacobianTape(), dtype=tf.float32) as qtape:
                qml.RY(a, wires=0)
                qml.RX(b, wires=1)
                qml.CNOT(wires=[0, 1])
                qml.expval(qml.PauliZ(0))
                qml.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 #5
0
    def test_repeated_interface_construction(self):
        """Test that the interface is correctly applied multiple times"""
        with TFInterface.apply(JacobianTape()) as tape:
            qml.RX(0.5, wires=0)
            qml.expval(qml.PauliX(0))

        assert tape.interface == "tf"
        assert isinstance(tape, TFInterface)
        assert tape.__bare__ == JacobianTape
        assert tape.dtype is tf.float64

        TFInterface.apply(tape, dtype=tf.float32)
        assert tape.interface == "tf"
        assert isinstance(tape, TFInterface)
        assert tape.__bare__ == JacobianTape
        assert tape.dtype is tf.float32
    def test_hamiltonian_dif_tensorflow(self):
        """Tests that the hamiltonian_expand tape transform is differentiable with the Tensorflow interface"""

        tf = pytest.importorskip("tensorflow")
        from pennylane.interfaces.tf import TFInterface

        H = qml.Hamiltonian(
            [-0.2, 0.5, 1],
            [qml.PauliX(1),
             qml.PauliZ(1) @ qml.PauliY(2),
             qml.PauliZ(0)])
        var = tf.Variable([[0.1, 0.67, 0.3], [0.4, -0.5, 0.7]],
                          dtype=tf.float64)
        output = 0.42294409781940356
        output2 = [
            9.68883500e-02,
            -2.90832724e-01,
            -1.04448033e-01,
            -1.94289029e-09,
            3.50307411e-01,
            -3.41123470e-01,
        ]

        with tf.GradientTape() as gtape:
            with qml.tape.JacobianTape() as tape:
                for i in range(2):
                    qml.RX(var[i, 0], wires=0)
                    qml.RX(var[i, 1], wires=1)
                    qml.RX(var[i, 2], wires=2)
                    qml.CNOT(wires=[0, 1])
                    qml.CNOT(wires=[1, 2])
                    qml.CNOT(wires=[2, 0])
                qml.expval(H)

            TFInterface.apply(tape)
            tapes, fn = qml.transforms.hamiltonian_expand(tape)
            res = fn([t.execute(dev) for t in tapes])

            assert np.isclose(res, output)

            g = gtape.gradient(res, var)
            assert np.allclose(list(g[0]) + list(g[1]), output2)
Beispiel #7
0
    def test_differentiable_expand(self, tol):
        """Test that operation and nested tapes expansion
        is differentiable"""
        class U3(qml.U3):
            def expand(self):
                tape = JacobianTape()
                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 = JacobianTape()

        dev = qml.device("default.qubit", 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)
                qml.expval(qml.PauliX(0))

            qtape = TFInterface.apply(qtape.expand())

            assert qtape.trainable_params == [1, 2, 3, 4]
            assert [i.name
                    for i in qtape.operations] == ["RX", "Rot", "PhaseShift"]
            assert np.all(
                qtape.get_parameters() == [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)
Beispiel #8
0
    def to_tf(self, dtype=None):
        """Apply the TensorFlow interface to the internal quantum tape.

        Args:
            dtype (tf.dtype): The dtype that the TensorFlow QNode should
                output. If not provided, the default is ``tf.float64``.

        Raises:
            .QuantumFunctionError: if TensorFlow >= 2.1 is not installed
        """
        # pylint: disable=import-outside-toplevel
        try:
            import tensorflow as tf
            from pennylane.interfaces.tf import TFInterface

            if self.interface != "tf" and self.interface is not None:
                # Since the interface is changing, need to re-validate the tape class.
                self._tape, interface, self.device, diff_options = self.get_tape(
                    self._original_device, "tf", self.diff_method
                )

                self.interface = interface
                self.diff_options.update(diff_options)
            else:
                self.interface = "tf"

            if not isinstance(self.dtype, tf.DType):
                self.dtype = None

            self.dtype = dtype or self.dtype or TFInterface.dtype

            if self.qtape is not None:
                TFInterface.apply(self.qtape, dtype=tf.as_dtype(self.dtype))

        except ImportError as e:
            raise qml.QuantumFunctionError(
                "TensorFlow not found. Please install the latest "
                "version of TensorFlow to enable the 'tf' interface."
            ) from e
Beispiel #9
0
    def test_sampling(self):
        """Test sampling works as expected"""
        dev = qml.device("default.qubit", wires=2, shots=10)

        with tf.GradientTape() as tape:
            with TFInterface.apply(JacobianTape()) as qtape:
                qml.Hadamard(wires=[0])
                qml.CNOT(wires=[0, 1])
                qml.sample(qml.PauliZ(0))
                qml.sample(qml.PauliX(1))

            res = qtape.execute(dev)

        assert res.shape == (2, 10)
        assert isinstance(res, tf.Tensor)
Beispiel #10
0
    def test_execution(self):
        """Test execution"""
        a = tf.Variable(0.1)
        dev = qml.device("default.qubit", wires=1)

        with tf.GradientTape() as tape:
            with TFInterface.apply(JacobianTape()) as qtape:
                qml.RY(a, wires=0)
                qml.RX(0.2, wires=0)
                qml.expval(qml.PauliZ(0))

            assert qtape.trainable_params == [0]
            res = qtape.execute(dev)

        assert isinstance(res, tf.Tensor)
        assert res.shape == (1, )
Beispiel #11
0
    def test_get_parameters(self):
        """Test that the get parameters function correctly sets and returns the
        trainable parameters"""
        a = tf.Variable(0.1)
        b = tf.constant(0.2)
        c = tf.Variable(0.3)
        d = 0.4

        with tf.GradientTape() as tape:
            with TFInterface.apply(JacobianTape()) as qtape:
                qml.Rot(a, b, c, wires=0)
                qml.RX(d, wires=1)
                qml.CNOT(wires=[0, 1])
                qml.expval(qml.PauliX(0))

        assert qtape.trainable_params == [0, 2]
        assert np.all(qtape.get_parameters() == [a, c])
Beispiel #12
0
    def test_no_trainable_parameters(self, tol):
        """Test evaluation if there are no trainable parameters"""
        dev = qml.device("default.qubit", wires=2)

        with tf.GradientTape() as tape:

            with TFInterface.apply(JacobianTape()) as qtape:
                qml.RY(0.2, wires=0)
                qml.RX(tf.constant(0.1), wires=0)
                qml.CNOT(wires=[0, 1])
                qml.expval(qml.PauliZ(0))
                qml.expval(qml.PauliZ(1))

            assert qtape.trainable_params == []

            res = qtape.execute(dev)

        assert res.shape == (2, )
        assert isinstance(res, tf.Tensor)
Beispiel #13
0
    def test_matrix_parameter(self, U, tol):
        """Test that the TF interface works correctly
        with a matrix parameter"""
        a = tf.Variable(0.1, dtype=tf.float64)

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

        with tf.GradientTape() as tape:

            with TFInterface.apply(JacobianTape()) as qtape:
                qml.QubitUnitary(U, wires=0)
                qml.RY(a, wires=0)
                qml.expval(qml.PauliZ(0))

            assert qtape.trainable_params == [1]
            res = qtape.execute(dev)

        assert np.allclose(res, -tf.cos(a), atol=tol, rtol=0)

        res = tape.jacobian(res, a)
        assert np.allclose(res, tf.sin(a), atol=tol, rtol=0)
Beispiel #14
0
    def test_jacobian_options(self, mocker, tol):
        """Test setting jacobian options"""
        spy = mocker.spy(JacobianTape, "numeric_pd")

        a = tf.Variable([0.1, 0.2])

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

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

            res = qtape.execute(dev)

        qtape.jacobian_options = {"h": 1e-8, "order": 2}
        tape.jacobian(res, a)

        for args in spy.call_args_list:
            assert args[1]["order"] == 2
            assert args[1]["h"] == 1e-8
Beispiel #15
0
    def test_reusing_pre_constructed_quantum_tape(self, tol):
        """Test re-using a quantum tape that was previously constructed
        *outside of* a gradient tape, by passing new parameters"""
        a = tf.Variable(0.1, dtype=tf.float64)
        b = tf.Variable(0.2, dtype=tf.float64)

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

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

        with tf.GradientTape() as tape:
            qtape.set_parameters([a, b], trainable_only=False)
            qtape._update_trainable_params()
            assert qtape.trainable_params == [0, 1]
            res = qtape.execute(dev)

        jac = tape.jacobian(res, [a, b])

        a = tf.Variable(0.54, dtype=tf.float64)
        b = tf.Variable(0.8, dtype=tf.float64)

        with tf.GradientTape() as tape:
            res2 = qtape.execute(dev, params=[2 * a, b])

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

        jac2 = tape.jacobian(res2, [a, b])
        expected = [
            [-2 * tf.sin(2 * a), 2 * tf.sin(2 * a) * tf.sin(b)],
            [0, -tf.cos(2 * a) * tf.cos(b)],
        ]
        assert np.allclose(jac2, expected, atol=tol, rtol=0)
Beispiel #16
0
    def test_classical_processing(self, tol):
        """Test classical processing within the quantum tape"""
        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", wires=1)

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

            assert qtape.trainable_params == [0, 2]
            assert qtape.get_parameters() == [a * c, 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)