Python autograd.jacobian() Examples

The following are 23 code examples of autograd.jacobian(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module autograd , or try the search function .
Example #1
Source File: __init__.py    From pennylane with Apache License 2.0 7 votes vote down vote up
def jacobian(func, argnum):
    """Returns the Jacobian as a callable function of vector-valued
    (functions of) QNodes.

    This is a wrapper around the :mod:`autograd.jacobian` function.

    Args:
        func (function): a vector-valued Python function or QNode that contains
            a combination of quantum and classical nodes. The output of the computation
            must consist of a single NumPy array (if classical) or a tuple of
            expectation values (if a quantum node)
        argnum (int or Sequence[int]): which argument to take the gradient
            with respect to. If a sequence is given, the Jacobian matrix
            corresponding to all input elements and all output elements is returned.

    Returns:
        function: the function that returns the Jacobian of the input
        function with respect to the arguments in argnum
    """
    # pylint: disable=no-value-for-parameter
    if isinstance(argnum, int):
        return _jacobian(func, argnum)
    return lambda *args, **kwargs: _np.stack(
        [_jacobian(func, arg)(*args, **kwargs) for arg in argnum]
    ).T 
Example #2
Source File: test_autograd.py    From pennylane with Apache License 2.0 6 votes vote down vote up
def test_multiple_expectation_jacobian_array(self, tol, qubit_device_2_wires):
        """Tests that qnodes using an array argument return correct gradients
        for multiple expectation values."""
        par = np.array([0.5, 0.54, 0.3])

        def circuit(weights):
            qml.QubitStateVector(np.array([1, 0, 1, 1]) / np.sqrt(3), wires=[0, 1])
            qml.Rot(weights[0], weights[1], weights[2], wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1))

        circuit = to_autograd(QubitQNode(circuit, qubit_device_2_wires))

        expected_jac = self.expected_jacobian(*par)
        res = circuit.jacobian([par])
        assert expected_jac == pytest.approx(res, abs=tol)

        jac = autograd.jacobian(circuit, 0)
        res = jac(par)
        assert expected_jac == pytest.approx(res, abs=tol) 
Example #3
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 6 votes vote down vote up
def test_cv_gradient_fanout(self, gaussian_dev, tol):
        "Tests that qnodes can compute the correct gradient when the same parameter is used in multiple gates."
        par = [0.5, 1.3]

        def circuit(x, y):
            qml.Displacement(x, 0, wires=[0])
            qml.Rotation(y, wires=[0])
            qml.Displacement(0, x, wires=[0])
            return qml.expval(qml.X(0))

        q = qml.QNode(circuit, gaussian_dev)
        grad_F = q.jacobian(par, method='F')
        grad_A = q.jacobian(par, method='A')
        grad_A2 = q.jacobian(par, method='A', options={"force_order2": True})

        # analytic method works for every parameter
        assert q.par_to_grad_method == {0:'A', 1:'A'}
        # the different methods agree
        assert grad_A == pytest.approx(grad_F, abs=tol)
        assert grad_A2 == pytest.approx(grad_F, abs=tol) 
Example #4
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 6 votes vote down vote up
def test_cv_gradients_repeated_gate_parameters(self, gaussian_dev, tol):
        "Tests that repeated use of a free parameter in a multi-parameter gate yield correct gradients."
        par = [0.2, 0.3]

        def qf(x, y):
            qml.Displacement(x, 0, wires=[0])
            qml.Squeezing(y, -1.3*y, wires=[0])
            return qml.expval(qml.X(0))

        q = qml.QNode(qf, gaussian_dev)
        grad_F = q.jacobian(par, method='F')
        grad_A = q.jacobian(par, method='A')
        grad_A2 = q.jacobian(par, method='A', options={"force_order2": True})

        # analytic method works for every parameter
        assert q.par_to_grad_method == {0:'A', 1:'A'}
        # the different methods agree
        assert grad_A == pytest.approx(grad_F, abs=tol)
        assert grad_A2 == pytest.approx(grad_F, abs=tol) 
