Skip to content

← JAX Autodiff step 7 of 25

Easy Primitives

Hessian of a Quadratic

Jump to the task

Read the second derivatives

A gradient tells you how a scalar function changes with each input. Its Hessian tells you how those derivatives change. For a vector input with d entries, the Hessian of a scalar function has shape (d, d). Entry (i, j) is the derivative of gradient entry i with respect to input entry j.

import jax
import jax.numpy as jnp

def f(x):
    return x[0]**2 + x[0]*x[1] + 1.5*x[1]**2

H = jax.hessian(f)(jnp.array([3.0, 4.0]))
# [[2.0, 1.0],
#  [1.0, 3.0]]

The gradient is [2*x[0] + x[1], x[0] + 3*x[1]]. Differentiating each entry gives the two rows above. The diagonal entries describe curvature along individual coordinates; the off-diagonal entries describe how the coordinates affect one another's derivatives.

Why symmetry matters for this quadratic

The example can be written as 0.5 * x @ A @ x, with A = [[2, 1], [1, 3]]. For a real symmetric A, the gradient is A @ x, so the Hessian is A at every x.

The factor 0.5 matters: removing it doubles the Hessian. If A were not symmetric, the Hessian of 0.5 * x @ A @ x would instead be (A + A.T)/2. This exercise guarantees symmetry.

What jax.hessian returns

Pass a function to jax.hessian, then call the resulting function at an input. For this scalar loss it returns the full matrix. Unlike jax.grad, jax.hessian also supports array-valued outputs. For an output with shape (m,) and an input with shape (d,), its result has shape (m, d, d): one matrix of second derivatives per output.

A dense Hessian for d scalar parameters contains d*d entries. Two nested differentiation transforms do not make its cost independent of d. If you only need the product with a vector, use an HVP method to avoid constructing the full matrix.

Problem

Implement hessian_quadratic(x, A) using jax.hessian for f(x) = 0.5 * x @ A @ x. Hold A fixed while differentiating with respect to x.

Both inputs are real floating-point JAX arrays. x has shape (d,), and A is symmetric with shape (d, d). Return the Hessian as a JAX array with shape (d, d). It should agree with A within floating-point tolerance, regardless of x.

The known answer makes this an exercise in constructing second derivatives. Practice using jax.hessian; numerical tests alone cannot distinguish that method from returning A directly.