Determinant and Sign-Log-Determinant Reverse-Mode Rules
1. Determinant (det)
Forward
d = \det(A), \quad A \in \mathbb{C}^{N \times N}
Forward mode (JVP)
By Jacobi’s formula (1841):
\dot{d} = \det(A) \cdot \mathrm{tr}(A^{-1} \dot{A})
Reverse mode (VJP)
Given cotangent \bar{d} \in \mathbb{C} (or \mathbb{R}):
Real case (A \in \mathbb{R}^{N \times N}):
\bar{A} = \bar{d} \cdot \det(A) \cdot A^{-\mathsf{T}}
Equivalently, \bar{A} = \bar{d} \cdot \mathrm{adj}(A)^{\mathsf{T}}, where \mathrm{adj}(A) = \det(A) \cdot A^{-1} is the classical adjugate.
Complex case (A \in \mathbb{C}^{N \times N}, Wirtinger convention):
\bar{A} = \overline{\bar{d} \cdot \det(A)} \cdot A^{-\mathsf{H}}
Under the Wirtinger (CR-calculus) convention the gradient is with respect to \bar{A} (the conjugate variable). The loss is real-valued, so the chain rule gives \partial\ell / \partial \bar{A}_{ij}. This produces the conjugate transpose A^{-\mathsf{H}} (not A^{-\mathsf{T}}) and conjugates the scalar prefactor.
Implementation note (PyTorch convention): PyTorch computes
grad_A = (grad * det(A)).conj() * A^{-H}viatorch.linalg.solve(A.mH, rhs), which is equivalent to the formula above. Seelinalg_det_backwardinFunctionsManual.cpp(L4321–4337).
Derivation (real case). From the JVP:
\delta\ell = \langle \bar{d},\, \dot{d} \rangle = \bar{d} \cdot \det(A) \cdot \mathrm{tr}(A^{-1} \dot{A}) = \mathrm{tr}\!\bigl((\bar{d} \cdot \det(A) \cdot A^{-\mathsf{T}})^{\mathsf{T}} \dot{A}\bigr)
Reading off: \bar{A} = \bar{d} \cdot \det(A) \cdot A^{-\mathsf{T}}.
Derivation (complex case). For a real-valued loss \ell with Wirtinger derivatives, d\ell = 2 \operatorname{Re}\!\bigl(\mathrm{tr}(\bar{A}^{\mathsf{H}} dA)\bigr). The JVP gives \dot{d} = \det(A) \cdot \mathrm{tr}(A^{-1} \dot{A}), and the chain rule contribution is \operatorname{Re}(\bar{d}^* \dot{d}) = \operatorname{Re}\!\bigl(\overline{\bar{d} \det(A)} \cdot \mathrm{tr}(A^{-1} \dot{A})\bigr). Matching with the Wirtinger inner product yields \bar{A} = \overline{\bar{d} \cdot \det(A)} \cdot A^{-\mathsf{H}}.
Singular matrix handling
When A is singular, A^{-1} does not exist, but \mathrm{adj}(A)^{\mathsf{T}} is well-defined:
- \mathrm{rank}(A) = N-1: \mathrm{adj}(A) is rank 1, computable via SVD: A = U \Sigma V^{\mathsf{H}} gives \mathrm{adj}(A) = V \mathrm{diag}(d) U^{\mathsf{H}} where d_k = \prod_{i \neq k} \sigma_i.
- \mathrm{rank}(A) \leq N-2: \mathrm{adj}(A) = 0.
Orientation / phase factor. The SVD-based adjugate formula above omits the orientation factor needed for correct sign/phase. Because \det(A) = \det(U) \cdot \prod_i \sigma_i \cdot \det(V^{\mathsf{H}}), when \sigma_k = 0 the adjugate picks up the phase of the non-zero singular values times \det(U) \det(V^{\mathsf{H}}). In practice the implementation must include:
\alpha = \overline{\bar{d} \cdot \det(U) \cdot \det(V^{\mathsf{H}})}
and then scale the leave-one-out product vector by \alpha:
\bar{A} = V (\alpha \cdot D) U^{\mathsf{H}}, \qquad D = \mathrm{diag}\!\bigl(\textstyle\prod_{i \neq k} \sigma_i\bigr)
PyTorch reference:
linalg_det_backward(L4354–4357) computesalpha = (det(U) * det(Vh)).conj() * grad, then passes the singular values throughprod_safe_zeros_backward(leave-one-out product via exclusive cumulative product) and scales byalpha.
2. Sign-Log-Determinant (slogdet)
Forward
(\mathrm{sign}, \mathrm{logabsdet}) = \mathrm{slogdet}(A)
where \det(A) = \mathrm{sign} \cdot \exp(\mathrm{logabsdet}).
- Real: \mathrm{sign} \in \{-1, 0, +1\}, \mathrm{logabsdet} = \log|\det(A)|.
- Complex: \mathrm{sign} = \det(A)/|\det(A)| (unit complex), \mathrm{logabsdet} = \log|\det(A)|.
Forward mode (JVP)
Let w = \mathrm{tr}(A^{-1} \dot{A}).
Real case:
\dot{\mathrm{logabsdet}} = w, \qquad \dot{\mathrm{sign}} = 0
(\mathrm{sign} is piecewise constant.)
Complex case:
\dot{\mathrm{logabsdet}} = \mathrm{Re}(w), \qquad \dot{\mathrm{sign}} = i \cdot \mathrm{Im}(w) \cdot \mathrm{sign}
Derivation. From \log\det(A) = \mathrm{logabsdet} + i\arg(\det(A)) and Jacobi’s formula d(\log\det(A)) = \mathrm{tr}(A^{-1} dA), the real part gives the log-magnitude derivative and the imaginary part gives the argument (phase) derivative. Since \mathrm{sign} = e^{i\arg(\det(A))}, we get d(\mathrm{sign}) = i \cdot d(\arg) \cdot \mathrm{sign}.
Reverse mode (VJP)
Given cotangents (\overline{\mathrm{sign}},\, \overline{\mathrm{logabsdet}}):
Real case (\overline{\mathrm{sign}} has no contribution):
\bar{A} = \overline{\mathrm{logabsdet}} \cdot A^{-\mathsf{T}}
Complex case:
\bar{A} = g \cdot A^{-\mathsf{H}}
where
g = \overline{\mathrm{logabsdet}} - i \cdot \mathrm{Im}(\overline{\mathrm{sign}}^* \cdot \mathrm{sign})
Derivation. Taking the adjoint of the JVP for each output:
logabsdet cotangent: \langle \bar{g}_{\mathrm{abs}},\, \mathrm{Re}(w) \rangle = \mathrm{Re}(\bar{g}_{\mathrm{abs}} \cdot w) = \langle \bar{g}_{\mathrm{abs}} \cdot A^{-\mathsf{H}},\, \dot{A} \rangle.
sign cotangent: Using \mathrm{Re}(z \cdot \mathrm{Im}(w)) = \mathrm{Re}(-\mathrm{Re}(z) \cdot i \cdot w), we get contribution -i \cdot \mathrm{Im}(\bar{g}_{\mathrm{sign}}^* \cdot \mathrm{sign}) \cdot A^{-\mathsf{H}}.
Combining yields the formula above.
Note on singularity
slogdet is not differentiable at singular matrices (\mathrm{logabsdet} = -\infty), unlike det.
Implementation notes
- Compute A^{-1} via LU factorization (never form A^{-1} explicitly); solve A X = I or A^{\mathsf{H}} X = g \cdot I.
- Cost: O(N^3), same as forward evaluation.
References
- Jacobi, C. G. J. (1841). “De formatione et proprietatibus determinantium.” J. Reine Angew. Math., 22, 285-318.
- Giles, M. B. (2008). “An extended collection of matrix derivative results for forward and reverse mode algorithmic differentiation.”
- PyTorch
FunctionsManual.cpp:linalg_det_backward(L4308),linalg_det_jvp(L4290),slogdet_backward(L4396),slogdet_jvp(L4376). - JAX
jax/_src/numpy/linalg.py:_slogdet_jvp,_det_jvp,_cofactor_solve. - ChainRules.jl
src/rulesets/LinearAlgebra/dense.jl:frule/rrulefordet,logdet,logabsdet.