Example #5
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 6 votes vote down vote up
def test_cv_gradients_parameters_inside_array(self, gaussian_dev, tol):
        "Tests that free parameters inside an array passed to an Operation yield correct gradients."
        par = [0.4, 1.3]

        def qf(x, y):
            qml.Displacement(0.5, 0, wires=[0])
            qml.Squeezing(x, 0, wires=[0])
            M = np.zeros((5, 5), dtype=object)
            M[1,1] = y
            M[1,2] = 1.0
            M[2,1] = 1.0
            return qml.expval(qml.PolyXP(M, [0, 1]))

        q = qml.QNode(qf, gaussian_dev)
        grad = q.jacobian(par)
        grad_F = q.jacobian(par, method='F')
        grad_A = q.jacobian(par, method="best")
        grad_A2 = q.jacobian(par, method="best", options={"force_order2": True})

        # par[0] can use the 'A' method, par[1] cannot
        assert q.par_to_grad_method == {0:'A', 1:'F'}
        # the different methods agree
        assert grad == pytest.approx(grad_F, abs=tol) 
Example #6
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_cv_gradients_gaussian_circuit(self, G, O, gaussian_dev, tol):
        """Tests that the gradients of circuits of gaussian gates match between the finite difference and analytic methods."""

        tol = 1e-5
        par = [0.4]
        def circuit(x):
            args = [0.3] * G.num_params
            args[0] = x
            qml.Displacement(0.5, 0, wires=0)
            G(*args, wires=range(G.num_wires))
            qml.Beamsplitter(1.3, -2.3, wires=[0, 1])
            qml.Displacement(-0.5, 0.1, wires=0)
            qml.Squeezing(0.5, -1.5, wires=0)
            qml.Rotation(-1.1, wires=0)
            return qml.expval(O(wires=0))

        q = qml.QNode(circuit, gaussian_dev)
        val = q.evaluate(par, {})

        grad_F  = q.jacobian(par, method='F')
        grad_A2 = q.jacobian(par, method='A', options={"force_order2": True})
        if O.ev_order == 1:
            grad_A = q.jacobian(par, method='A')
            # the different methods agree
            assert grad_A == pytest.approx(grad_F, abs=tol)

        # analytic method works for every parameter
        assert q.par_to_grad_method == {0:'A'}
        # the different methods agree
        assert grad_A2 == pytest.approx(grad_F, abs=tol) 
Example #7
Source File: test_jacobian.py    From autograd with MIT License 5 votes vote down vote up
def test_jacobian_higher_order():
    fun = lambda x: np.sin(np.outer(x,x)) + np.cos(np.dot(x,x))

    assert jacobian(fun)(npr.randn(2)).shape == (2,2,2)
    assert jacobian(jacobian(fun))(npr.randn(2)).shape == (2,2,2,2)
    # assert jacobian(jacobian(jacobian(fun)))(npr.randn(2)).shape == (2,2,2,2,2)

    check_grads(lambda x: np.sum(np.sin(jacobian(fun)(x))))(npr.randn(2))
    check_grads(lambda x: np.sum(np.sin(jacobian(jacobian(fun))(x))))(npr.randn(2)) 
Example #8
Source File: test_jacobian.py    From autograd with MIT License 5 votes vote down vote up
def test_jacobian_against_stacked_grads():
    scalar_funs = [
        lambda x: np.sum(x**3),
        lambda x: np.prod(np.sin(x) + np.sin(x)),
        lambda x: grad(lambda y: np.exp(y) * np.tanh(x[0]))(x[1])
    ]

    vector_fun = lambda x: np.array([f(x) for f in scalar_funs])

    x = npr.randn(5)
    jac = jacobian(vector_fun)(x)
    grads = [grad(f)(x) for f in scalar_funs]

    assert np.allclose(jac, np.vstack(grads)) 
Example #9
Source File: test_jacobian.py    From autograd with MIT License 5 votes vote down vote up
def test_jacobian_scalar_to_vector():
    fun = lambda x: np.array([x, x**2, x**3])
    val = npr.randn()
    assert np.allclose(jacobian(fun)(val), np.array([1., 2*val, 3*val**2])) 
Example #10
Source File: test_jacobian.py    From autograd with MIT License 5 votes vote down vote up
def test_jacobian_against_grad():
    fun = lambda x: np.sum(np.sin(x), axis=1, keepdims=True)
    A = npr.randn(1,3)
    assert np.allclose(grad(fun)(A), jacobian(fun)(A)) 
