Introductory demo of autodiff module with the gradpy package

Welcome to the introductory demo for automatic differentiation with gradpy! After you have successfully installed the gradpy package (please refer to the Installation page for reference), you can follow along the commands below to get started.

Single-variable function

From the main module autodiff, we will begin by importing the elementary Var object, used to define independent variables in an equation or model of interest. We create a Var variable \(x\) initialized with the value 1 and use it to create a simple user-defined function, \(f = 3x^2+5\).

In [1]:
from gradpy.autodiff import Var

x = Var(1)
f = 3*x**2 + 5

We can obtain the value and derivative of \(f\) with respect to \(x\), evaluated at \(x=1\), by accessing the value attribute, and calling the der method with the appropriate Var object as its argument:

In [2]:
fval = f.value
fder = f.der(x)

print("f(x) =",fval)
print("f'(x) =",fder)
f(x) = 8
f'(x) = 6

If we do not know the value of \(x\) ahead of time, or would like to change it later without redefining \(f\), we can do so using the set_value method:

In [3]:
x.set_value(3)

print("f(x) =",f.value)
print("f'(x) =",f.der(x))
f(x) = 32
f'(x) = 18

Var is itself a differentiable object; thus we can also do:

In [4]:
print("x =",x.value)
print("x' =",x.der(x))
x = 3
x' = 1

Multi-variable function

Multi-variable functions can be defined by instantiating multiple Var instances as independent variables.

In [5]:
a = Var()
b = Var()

c = a**2 - 2*a*b + b**2

a.set_value(2)
b.set_value(2)
print(c.value, c.der(a), c.der(b))

a.set_value(3)
b.set_value(4)
print(c.value, c.der(a), c.der(b))
0 0 0
1 -2 2

Derivatives with respect to several independent variables, comprising the gradient of a function, can be obtained simultaneously by supplying a list of Var objects to the grad method. The return type is a numpy array.

In [6]:
print(c.value, c.grad([a,b]), type(c.grad([a,b])))
1 [-2  2] <class 'numpy.ndarray'>

Vector-valued function

Vector-valued functions can be initialized with the Array class. The value attribute and der method of Array objects also return numpy arrays.

In [7]:
from gradpy.autodiff import Array

t = Var(4)

vec = Array([0.5*t**2,
             5*t])

print(vec.value, vec.der(t))
[ 8. 20.] [4. 5.]

Vector-valued functions can also be multi-variable:

In [8]:
import numpy as np

x = Var(3)
y = Var(2)
z = Var(1)

v = Array([-y - z,
           x + 0.1*y,
           0.1 + z*(x - 14)])

print(v.grad([x,y,z]))

# is equivalent to ...
print(np.array([v[0].grad([x,y,z]),
                v[1].grad([x,y,z]),
                v[2].grad([x,y,z])]))

# is equivalent to ...
print(np.array([[v[0].der(x), v[0].der(y), v[0].der(z)],
                [v[1].der(x), v[1].der(y), v[1].der(z)],
                [v[2].der(x), v[2].der(y), v[2].der(z)]]))
[[  0.   -1.   -1. ]
 [  1.    0.1   0. ]
 [  1.    0.  -11. ]]
[[  0.   -1.   -1. ]
 [  1.    0.1   0. ]
 [  1.    0.  -11. ]]
[[  0.   -1.   -1. ]
 [  1.    0.1   0. ]
 [  1.    0.  -11. ]]