"""
Module containing functions to differentiate functions using autograd.
"""
import functools

try:
    import autograd
except ImportError:
    autograd = None

from ._backend import Backend
from .. import make_tracing_backend_decorator
from ...tools import bisect_sequence, unpack_singleton_sequence_return_value


class _AutogradBackend(Backend):
    def __init__(self):
        super().__init__("Autograd")

    @staticmethod
    def is_available():
        return autograd is not None

    @Backend._assert_backend_available
    def is_compatible(self, objective, argument):
        return (callable(objective) and isinstance(argument, (list, tuple)) and
                len(argument) > 0)

    @Backend._assert_backend_available
    def compile_function(self, function, arguments):
        return function

    @Backend._assert_backend_available
    def compute_gradient(self, function, arguments):
        num_arguments = len(arguments)
        gradient = autograd.grad(function, argnum=list(range(num_arguments)))
        if num_arguments == 1:
            return unpack_singleton_sequence_return_value(gradient)
        return gradient

    @Backend._assert_backend_available
    def compute_hessian_vector_product(self, function, arguments):
        num_arguments = len(arguments)
        hessian_vector_product = autograd.hessian_vector_product(
            function, argnum=tuple(range(num_arguments)))

        @functools.wraps(hessian_vector_product)
        def wrapper(*args):
            arguments, vectors = bisect_sequence(args)
            return hessian_vector_product(*arguments, vectors)
        if num_arguments == 1:
            return unpack_singleton_sequence_return_value(wrapper)
        return wrapper


Autograd = make_tracing_backend_decorator(_AutogradBackend)

@@ -115,16 +115,48 @@
 utograd%0A
+    import autograd.numpy as np%0A
 except I
@@ -1172,16 +1172,494 @@
 adient%0A%0A
+    @staticmethod%0A    def _hessian_vector_product(function, argnum):%0A        gradient = autograd.grad(function, argnum)%0A%0A        def vector_dot_gradient(*args):%0A            arguments, vectors = args%5B:-1%5D, args%5B-1%5D%0A            gradients = gradient(*arguments)%0A            return np.sum(%0A                %5Bnp.tensordot(gradient, vector, axes=vector.ndim)%0A                 for gradient, vector in zip(gradients, vectors)%5D)%0A        return autograd.grad(vector_dot_gradient, argnum)%0A%0A
     @Bac
@@ -1681,32 +1681,32 @@
 ckend_available%0A
-
     def compute_
@@ -1828,25 +1828,22 @@
 oduct = 
-autograd.
+self._
 hessian_

fix bug in hvp for nary functions