Example #11
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_gradient_exception_on_sample(self, qubit_device_2_wires):
        """Tests that the proper exception is raised if differentiation of sampling is attempted."""

        @qml.qnode(qubit_device_2_wires)
        def circuit(x):
            qml.RX(x, wires=[0])
            return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliX(1))

        with pytest.raises(qml.QuantumFunctionError,
                           match="Circuits that include sampling can not be differentiated."):
            grad_fn = autograd.jacobian(circuit)
            grad_fn(1.0) 
Example #12
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_hybrid_gradients_autograd_numpy(self, qubit_device_2_wires, tol):
        "Test the gradient of a hybrid computation requiring autograd.numpy functions."

        def circuit(x, y):
            "Quantum node."
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(y, wires=[0])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        quantum = qml.QNode(circuit, qubit_device_2_wires)

        def classical(p):
            "Classical node, requires autograd.numpy functions."
            return anp.exp(anp.sum(quantum(p[0], anp.log(p[1]))))

        def d_classical(a, b, method):
            "Gradient of classical computed symbolically, can use normal numpy functions."
            val = classical((a, b))
            J = quantum.jacobian((a, np.log(b)), method=method)
            return val * np.array([J[0, 0] + J[1, 0], (J[0, 1] + J[1, 1]) / b])

        param = np.array([-0.1259, 1.53])
        y0 = classical(param)
        grad_classical = autograd.jacobian(classical)
        grad_auto = grad_classical(param)

        grad_fd1 = d_classical(*param, 'F')
        grad_angle = d_classical(*param, 'A')

        # gradients computed with different methods must agree
        assert grad_fd1 == pytest.approx(grad_angle, abs=tol)
        assert grad_fd1 == pytest.approx(grad_auto, abs=tol)
        assert grad_angle == pytest.approx(grad_auto, abs=tol) 
Example #13
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_qfunc_gradients(self, qubit_device_2_wires, tol):
        "Tests that the various ways of computing the gradient of a qfunc all agree."

        def circuit(x, y, z):
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(-1.6, wires=[0])
            qml.RY(y, wires=[1])
            qml.CNOT(wires=[1, 0])
            qml.RX(z, wires=[0])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        qnode = qml.QNode(circuit, qubit_device_2_wires)
        params = np.array([0.1, -1.6, np.pi / 5])

        # manual gradients
        grad_fd1 = qnode.jacobian(params, method='F', options={"order": 1})
        grad_fd2 = qnode.jacobian(params, method='F', options={"order": 2})
        grad_angle = qnode.jacobian(params, method='A')

        # automatic gradient
        # Note: the lambda function is required as evaluate now receives a required `kwargs` argument
        # that cannot be differentiated by autograd.
        grad_fn = autograd.grad(lambda x: qnode.evaluate(x, {}))
        grad_auto = grad_fn(params)[np.newaxis, :]  # so shapes will match

        # gradients computed with different methods must agree
        assert grad_fd1 == pytest.approx(grad_fd2, abs=tol)
        assert grad_fd1 == pytest.approx(grad_angle, abs=tol)
        assert grad_fd1 == pytest.approx(grad_auto, abs=tol) 
Example #14
Source File: test_quantum_gradients.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_CVOperation_with_heisenberg_and_no_params(self, name, gaussian_dev, tol):
        """An integration test for CV gates that support analytic differentiation
        if succeeding the gate to be differentiated, but cannot be differentiated
        themselves (for example, they may be Gaussian but accept no parameters).

        This ensures that, assuming their _heisenberg_rep is defined, the quantum
        gradient analytic method can still be used, and returns the correct result.
        """

        cls = getattr(qml.ops, name)
        if cls.supports_heisenberg and (not cls.supports_parameter_shift):
            U = np.array([[0.51310276+0.81702166j, 0.13649626+0.22487759j],
                          [0.26300233+0.00556194j, -0.96414101-0.03508489j]])

            if cls.num_wires <= 0:
                w = list(range(2))
            else:
                w = list(range(cls.num_wires))

            def circuit(x):
                qml.Displacement(x, 0, wires=0)

                if cls.par_domain == 'A':
                    cls(U, wires=w)
                else:
                    cls(wires=w)
                return qml.expval(qml.X(0))

            qnode = qml.QNode(circuit, gaussian_dev)
            grad_F = qnode.jacobian(0.5, method='F')
            grad_A = qnode.jacobian(0.5, method='A')
            grad_A2 = qnode.jacobian(0.5, method='A', options={"force_order2": True})

            # par[0] can use the 'A' method
            assert qnode.par_to_grad_method == {0: 'A'}

            # the different methods agree
            assert grad_A == pytest.approx(grad_F, abs=tol)
            assert grad_A2 == pytest.approx(grad_F, abs=tol) 
