19
import numpy as np


a = np.array([[1,2,3],
              [4,5,6],
              [7,8,9]])


b = np.array([[1,2,3]]).T

c = a.dot(b) #function

jacobian = a # as partial derivative of c w.r.t to b is a.

I am reading about jacobian Matrix, trying to build one and from what I have read so far, this python code should be considered as jacobian. Am I understanding this right?

filtertips
  • 801
  • 3
  • 12
  • 25
  • No, the Jacobian is defined for functions of variables. The Jacobian for a constant is 0. – dROOOze Mar 29 '18 at 09:57
  • Not likely, [The Jacobian matrix is the matrix of all first-order partial derivatives of a vector-valued function.](https://ipfs.io/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Jacobian_matrix_and_determinant.html) – Mazdak Mar 29 '18 at 10:00
  • 2
    Yes...if for vector `x` you define `f(x)=A.x` then `A` is the Jacobian...(only that you did not define it as python function here) – mikuszefski Mar 29 '18 at 10:38
  • @droooze Please read OP's question again, see my comment above. – mikuszefski Mar 29 '18 at 10:39
  • @mikuszefski the code doesn't demonstrate a Jacobian. `c = a.dot(b)` results in `c = array([[14],[32],[50]])`, an `array` of constants. There is no partial derivative of `c` with respect to `b` here. – dROOOze Mar 29 '18 at 10:48
  • 1
    @droooze seriously? `f = lambda x: np.dot( a, x )` now `c = f( b )`. What is the Jacobian of `f`? – mikuszefski Mar 29 '18 at 11:19
  • There's a world of difference between derivatives and division. Giving a scalar function example, if I say that `a = 2` and `b = 2`, then say that `c = 2*2 = 4`, this is not an example of differentiation and `a` is not an example of `dc/db`. The underlying relation could easily be `c = b^b` for all you know, which makes `dc/db = b^b * (ln(b) + 1)`; defining constants which happen to have a multiplicative relationship doesn't say anything about differentiation. – dROOOze Mar 29 '18 at 11:54
  • 1
    @droooze absolutely agree...and `c=np.dot(a,b)` is a constant formed from constant. However, looking at OP's comment stating `#function` I assume that he is talking about somewhat like my lambda definition above, without explicitly writing it like that. BTW, I think your originals answer, slightly modified would be quite helpful. Consider putting it again. – mikuszefski Mar 29 '18 at 13:18
  • @mikuszefski I deleted it when I realised that this whole question and comment thread could become very confusing to a reader who seems to be new to programming. The OP needs to be very clear about what a constant is, what a variable is, and how `=` works in Python before any of the code can make sense. This is StackOverflow and the question is asking about Python after all, not Mathematics SE. – dROOOze Mar 29 '18 at 13:31
  • @droooze again agreed; it seems more a mathematical and less a python / programming question. Probably OffTopic. – mikuszefski Mar 29 '18 at 14:31
  • @mikuszefski I am sorry for missleading you in anyway. What I am trying to ask is: is Jacobian matrix the shape and value of partial derivative of function with respect to variable, in my case b? – filtertips Apr 01 '18 at 11:42
  • @droooze sorry. a is a constant, while b is variable. Sorry for this. – filtertips Apr 01 '18 at 11:43

6 Answers6

21

You can use the Harvard autograd library (link), where grad and jacobian take a function as their argument:

import autograd.numpy as np
from autograd import grad, jacobian

x = np.array([5,3], dtype=float)

def cost(x):
    return x[0]**2 / x[1] - np.log(x[1])

gradient_cost = grad(cost)
jacobian_cost = jacobian(cost)

gradient_cost(x)
jacobian_cost(np.array([x,x,x]))

Otherwise, you could use the jacobian method available for matrices in sympy:

from sympy import sin, cos, Matrix
from sympy.abc import rho, phi

X = Matrix([rho*cos(phi), rho*sin(phi), rho**2])
Y = Matrix([rho, phi])

X.jacobian(Y)

Also, you may also be interested to see this low-level variant (link). MATLAB provides nice documentation on its jacobian function here.

UPDATE: Note that the autograd library has since been rolled into jax, which provides functions for computing forward and inverse Jacobian matrices (link).

Adam Erickson
  • 6,027
  • 2
  • 46
  • 33
14

The Jacobian is only defined for vector-valued functions. You cannot work with arrays filled with constants to calculate the Jacobian; you must know the underlying function and its partial derivatives, or the numerical approximation of these. This is obvious when you consider that the (partial) derivative of a constant (with respect to something) is 0.

In Python, you can work with symbolic math modules such as SymPy or SymEngine to calculate Jacobians of functions. Here's a simple demonstration of an example from Wikipedia:

enter image description here

Using the SymEngine module:

Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import symengine
>>>
>>>
>>> vars = symengine.symbols('x y') # Define x and y variables
>>> f = symengine.sympify(['y*x**2', '5*x + sin(y)']) # Define function
>>> J = symengine.zeros(len(f),len(vars)) # Initialise Jacobian matrix
>>>
>>> # Fill Jacobian matrix with entries
... for i, fi in enumerate(f):
...     for j, s in enumerate(vars):
...         J[i,j] = symengine.diff(fi, s)
...
>>> print J
[2*x*y, x**2]
[5, cos(y)]
>>>
>>> print symengine.Matrix.det(J)
2*x*y*cos(y) - 5*x**2
dROOOze
  • 1,727
  • 1
  • 9
  • 17
6

In python 3, you can try sympy package:

import sympy as sym

def Jacobian(v_str, f_list):
    vars = sym.symbols(v_str)
    f = sym.sympify(f_list)
    J = sym.zeros(len(f),len(vars))
    for i, fi in enumerate(f):
        for j, s in enumerate(vars):
            J[i,j] = sym.diff(fi, s)
    return J

Jacobian('u1 u2', ['2*u1 + 3*u2','2*u1 - 3*u2'])

which gives out:

Matrix([[2,  3],[2, -3]])
OliverQ
  • 1,489
  • 1
  • 11
  • 7
  • 1
    Or just `Matrix(['2*u1 + 3*u2','2*u1 - 3*u2']).jacobian(['u1', 'u2'])` gives the same in SymPy. – smichr Jul 07 '19 at 12:18
6

Here is a Python implementation of the mathematical Jacobian of a vector function f(x), which is assumed to return a 1-D numpy array.

import numpy as np

def J(f, x, dx=1e-8):
    n = len(x)
    func = f(x)
    jac = np.zeros((n, n))
    for j in range(n):  # through columns to allow for vector addition
        Dxj = (abs(x[j])*dx if x[j] != 0 else dx)
        x_plus = [(xi if k != j else xi + Dxj) for k, xi in enumerate(x)]
        jac[:, j] = (f(x_plus) - func)/Dxj
    return jac

It is recommended to make dx ~ 10-8.

Tonechas
  • 13,398
  • 16
  • 46
  • 80
James Carter
  • 803
  • 2
  • 10
  • 18
  • What is dx? Shouldn't it be a derivative of x? How is it a number here? – pr338 Sep 14 '20 at 19:26
  • 1
    The numerical derivative is calculated as a the rate of change of a function between the value of interest and a value very close to it. This definition of the numerical derivative here uses the forward definition, or f(x+dx)-f(x)/dx where dx is very small. Obviously, differential calculus is all about calculating the limit of that function as dx approaches 0, but the numerical estimate of that quantity can be obtained with a very low dx – James Carter Sep 15 '20 at 21:22
  • This fails for non-square matrices – fdermishin Feb 09 '21 at 11:07
  • Could you please give an example on how to implement your function J? – Wei Shan Lee Jul 22 '23 at 03:11
2

While autograd is a good library, make sure to check out its upgraded version JAX which is very well documented (compared to autograd).

A simple example:

import jax.numpy as jnp
from jax import jacfwd

# Define some simple function.
def sigmoid(x):
    return 0.5 * (jnp.tanh(x / 2) + 1)
# Note that here, I want a derivative of a "vector" output function (inputs*a + b is a vector) wrt a input 
# "vector" a at a0: Derivative of vector wrt another vector is a matrix: The Jacobian
def simpleJ(a, b, inputs): #inputs is a matrix, a & b are vectors
    return sigmoid(jnp.dot(inputs, a) + b)

inputs = jnp.array([[0.52, 1.12,  0.77],
                   [0.88, -1.08, 0.15],
                   [0.52, 0.06, -1.30],
                   [0.74, -2.49, 1.39]])

b = jnp.array([0.2, 0.1, 0.3, 0.2])
a0 = jnp.array([0.1,0.7,0.7])

# Isolate the function: variables to be differentiated from the constant parameters
f = lambda a: simpleJ(a, b, inputs) # Now f is just a function of variable to be differentiated

J = jacfwd(f)
# Till now I have only calculated the derivative, it still needs to be evaluated at a0.
J(a0)
0

If you want to find the Jacobian numerically for many points at once (for example, if your function accepts shape (n, x) and outputs (n, y)), here is a function. This is essentially the answer from James Carter but for many points. The dx may need to be adjusted based on absolute value as in his answer.

def numerical_jacobian(f, xs, dx=1e-6):
  """
      f is a function that accepts input of shape (n_points, input_dim)
      and outputs (n_points, output_dim)

      return the jacobian as (n_points, output_dim, input_dim)
  """
  if len(xs.shape) == 1:
    xs = xs[np.newaxis, :]
    
  assert len(xs.shape) == 2

  ys = f(xs)
  
  x_dim = xs.shape[1]
  y_dim = ys.shape[1]
  
  jac = np.empty((xs.shape[0], y_dim, x_dim))
  
  for i in range(x_dim):
    x_try = xs + dx * e(x_dim, i + 1)
    jac[:, :, i] = (f(x_try) - ys) / dx
  
  return jac

def e(n, i):
  ret = np.zeros(n)
  ret[i - 1] = 1.0
  return ret
Alex
  • 947
  • 6
  • 16