Before this lesson:lesson 03 (inverse,
determinant, trace), lesson 05(A=XΛX−1 and eJt),lesson 06(S=QΛQ⊤) and lesson 15 (JVP and VJP).
Time: about 85 minutes, plus the notebook.
Many ML objectives are scalar functions of a matrix: a Gaussian log-likelihood contains
logdetΣ and Σ−1, and cross-entropy and attention go through a softmax.
Index-by-index derivatives are slow and error-prone; the differential method gives them in a few
lines. Matrix functions say what eA or S means. The matrix exponential solves every
linear ODE x′=Ax: heat diffusion on a grid, linearized dynamics, the state-space layers of
Mamba. The Kronecker product and vec turn linear maps on matrices, such as X↦AXB, into
ordinary matrices: the algebra behind layer Jacobians, K-FAC and Shampoo, and fast Gaussian
processes on space–time grids.
Differentials. Start with one variable. The differentialdf=f′(x)dx is the linear part
of the change f(x+dx)−f(x); the rest shrinks faster than dx. The matrix case is the same
idea. For a function of a matrix X,df is the part of f(X+dX)−f(X) that is linear in
the small matrix dX. We use rules (sum, product, chain) on whole matrices and never write
indices. The one new thing: matrices do not commute, so the order of the factors must stay.
A scalar f of an m×n matrix has a linear part ∑ijGijdXij for some
m×n matrix G, and this sum is tr(G⊤dX). So if we bring df into the
form tr(G⊤dX), the gradient is G. The tool for this is the cyclic property of
the trace.
How to test a derivative. Walk from X along a direction dX for a step t. A correct
derivative predicts the new value up to a second-order term:
f(X+tdX)=f(X)+tdf(dX)+O(t2).
So the error of the prediction falls like t2: halve t and the error is divided by 4. A wrong
derivative leaves an error of order t: halve t and the error is only divided by 2. On a log–log
plot the first is a line of slope 2 and the second a line of slope 1. This is the standard
gradient check of autodiff libraries, done along one random direction.
Interactive figure: loading…
Choose a function and press New direction. The blue curve uses the
correct derivative and falls with slope 2. The orange curve uses a common
mistake (X−1 instead of X−⊤,2Ax instead of (A+A⊤)x,−X−2dX instead of
−X−1dXX−1) and falls only with slope 1. For tr(AX) the function is linear,
so the correct prediction is exact and only rounding error is left.
Quick check
You test a gradient along a random direction. At t=0.01 the error of the first-order prediction is 4×10−6. The gradient is correct. What error do you expect at t=0.005?
Why.
With a correct gradient the error is O(t2), so halving t divides it by 22=4. Division by 2 (the first option) is what a wrong gradient gives: its error is O(t).
Matrix functions. Take S=diag(4,1). The obvious candidate for S is
diag(2,1): it squares to S. A symmetric S=QΛQ⊤ is diagonal in its
eigen-axes, so we apply f to each axis on its own: f(S) scales the eigen-axis qi by
f(λi). It is not the entrywise f(Sij).
Kronecker and vec. The map X↦AXB is linear in X, so it is a matrix acting on the
coordinates of X. Stack the columns of X into one long vector vec(X). The
matrix of the map is then B⊤⊗A: a block matrix made of copies of A, each scaled by
an entry of B⊤.
Interactive figure: loading…
Match the blocks. Press Next block or click a block of B⊤⊗A. Block (k,j) is
bjkA. It multiplies column j of X (the same colour in vecX), and block row k
adds up to column k of AXB. Press New numbers: the check at the bottom
always says equal.
Definition. For a map f from matrices to matrices, the differential df is the linear
function of dX with f(X+dX)=f(X)+df+o(∥dX∥).
Rules. Each follows from expanding f(X+dX) and dropping second-order terms.
constant: dA=0; sum: d(F+G)=dF+dG;
product: d(FG)=dFG+FdG (keep the order);
transpose and trace: d(F⊤)=(dF)⊤,dtrF=tr(dF);
chain rule: the differential of g(F(X)) is the differential of g at F, applied to dF.
Identification rule. If a scalar f has df=tr(G⊤dX) for every dX, then
∇Xf=G, the matrix of partial derivatives ∂f/∂Xij (same shape as X).
Reason: tr(G⊤dX)=∑ijGijdXij; put dX=Eij, the matrix with a
single 1 at (i,j). For vectors, df=g⊤dx gives ∇f=g.
The rule entry by entry, for a 2×2 matrix.
Multiply out: G⊤dX=(g11g12g21g22)(dx11dx21dx12dx22).
Its diagonal entries are g11dx11+g21dx21 and g12dx12+g22dx22.
Add them: the trace is the sum of the four terms g11dx11,g12dx12,g21dx21 and g22dx22, that is, tr(G⊤dX)=∑ijgijdxij.
Every entry of dX is multiplied by the entry of G at the same position.
Compare with the multivariable chain rule df=∑ij∂xij∂fdxij:
so gij=∂f/∂xij.
Example.f(X)=tr(AX) with A=(1324). The diagonal of
AX gives f=(x11+2x21)+(3x12+4x22), so
The rule gives the same in one line: df=tr(AdX)=tr((A⊤)⊤dX).
Trace tools. A scalar equals its own trace; tr(M⊤)=tr(M); and
tr(ABC)=tr(BCA)=tr(CAB) (cyclic moves only).
Two first examples.
f(X)=tr(AX):df=tr(AdX)=tr((A⊤)⊤dX), so ∇f=A⊤.
f(x)=x⊤Ax:df=dx⊤Ax+x⊤Adx. The first term is a scalar, so it equals its
transpose x⊤A⊤dx. Hence df=x⊤(A+A⊤)dx and ∇f=(A+A⊤)x, which
is 2Ax for a symmetric A.
So the quadratic f(x)=21x⊤Ax−b⊤x has ∇f=21(A+A⊤)x−b. Only the
symmetric part of A enters f, because x⊤Kx=0 for a skew-symmetric K. The shortcut
∇f=Ax−b is right only when A=A⊤.
Interactive figure: loading…
The gradient is perpendicular to the level sets. Drag the violet point x. The
blue arrow is the true gradient 21(A+A⊤)x−b; it crosses the green
contour lines at a right angle. The orange dashed arrow is Ax−b: for a
non-symmetric A it points in another direction. Choose I + skew part: the contours are circles,
yet Ax−b is turned by a fixed angle. Switch the arrow field to Ax−b to see the error everywhere.
Differentiate the identity XX−1=I. The right side is constant, so d(XX−1)=0.
Product rule, with the order kept: dXX−1+Xd(X−1)=0.
Multiply on the left by X−1:d(X−1)=−X−1dXX−1.■
Why −X−2dX is wrong. To get −X−2dX you must move dX past X−1, and matrices do
not commute. A small example shows the difference. Take X=diag(1,2) and change one
off-diagonal entry: dX=(000.10).
Exact: (X+dX)−1=(100.12)−1=(10−0.050.5),
so the change is (00−0.050).
−X−1dXX−1: the entry 0.1 is multiplied by (X−1)11=1 from the left and by
(X−1)22=0.5 from the right, which gives −0.05. Correct (here even exactly).
−X−2dX: the entry is multiplied by (X−2)11=1 only, which gives −0.1. Twice too large.
Only when dX commutes with X (for example in the 1×1 case) do the two agree.
Example: f(X)=a⊤X−1b has df=−a⊤X−1dXX−1b=−tr(X−1ba⊤X−1dX),
so ∇f=−X−⊤ab⊤X−⊤.
Quick check
X is invertible and depends on a parameter θ. What is dθdX−1?
Why.
Differentiate XX−1=I with the order kept: X′X−1+X(X−1)′=0, so (X−1)′=−X−1X′X−1. The two −X−2 forms move X′ past X−1, which is wrong unless they commute; the last option has the wrong sign.
For an invertible X:ddetX=detX⋅tr(X−1dX). If detX>0, then
dlogdetX=tr(X−1dX), so ∇XlogdetX=X−⊤(=X−1 for a symmetric X).
Proof.
Factor: X+dX=X(I+E) with E=X−1dX. The determinant is multiplicative, so
det(X+dX)=detX⋅det(I+E).
det(I+E)=1+trE+O(∥E∥2). For a 2×2 matrix you can see it directly:
det(I+E)=(1+e11)(1+e22)−e12e21=1+trE+detE, and detE is
second order. The fold below shows it for every size.
Keep the linear part: ddetX=detX⋅tr(X−1dX).
Chain rule with dlogu=du/u:dlogdetX=tr(X−1dX).
Identify: tr(X−1dX)=tr((X−⊤)⊤dX), so the gradient is X−⊤.■
Step 2 for every size: det(I+E)=1+trE+O(∥E∥2)
In the permutation expansion of det(I+E), the identity permutation gives
∏i(1+Eii)=1+∑iEii+O(∥E∥2). Every other permutation moves at least two
indices, so it uses at least two off-diagonal entries, and each is an entry of E: that term is
O(∥E∥2). The argument uses no eigenvalues, so it holds for every square E, also when X is
not diagonalizable.
The same formula holds for log∣detX∣ at every invertible X (for detX<0, apply step 4
to −detX).
For z∈Rn,s=softmax(z) has entries si=ezi/Z with Z=∑jezj.
Result.ds=Jdz with J=diag(s)−ss⊤.
One entry first. Use the quotient rule on s1=ez1/Z, and note that ∂Z/∂zj=ezj.
Same index: ∂z1∂s1=Z2ez1Z−ez1ez1=s1−s12=s1(1−s1).
Other index: ∂z2∂s1=Z20⋅Z−ez1ez2=−s1s2.
So Jij=siδij−sisj: the diagonal holds si(1−si), the rest −sisj. In matrix
form this is diag(s)−ss⊤.Check: equal logits for n=2 give
s=(0.5,0.5) and
Raising z1 raises s1 and lowers s2 by the same amount, because s1+s2=1.
The same result without indices.
Take logs: logsi=zi−log∑jezj.
Differentiate: dlog∑jezj=∑jezjdzj/∑lezl=s⊤dz. So
dlogsi=dzi−s⊤dz.
Use dsi=sidlogsi:dsi=sidzi−si(s⊤dz), that is, ds=(diag(s)−ss⊤)dz.
Interactive figure: loading…
Move the logits and the temperature. The bars are the probabilities s; the map is
J=diag(s)−ss⊤ (orange positive,
blue negative). The row sums are always 0. The preset z=(0,ln2,ln3) is
worked example (b). Lower the temperature T:s becomes one-hot and every entry of J goes to 0,
which is why a saturated softmax passes almost no gradient.
Properties.
J is symmetric, and J1=s−s(s⊤1)=0(1 is the all-ones vector):
adding a constant to all logits does not change the softmax. So J is singular.
J is PSD: v⊤Jv=∑isivi2−(∑isivi)2 is the variance of vi when the
index i is drawn with probabilities s. If all si>0, it is zero only for constant v, so
rankJ=n−1.
Cross-entropy L=−logsy for the true class y: by step 2, dL=−(dzy−s⊤dz)=(s−ey)⊤dz,
so ∇zL=s−ey(ey is the one-hot vector of class y).
Backprop never builds J. With the upstream gradient g=∂L/∂s, the VJP is
J⊤g=s⊙(g−(s⊤g)1)(⊙ is the entrywise product): O(n) work, not O(n2).
Quick check
The softmax output is s=(0.2,0.3,0.5). What is ∂s1/∂z2?
Why.
Off the diagonal, Jij=−sisj=−0.2⋅0.3=−0.06: raising one logit takes probability from all the others. 0.16=s1(1−s1) is the diagonal entry ∂s1/∂z1, and 0.21=s2(1−s2) is ∂s2/∂z2.
For a diagonalizable A=XΛX−1, in the same way f(A)=Xf(Λ)X−1.
Why this is the right definition.Sk=QΛkQ⊤, because the inner factors
Q⊤Q=I cancel. So p(S)=Qp(Λ)Q⊤ for every polynomial p. A power series such as
ex=∑kxk/k! is a limit of polynomials, so the definition agrees with
eS=∑kSk/k!. It also does not depend on the choice of eigenbasis: inside an eigenspace,
f multiplies the whole projector onto it by the single number f(λ).
The three main functions.
eS: defined for every symmetric S; it is symmetric positive definite, with eigenvalues
eλi>0. The series eA=∑kAk/k! defines eA for every square A, even a
defective one.
S1/2=QΛ1/2Q⊤ for S⪰0: the unique PSD matrix whose square is S. It is
used for whitening (S−1/2x) and in the Fréchet distance between Gaussians.
logS=QlogΛQ⊤ for S≻0: symmetric, with elogS=S. A useful
identity: logdetS=∑ilogλi=trlogS.
Rules that do not carry over from numbers.eA+B=eAeB holds when AB=BA (then the
binomial theorem works for (A+B)k). Without this condition it fails in general. In the same way,
dtdeA(t)=A′(t)eA(t) holds when A′(t) commutes with A(t), and fails in general.
Quick check
For which pair of square matrices is eA+B=eAeB guaranteed?
Why.
The proof expands (A+B)k with the binomial theorem, which needs AB=BA. Symmetry, invertibility or equal traces do not give this. For example A=diag(1,0) and B=(0110) are symmetric, AB=BA, and eAeB is not even symmetric, while eA+B is.
For A∈Rn×n and x0∈Rn, the unique solution of x′(t)=Ax(t) with
x(0)=x0 is x(t)=eAtx0.
The key step is the derivative of the series: dtdeAt=AeAt, just as
dtdeat=aeat for a number a.
Proof (convergence, derivative, uniqueness)
The series eAt=∑k≥0tkAk/k! converges for every t: in the spectral norm
(∥Ak∥2≤∥A∥2k) the k-th term has norm at most (∣t∣∥A∥2)k/k!, and these
numbers sum to e∣t∣∥A∥2.
Differentiate term by term (allowed for a convergent power series):
dtdeAt=∑k≥1k!ktk−1Ak=A∑k≥0k!tkAk=AeAt.
So x(t)=eAtx0 satisfies x′=Ax, and x(0)=Ix0=x0.
Uniqueness. Let y be any solution. e−At commutes with A, so
dtd(e−Aty)=e−At(−Ay+y′)=0. Hence e−Aty(t)=y(0)=x0. As At and
−At commute, eAte−At=e0=I, so y(t)=eAtx0.■
Reading the solution. If A=XΛX−1 with eigenvectors xi and c=X−1x0, then
x(t)=∑icieλitxi: each eigen-direction grows or decays at its own rate. The
solution goes to 0 for every x0 exactly when all Reλi<0. A 2×2 Jordan block
Jλ=λI+N, with N=(0010) and N2=0, gives eJλt=eλt(I+tN),
the teλt terms of lesson 05. Sampling at a step Δ
gives the exact recurrence xk+1=eAΔxk.
Interactive figure: loading…
Let the plane flow. Press Play or move t. Every point moves along x(t)=etAx(0); the
green ring is the unit circle carried by etA, and it stays an ellipse
because etA is a linear map. Try the presets: real eigenvalues give straight eigen-directions
(dashed), complex ones give spirals (closed ellipses for the center, where
Reλ=0), a saddle stretches along one eigen-direction and squeezes along
the other. The readout shows that detetA and ettrA are the same number.
How the figure computes etA, and how libraries do it
For a 2×2 matrix the figure computes etA exactly from the Cayley–Hamilton theorem
(A2=2τA−(detA)I with τ=21trA): with δ2=τ2−detA,
etA=eτt(cosh(δt)I+δsinh(δt)(A−τI)),
read with cosh(δt)=cos(ωt) and sinh(δt)/δ=sin(ωt)/ω when
δ2=−ω2<0, and with 1 and t when δ=0. For larger matrices libraries use
scaling and squaring: eA=(eA/2s)2s, with a Padé or Taylor approximation of
eA/2s (the notebook builds one).
Definitions.vec(X)∈Rmn stacks the columns of X∈Rm×n,
the first column on top. For A∈Rm×n and B∈Rp×q, the
Kronecker product is the mp×nq block matrix
A⊗B=a11B⋮am1B⋯⋯a1nB⋮amnB.
Rules.(A⊗B)(C⊗D)=AC⊗BD (the mixed-product rule, when AC and BD
exist); (A⊗B)⊤=A⊤⊗B⊤;(A⊗B)−1=A−1⊗B−1 (for invertible A,B);vec(uv⊤)=v⊗u;tr(A⊤X)=vec(A)⊤vec(X).
Let xj be column j of X and bjk the entries of B. Column k of XB is ∑jbjkxj.
So column k of AXB is ∑jbjk(Axj).
Block k of vec(AXB) is column k of AXB, and block j of vec(X) is xj.
Step 2 says: block k of the output =∑j(bjkA)(block j of the input).
So the matrix of the map has block (k,j) equal to bjkA=(B⊤)kjA. This is the
definition of B⊤⊗A.■
Special cases: vec(AX)=(I⊗A)vecX and vec(XB)=(B⊤⊗I)vecX.
Example: a linear layer Y=WX has dY=dWX, so the Jacobian of vecY with
respect to vecW is X⊤⊗I. A VJP never forms it: for the upstream gradient
G=∂L/∂Y,(X⊤⊗I)⊤vecG=(X⊗I)vecG=vec(GX⊤),
the familiar weight gradient GX⊤.
Let A be n×n with eigenvalues λ1,…,λn, and B be m×m with
eigenvalues μ1,…,μm (with multiplicity). Then A⊗B has the nm eigenvalues
λiμj, and the Kronecker sumA⊗Im+In⊗B has the nm eigenvalues
λi+μj.
Why (eigenvectors). If Ax=λx and By=μy, the mixed-product rule gives
(A⊗B)(x⊗y)=Ax⊗By=λμ(x⊗y) and
(A⊗I+I⊗B)(x⊗y)=λx⊗y+x⊗μy=(λ+μ)(x⊗y).
When A and B are diagonalizable, the nm vectors xi⊗yj form a basis, and the theorem follows.
Proof with multiplicities, also for non-diagonalizable matrices (Schur form)
Take Schur forms A=UTU∗ and B=VRV∗, with U,V unitary and T,R upper triangular
(diagonals: the eigenvalues).
Mixed product: A⊗B=(U⊗V)(T⊗R)(U⊗V)∗, and U⊗V is unitary.
So A⊗B is similar to T⊗R.
T⊗R is upper triangular: its blocks tijR below the diagonal are zero, and its
diagonal blocks tiiR are upper triangular. Its diagonal entries are tiirjj=λiμj.
In the same way A⊗I+I⊗B is similar to T⊗I+I⊗R, which is upper
triangular with diagonal entries λi+μj.■
Consequences: tr(A⊗B)=trA⋅trB,det(A⊗B)=(detA)m(detB)n,
the singular values of A⊗B are σi(A)σj(B), so κ(A⊗B)=κ(A)κ(B).
The Sylvester equationAX+XB=C is linear in X. With vec it reads
(I⊗A+B⊤⊗I)vecX=vecC. That matrix is a Kronecker sum with
eigenvalues λi(A)+μj(B)(B⊤ has the eigenvalues of B). So the solution is unique
exactly when λi(A)+μj(B)=0 for all i,j.
Answers to section 1. (1) No. The derivative is −X−1dXX−1. It equals −X−2dX only
when dX commutes with X, as in the 1×1 case. (2) Not in general; it holds when AB=BA.
For A=(0010) and B=A⊤:eAeB=(1011)(1101)=(2111),
but eA+B=(cosh1sinh1sinh1cosh1)≈(1.5431.1751.1751.543).
(a) logdet and the inverse, with numbers.X=(2112) has
detX=3 and X−1=31(2−1−12). Change one entry: dX=0.01E11.
Prediction: dlogdetX=tr(X−1dX)=0.01⋅32≈0.0066667. Exact:
det(X+dX)=2.01⋅2−1=3.02 and log3.02−log3≈0.0066445. The difference,
about 2.2×10−5, is second order.
(b) Softmax.z=(0,ln2,ln3) gives ez=(1,2,3) and s=(61,31,21). Then
J=diag(s)−ss⊤=3615−2−3−28−6−3−69.
For example J11=61⋅65=365 and J12=−61⋅31=−362.
Each row sums to 0 (J1=0). With the true class y=3:∇zL=s−e3=(61,31,−21).
(c) A square root and a linear ODE.S=(2112) has λ=3 with
q1=(1,1)/2 and λ=1 with q2=(1,−1)/2. With the projectors
P1=q1q1⊤=21(1111) and P2=q2q2⊤=21(1−1−11):
Squaring gives back S. In the same way logS=ln3⋅P1 (because ln1=0), and
trlogS=ln3=logdetS.
Now heat flow in two cells. Each cell exchanges heat with the other (rate 1) and loses heat to
the surroundings (rate 1): x1′=(x2−x1)−x1, and the same for x2. So x′=Ax with
A=(−211−2), which has eigenvalue −1 for q1 and −3 for q2. Start
with all heat in cell 1: x0=(1,0)=21(q1+q2). Then
x(t)=eAtx0=21e−t(11)+21e−3t(1−1).
The average temperature decays at rate 1; the difference between the cells decays three times
faster. At t=1:x≈(0.2088,0.1590).
(d) vec and Kronecker, step by step.A=(1324),X=A, and
B=(0110) (it swaps columns).
Left side: AX=(7151022) and AXB=(1022715), so
vec(AXB)=(10,22,7,15) (first column on top).
vecX=(1,3,2,4): block 1 is x1=(1,3), block 2 is x2=(2,4).
B⊤=B, so block (k,j) of B⊤⊗A is bjkA: blocks (1,1) and (2,2) are 0⋅A,
blocks (1,2) and (2,1) are 1⋅A. So B⊤⊗A=(0AA0).
Stacked: (10,22,7,15), the same vector as in step 1. ✓
Eigenvalues: A1=(2013) (eigenvalues 2, 3) and
B1=(5207) (eigenvalues 5, 7). A1⊗B1 has eigenvalues
10,14,15,21, and A1⊗I+I⊗B1 has 7,9,8,10. Check:
det(A1⊗B1)=62⋅352=44100=10⋅14⋅15⋅21.
Quick check
What are the eigenvalues of diag(2,3)⊗(1015)?
Why.
The second factor is triangular, so its eigenvalues are 1 and 5. A Kronecker product has all products λiμj:2⋅1,2⋅5,3⋅1,3⋅5. The sums 3,7,4,8 belong to the Kronecker sum A⊗I+I⊗B.
NumPy and SciPy check the hand computations above; finite differences stand in for autodiff.
The notebook for this lesson has these cells and the exercises.
importnumpyasnpfromscipy.linalgimportexpm,sqrtm,logmfromscipy.specialimportsoftmaxX=np.array([[2.,1.],[1.,2.]])Xi=np.linalg.inv(X)dX=np.array([[0.01,0.],[0.,0.]])# d log det X = tr(X^{-1} dX): equal to first orderprint(round(np.linalg.slogdet(X+dX)[1]-np.linalg.slogdet(X)[1],7),round(np.trace(Xi@dX),7))# 0.0066445 0.0066667# d(X^{-1}) = -X^{-1} dX X^{-1}print(np.round(np.linalg.inv(X+dX)-Xi,6))# [[-0.004415 0.002208] [ 0.002208 -0.001104]]print(np.round(-Xi@dX@Xi,6))# [[-0.004444 0.002222] [ 0.002222 -0.001111]]defnum_grad(f,X,h=1e-6):"""Central differences, one entry at a time."""G=np.zeros_like(X)foridxinnp.ndindex(X.shape):E=np.zeros_like(X);E[idx]=hG[idx]=(f(X+E)-f(X-E))/(2*h)returnG# the gradient of log det is X^{-T}, not X^{-1} (non-symmetric X here)Xn=np.array([[2.,1.],[0.,3.]])g=num_grad(lambdaM:np.linalg.slogdet(M)[1],Xn)print(np.allclose(g,np.linalg.inv(Xn).T,atol=1e-8),np.allclose(g,np.linalg.inv(Xn)))# True False# softmax Jacobian = diag(s) - s s^T (columns by finite differences)z=np.log(np.array([1.,2.,3.]))s=softmax(z)J=np.column_stack([(softmax(z+1e-6*e)-softmax(z-1e-6*e))/2e-6foreinnp.eye(3)])print(np.round(36*J,6))# [[5 -2 -3] [-2 8 -6] [-3 -6 9]]print(np.allclose(J,np.diag(s)-np.outer(s,s)),np.allclose(J@np.ones(3),0))# True True# matrix functions: f(S) = Q f(Lambda) Q^T, not entrywiseS=Xlam,Q=np.linalg.eigh(S)R=Q@np.diag(np.sqrt(lam))@Q.Tprint(np.round(R,6),np.allclose(R,sqrtm(S)),np.allclose(R@R,S))# [[1.366025 0.366025] ...] True Trueprint(np.allclose(expm(S),Q@np.diag(np.exp(lam))@Q.T),np.allclose(expm(S),np.exp(S)))# True Falseprint(np.isclose(np.trace(logm(S)),np.log(np.linalg.det(S))))# True: tr log S = log det S# x' = Ax is solved by x(t) = e^{At} x0 (the two-cell heat example)A=np.array([[-2.,1.],[1.,-2.]])print(np.round(expm(A*1.0)@np.array([1.,0.]),6))# [0.208833 0.159046]# e^{A+B} != e^A e^B when AB != BAN=np.array([[0.,1.],[0.,0.]])print(np.round(expm(N)@expm(N.T),4))# [[2. 1.] [1. 1.]]print(np.round(expm(N+N.T),4))# [[1.5431 1.1752] [1.1752 1.5431]]# vec(AXB) = (B^T kron A) vec(X); vec stacks COLUMNS, so use order="F"A2=np.array([[1.,2.],[3.,4.]]);B2=np.array([[0.,1.],[1.,0.]])vec=lambdaM:M.reshape(-1,order="F")print(vec(A2@A2@B2),np.kron(B2.T,A2)@vec(A2))# [10. 22. 7. 15.] twice# eigenvalues: products for A kron B, sums for the Kronecker sumA1=np.array([[2.,1.],[0.,3.]]);B1=np.array([[5.,0.],[2.,7.]]);I2=np.eye(2)print(np.sort(np.linalg.eigvals(np.kron(A1,B1)).real))# [10. 14. 15. 21.]print(np.sort(np.linalg.eigvals(np.kron(A1,I2)+np.kron(I2,B1)).real))# [ 7. 8. 9. 10.]
The gradient check of section 2, as code: the error of the first-order prediction along a random
direction, for the correct gradient X−⊤ of logdet and for the wrong X−1.
importnumpyasnprng=np.random.default_rng(0)X=np.array([[2.,1.],[0.5,3.]])# not symmetric, so X^{-T} != X^{-1}D=rng.standard_normal((2,2));D/=np.linalg.norm(D)f=lambdaM:np.linalg.slogdet(M)[1]forG,namein[(np.linalg.inv(X).T,"X^{-T}"),(np.linalg.inv(X),"X^{-1}")]:err=[abs(f(X+t*D)-f(X)-t*np.sum(G*D))fortin(1e-3,5e-4)]print(name,round(err[0]/err[1],2))# X^{-T} 4.0 (O(t^2)), X^{-1} 2.0 (O(t))
Gaussian maximum likelihood. For N samples with known mean μ,ℓ(Σ)=−2N(logdetΣ+tr(Σ−1S^))+const, with
S^=N1∑n(xn−μ)(xn−μ)⊤. The two theorems give
dℓ=−2Ntr((Σ−1−Σ−1S^Σ−1)dΣ). This is zero for every
symmetric dΣ exactly when Σ=S^.
Gaussian processes and flows. GP hyperparameters need
∂θlogdetK=tr(K−1∂θK). Normalizing flows need log∣detJ∣, so
they use triangular Jacobians (the change-of-variables formula).
Softmax. In attention backward, FlashAttention computes dSij=Pij(dPij−Di) with
Di=∑jPijdPij: the VJP s⊙(g−(s⊤g)1), row by row.
Linear dynamics.eAt solves semi-discretized heat equations (u′=Lu), linearized
climate models and continuous-time Markov chains. Mamba discretizes h′=Ah+Bx with step
Δ by Aˉ=eΔA (zero-order hold). Its A is diagonal, so here "entrywise" is right.
SPD square roots and logs. Whitening Σ−1/2x; the Fréchet distance behind FID,
∥μ1−μ2∥2+tr(Σ1+Σ2−2(Σ11/2Σ2Σ11/2)1/2); the
log-Euclidean distance ∥logS1−logS2∥F between covariance matrices (lesson 19).
K-FAC and Shampoo. For a layer s=Wa with backpropagated g=∂L/∂s, the
weight gradient is ga⊤, and vec(ga⊤)=a⊗g. K-FAC approximates the Fisher
block E[aa⊤⊗gg⊤] by Aˉ⊗Gˉ(Aˉ=E[aa⊤],Gˉ=E[gg⊤]).
Then (Aˉ⊗Gˉ)−1vec(ga⊤)=vec(Gˉ−1ga⊤Aˉ−1): two small inverses
instead of one huge one. Shampoo steps along HL−1/4MtHR−1/4 for the gradient matrix Mt,
with HL=∑tMtMt⊤ and HR=∑tMt⊤Mt. By the vec rule this is the Kronecker
preconditioner HR−1/4⊗HL−1/4, built from two matrix functions.
Separable kernels and grids (ML for science). A space–time GP on a grid often uses
K=Ktime⊗Kspace. Then K+σ2I has eigenvalues λiμj+σ2, so
the solve and the logdet need only the eigendecompositions of the two small factors. The 2-D
Poisson matrix is Tm⊗I+I⊗Tm(Tm the 1-D second-difference matrix): its
eigenvalues are sums of 1-D eigenvalues, which gives its condition number in
lesson 14.
Losing the order.d(X−1)=−X−2dX, and d(X2)=dXX+XdX, not 2XdX.
∇logdetX=X−1 for every X. It is X−⊤. For symmetric X, some books give
2X−1−diag(X−1): the same differential, written in the free entries only (so Xij
and Xji move together). Safer: use the full-matrix gradient with a symmetric dX.
∇(21x⊤Ax−b⊤x)=Ax−b for every A. It is 21(A+A⊤)x−b.
Entrywise instead of matrix functions.np.exp(S) and np.sqrt(S) act entry by entry. Use
scipy.linalg.expm, sqrtm, logm, or Qf(Λ)Q⊤.
eA+B=eAeB without AB=BA. The same goes for log(AB)=logA+logB.
Products vs sums.A⊗B has eigenvalues λiμj; the Kronecker sum has λi+μj.
Row-major vec. NumPy's ravel() stacks rows; column-stacking vec is X.reshape(-1, order="F").
With row stacking the rule becomes vecr(AXB)=(A⊗B⊤)vecr(X).
Building Kronecker products or full Jacobians.B⊤⊗A for two 1000×1000 matrices
has 1012 entries. Apply it as AXB.
Softmax Jacobian =diag(s). This misses −ss⊤; the true J is singular.
Trusting a gradient check at one step size. One small error at one t can hide a wrong
gradient (for example when t is so small that rounding dominates). Compare two step sizes and
look for the factor 4.
Gradient of f(X)=a⊤Xb?Answerdf=a⊤dXb=tr(ba⊤dX), so ∇f=(ba⊤)⊤=ab⊤.
Gradient of f(X)=tr(X−1)?Answerdf=−tr(X−1dXX−1)=−tr(X−2dX) (cyclic move), so ∇f=−(X−2)⊤.
Why is deteA=etrA?AnswerWith a Schur form A=UTU∗,eA=UeTU∗ and eT is upper triangular with diagonal eλi. So deteA=∏ieλi=e∑iλi=etrA.
Solve x′=Ax for A=(0−110),x(0)=(1,0). Why does ∥x(t)∥ stay 1?AnswerA2=−I, so the series gives eAt=costI+sintA=(cost−sintsintcost) and x(t)=(cost,−sint).A is skew-symmetric, so (eAt)⊤=e−At=(eAt)−1:eAt is orthogonal and keeps lengths.
A(2×2) has eigenvalues 1,2 and B(2×2) has eigenvalues −1,4. Give the eigenvalues of A⊗B and of A⊗I+I⊗B. Does AX+XB=C have a unique solution?AnswerProducts: −1,4,−2,8. Sums: 0,5,1,6. The Sylvester matrix I⊗A+B⊤⊗I has the eigenvalues λi+μj, and one of them is 1+(−1)=0. The matrix is singular, so for a given C there is either no solution or infinitely many.
Why is the softmax Jacobian PSD, and why is it singular?Answerv⊤Jv=∑isivi2−(∑isivi)2 is a variance under the distribution s, so it is ≥0.J1=0, because adding the same constant to all logits does not change s.
Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
State the identification rule of matrix calculus.
If df=tr(G⊤dX) for every dX, then ∇Xf=G (same shape as X), because tr(G⊤dX)=∑ijGijdXij.
Why must the product rule for matrices keep the order of the factors?
Matrices do not commute: d(FG)=dFG+FdG, and dFG=GdF in general. For example d(X2)=dXX+XdX, not 2XdX.
What is d(X−1)?
−X−1dXX−1, from differentiating XX−1=I.
What is dlogdetX, and what is the gradient?
dlogdetX=tr(X−1dX), so ∇logdetX=X−⊤(X−1 if X is symmetric).
Compute ∇Xtr(AX).
A⊤, because dtr(AX)=tr(AdX)=tr((A⊤)⊤dX).
What is the Jacobian of s=softmax(z)? Give it for s=(0.5,0.5).
J=diag(s)−ss⊤. For s=(0.5,0.5):(0.25−0.25−0.250.25).
How do you compute f(S) for a symmetric matrix S?
Diagonalize S=QΛQ⊤ and apply f to the eigenvalues: f(S)=Qf(Λ)Q⊤. It is not f applied to each entry.
What solves x′=Ax with x(0)=x0?
x(t)=eAtx0, the unique solution.
State the vec rule for AXB.
vec(AXB)=(B⊤⊗A)vec(X), where vec stacks the columns.
What are the eigenvalues of A⊗B and of A⊗I+I⊗B?
All products λi(A)μj(B) for A⊗B, and all sums λi+μj for the Kronecker sum.
"Derive the MLE of a Gaussian covariance." — dlogdetΣ=tr(Σ−1dΣ) and
dΣ−1=−Σ−1dΣΣ−1 give Σ=S^ (section 6).
"Jacobian of softmax? Gradient of softmax cross-entropy?" — diag(s)−ss⊤;s−ey.
"How do you check a hand-written gradient?" — compare f(X+tdX)−f(X) with
ttr(G⊤dX) for a random dX and two values of t; the error must shrink by 4
when t is halved (central differences shrink it faster).
"Why is logdet concave on SPD matrices?" — the second differential is
−tr(X−1dXX−1dX)=−∥X−1/2dXX−1/2∥F2≤0 for symmetric dX.
"How do you solve x′=Ax, and when does it decay?" — x(t)=eAtx0; it decays for every
x0 exactly when all Reλi(A)<0.
"Why is K-FAC cheap to invert?" — (Aˉ⊗Gˉ)−1=Aˉ−1⊗Gˉ−1, applied as
Gˉ−1(gradient)Aˉ−1 by the vec rule.
The notebook for this lesson runs in Colab. It has five exercises, each with a check
cell and a folded solution:
Gradients by the differential method: logdetX,a⊤X−1b and tr(X−1),
checked against finite differences.
The softmax Jacobian diag(s)−ss⊤ and its O(n) VJP, and the
cross-entropy gradient s−ey.
Matrix functions Qf(Λ)Q⊤ for a symmetric matrix, checked against expm, sqrtm
and logm.
The matrix exponential by scaling and squaring with a Taylor polynomial, checked against
scipy.linalg.expm; then a demo solves the two-cell heat equation with eAtx0.
Solve the Sylvester equation AX+XB=C with the vec rule and a Kronecker sum, and check it
against scipy.linalg.solve_sylvester.
Open on YouTube · the player loads from youtube-nocookie.com when you press playOpen on YouTube · the player loads from youtube-nocookie.com when you press playOpen on YouTube · the player loads from youtube-nocookie.com when you press playOpen on YouTube · the player loads from youtube-nocookie.com when you press playOpen on YouTube · the player loads from youtube-nocookie.com when you press play
Paige Bright, Alan Edelman, Steven G. Johnson, Matrix Calculus (for Machine Learning and Beyond)
(MIT 18.S096 notes, free): ch. 2 "Derivatives as linear operators", §3.3 "Kronecker products",
ch. 7 "Derivative of matrix determinant and inverse". The
course page
has all lectures and problem sets.
K. B. Petersen, M. S. Pedersen, The Matrix Cookbook
(2012), free PDF: §2.1–2.2 (derivatives of the determinant and the inverse), §2.5 (traces),
§10.1 (functions and series), §10.2 (Kronecker and vec, eq. 519–520).