Example #15
Source File: likelihood.py    From momi2 with GNU General Public License v3.0 5 votes vote down vote up
def _score_cov(self, params):
        params = np.array(params)

        def f_vec(x):
            ret = self._log_lik(x, vector=True)
            # centralize
            return ret - np.mean(ret)

        j = ag.jacobian(f_vec)(params)
        return np.einsum('ij, ik', j, j) 
Example #16
Source File: test_autograd.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_hybrid_gradients_autograd_numpy(self, qubit_device_2_wires, tol):
        "Test the gradient of a hybrid computation requiring autograd.numpy functions."

        def circuit(x, y):
            "Quantum node."
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(y, wires=[0])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        quantum = to_autograd(QubitQNode(circuit, qubit_device_2_wires))

        def classical(p):
            "Classical node, requires autograd.numpy functions."
            return anp.exp(anp.sum(quantum(p[0], anp.log(p[1]))))

        def d_classical(a, b, method):
            "Gradient of classical computed symbolically, can use normal numpy functions."
            val = classical((a, b))
            J = quantum.jacobian((a, np.log(b)), method=method)
            return val * np.array([J[0, 0] + J[1, 0], (J[0, 1] + J[1, 1]) / b])

        param = np.array([-0.1259, 1.53])
        y0 = classical(param)
        grad_classical = autograd.jacobian(classical)
        grad_auto = grad_classical(param)

        grad_fd1 = d_classical(*param, 'F')
        grad_angle = d_classical(*param, 'A')

        # gradients computed with different methods must agree
        assert grad_fd1 == pytest.approx(grad_angle, abs=tol)
        assert grad_fd1 == pytest.approx(grad_auto, abs=tol)
        assert grad_angle == pytest.approx(grad_auto, abs=tol) 
Example #17
Source File: test_autograd.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_qfunc_gradients(self, qubit_device_2_wires, tol):
        "Tests that the various ways of computing the gradient of a qfunc all agree."

        def circuit(x, y, z):
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(-1.6, wires=[0])
            qml.RY(y, wires=[1])
            qml.CNOT(wires=[1, 0])
            qml.RX(z, wires=[0])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        qnode = to_autograd(QubitQNode(circuit, qubit_device_2_wires))
        params = np.array([0.1, -1.6, np.pi / 5])

        # manual gradients
        grad_fd1 = qnode.jacobian(params, method='F', options={'order': 1})
        grad_fd2 = qnode.jacobian(params, method='F', options={'order': 2})
        grad_angle = qnode.jacobian(params, method='A')

        # automatic gradient
        grad_fn = autograd.grad(qnode, argnum=[0, 1, 2])
        grad_auto = np.array([grad_fn(*params)])

        # gradients computed with different methods must agree
        assert grad_fd1 == pytest.approx(grad_fd2, abs=tol)
        assert grad_fd1 == pytest.approx(grad_angle, abs=tol)
        assert grad_fd1 == pytest.approx(grad_auto, abs=tol) 
Example #18
Source File: test_autograd.py    From pennylane with Apache License 2.0 5 votes vote down vote up
def test_multiple_expectation_jacobian_positional(self, tol, qubit_device_2_wires):
        """Tests that qnodes using positional arguments return
        correct gradients for multiple expectation values."""
        par = [0.5, 0.54, 0.3]

        def circuit(x, y, z):
            qml.QubitStateVector(np.array([1, 0, 1, 1]) / np.sqrt(3), wires=[0, 1])
            qml.Rot(x, y, z, wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1))

        circuit = to_autograd(QubitQNode(circuit, qubit_device_2_wires))

        # compare our manual Jacobian computation to theoretical result
        expected_jac = self.expected_jacobian(*par)
        res = circuit.jacobian(par)
        assert expected_jac == pytest.approx(res, abs=tol)

        # compare our manual Jacobian computation to autograd
        # not sure if this is the intended usage of jacobian
        jac0 = autograd.jacobian(circuit, 0)
        jac1 = autograd.jacobian(circuit, 1)
        jac2 = autograd.jacobian(circuit, 2)
        res = np.stack([jac0(*par), jac1(*par), jac2(*par)]).T

        assert expected_jac == pytest.approx(res, abs=tol)

        #compare with what we get if argnum is a list
        jac = autograd.jacobian(circuit, argnum=[0, 1, 2])
        #res2 = jac(*par)  # FIXME this call gives a TypeError inside Autograd
        #assert res == pytest.approx(res2, abs=tol) 
Example #19
Source File: ddp_gym.py    From ddp-gym with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
def __init__(self, next_state, running_cost, final_cost,
                 umax, state_dim, pred_time=50):
        self.pred_time = pred_time
        self.umax = umax
        self.v = [0.0 for _ in range(pred_time + 1)]
        self.v_x = [np.zeros(state_dim) for _ in range(pred_time + 1)]
        self.v_xx = [np.zeros((state_dim, state_dim)) for _ in range(pred_time + 1)]
        self.f = next_state
        self.lf = final_cost
        self.lf_x = grad(self.lf)
        self.lf_xx = jacobian(self.lf_x)
        self.l_x = grad(running_cost, 0)
        self.l_u = grad(running_cost, 1)
        self.l_xx = jacobian(self.l_x, 0)
        self.l_uu = jacobian(self.l_u, 1)
        self.l_ux = jacobian(self.l_u, 0)
        self.f_x = jacobian(self.f, 0)
        self.f_u = jacobian(self.f, 1)
        self.f_xx = jacobian(self.f_x, 0)
        self.f_uu = jacobian(self.f_u, 1)
        self.f_ux = jacobian(self.f_u, 0) 
Example #20
Source File: test_autograd.py    From pennylane with Apache License 2.0 4 votes vote down vote up
def test_differentiable_parameter_last(self):
        """Test that a differentiable parameter used as the last
        argument is correctly evaluated by QNode.jacobian, and that
        all other non-differentiable parameters are ignored"""
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, interface="autograd")
        def circuit(data1, data2, weights):
            # non-differentiable quantum function
            qml.templates.AmplitudeEmbedding(data1, wires=[0, 1])
            # differentiable quantum function
            qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1])
            # non-differentiable quantum function
            qml.templates.AngleEmbedding(data2, wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        # differentiating the circuit wrt the weights
        grad_fn = qml.grad(circuit)

        # input weights
        weights = qml.init.strong_ent_layers_normal(n_wires=2, n_layers=3)

        # input data
        data1 = qml.numpy.array([0, 1, 1, 0], requires_grad=False) / np.sqrt(2)
        data2 = qml.numpy.array([1, 1], requires_grad=False)

        res = grad_fn(data1, data2, weights)

        # we do not check for correctness, just that the output
        # is the correct shape
        assert len(res) == 1
        assert res[0].shape == weights.shape

        # check that the last arg was marked as non-differentiable
        assert circuit.get_trainable_args() == {2}

        # Check that the parameter shift was not performed for the
        # non-differentiable elements of `data1` and `data2`.
        # First, extract the variable indices that the jacobian method
        # 'skipped' (those with grad_method="0"):
        non_diff_var_indices = sorted([k for k, v in circuit.par_to_grad_method.items() if v == "0"])

        # Check that these indices corresponds to the elements of data1 and data2
        # within the flattenened list [data1, data2, weights]
        assert non_diff_var_indices == [0, 1, 2, 3, 4, 5] 
Example #21
Source File: test_autograd.py    From pennylane with Apache License 2.0 4 votes vote down vote up
def test_differentiable_parameter_middle(self):
        """Test that a differentiable parameter provided as the middle
        argument is correctly evaluated by QNode.jacobian, and that
        all other non-differentiable parameters are ignored"""
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, interface="autograd")
        def circuit(data1, weights, data2):
            # non-differentiable quantum function
            qml.templates.AmplitudeEmbedding(data1, wires=[0, 1])
            # differentiable quantum function
            qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1])
            # non-differentiable quantum function
            qml.templates.AngleEmbedding(data2, wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        # differentiating the circuit wrt the weights
        grad_fn = qml.grad(circuit)

        # input weights
        weights = qml.init.strong_ent_layers_normal(n_wires=2, n_layers=3)

        # input data
        data1 = qml.numpy.array([0, 1, 1, 0], requires_grad=False) / np.sqrt(2)
        data2 = qml.numpy.array([1, 1], requires_grad=False)

        res = grad_fn(data1, weights, data2)

        # we do not check for correctness, just that the output
        # is the correct shape
        assert len(res) == 1
        assert res[0].shape == weights.shape

        # check that the second arg was marked as non-differentiable
        assert circuit.get_trainable_args() == {1}

        # Check that the gradient was not computed for the
        # non-differentiable elements of `data1` and `data2`.
        # First, extract the variable indices that the jacobian method
        # 'skipped' (those with grad_method="0"):
        non_diff_var_indices = sorted([k for k, v in circuit.par_to_grad_method.items() if v == "0"])

        # Check that these indices corresponds to the elements of data1 and data2
        # within the flattenened list [data1, weights, data2]
        assert non_diff_var_indices == [0, 1, 2, 3, 22, 23] 
Example #22
Source File: test_autograd.py    From pennylane with Apache License 2.0 4 votes vote down vote up
def test_differentiable_parameter_first(self):
        """Test that a differentiable parameter used as the first
        argument is correctly evaluated by QNode.jacobian, and that
        all other non-differentiable parameters are ignored"""
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev, interface="autograd")
        def circuit(weights, data1, data2):
            # non-differentiable quantum function
            qml.templates.AmplitudeEmbedding(data1, wires=[0, 1])
            # differentiable quantum function
            qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1])
            # non-differentiable quantum function
            qml.templates.AngleEmbedding(data2, wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        # differentiating the circuit wrt the weights
        grad_fn = qml.grad(circuit)

        # input weights
        weights = qml.init.strong_ent_layers_normal(n_wires=2, n_layers=3)

        # input data
        data1 = qml.numpy.array([0, 1, 1, 0], requires_grad=False) / np.sqrt(2)
        data2 = qml.numpy.array([1, 1], requires_grad=False)

        res = grad_fn(weights, data1, data2)

        # we do not check for correctness, just that the output
        # is the correct shape
        assert len(res) == 1
        assert res[0].shape == weights.shape

        # check that the first arg was marked as non-differentiable
        assert circuit.get_trainable_args() == {0}

        # Check that the gradient was not computed for the
        # non-differentiable elements of `data1` and `data2`.
        # First, extract the variable indices that the jacobian method
        # 'skipped' (those with grad_method="0"):
        non_diff_var_indices = sorted([k for k, v in circuit.par_to_grad_method.items() if v == "0"])

        # Check that these indices corresponds to the elements of data1 and data2
        # within the flattenened list [weights, data1, data2]
        assert non_diff_var_indices == [18, 19, 20, 21, 22, 23] 
Example #23
Source File: test_autograd.py    From pennylane with Apache License 2.0 4 votes vote down vote up
def test_array_parameters_autograd(self, tol, qubit_device_2_wires):
        """Test that gradients of array parameters give
        same results as positional arguments."""

        par = [0.5, 0.54, 0.3]

        def ansatz(x, y, z):
            qml.QubitStateVector(np.array([1, 0, 1, 1]) / np.sqrt(3), wires=[0, 1])
            qml.Rot(x, y, z, wires=0)
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0))

        def circuit1(x, y, z):
            return ansatz(x, y, z)

        def circuit2(x, array):
            return ansatz(x, array[0], array[1])

        def circuit3(array):
            return ansatz(*array)

        circuit1 = to_autograd(QubitQNode(circuit1, qubit_device_2_wires))
        grad1 = autograd.grad(circuit1, argnum=[0, 1, 2])

        # three positional parameters
        jac = circuit1.jacobian(par)
        ag = grad1(*par)
        ag = np.array([ag])
        assert jac == pytest.approx(ag, abs=tol)

        circuit2 = to_autograd(QubitQNode(circuit2, qubit_device_2_wires))
        grad2 = autograd.grad(circuit2, argnum=[0, 1])

        # one scalar, one array
        temp = [par[0], np.array(par[1:])]
        jac = circuit2.jacobian(temp)
        ag = grad2(*temp)
        ag = np.r_[ag][np.newaxis, :]
        assert jac == pytest.approx(ag, abs=tol)

        circuit3 = to_autograd(QubitQNode(circuit3, qubit_device_2_wires))
        grad3 = autograd.grad(circuit3, argnum=0)

        # one array
        temp = [np.array(par)]
        jac = circuit3.jacobian(temp)
        ag = grad3(*temp)[np.newaxis, :]
        assert jac == pytest.approx(ag, abs=tol)