Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

MultivariateNormal & MultivariateNormalPrecision: the API tour

Notebook 0.1 introduced the multivariate normal as a math object. This notebook is the API tour: gaussx ships two distribution classes for the same family — one parameterised by the covariance Σ\boldsymbol{\Sigma}, one by the precision Λ=Σ−1\boldsymbol{\Lambda} = \boldsymbol{\Sigma}^{-1}. They expose the same surface (.sample, .log_prob, .entropy, .mean, .variance) but route through different primitives under the hood.

What you’ll learn

  1. The two parameterisations of a Gaussian and when each one is preferred.
  2. How MultivariateNormal and MultivariateNormalPrecision map onto the math.
  3. Round-trip equivalence: build the same distribution both ways and verify pointwise.
  4. Why precision form wins when Λ\boldsymbol{\Lambda} is sparse but Σ\boldsymbol{\Sigma} is dense — the GMRF / Markov story.
  5. A taste of natural parameters as a third equivalent representation.

1. Two parameterisations of one distribution

The same Gaussian can be written either with covariance Σ\boldsymbol{\Sigma} or with precision Λ=Σ−1\boldsymbol{\Lambda} = \boldsymbol{\Sigma}^{-1}:

N(x;μ,Σ)=(2π)−d/2∣Σ∣−1/2exp⁡ ⁣(−12(x−μ)⊤Σ−1(x−μ)),\mathcal{N}(\mathbf{x}; \boldsymbol{\mu}, \boldsymbol{\Sigma}) = (2\pi)^{-d/2}|\boldsymbol{\Sigma}|^{-1/2}\exp\!\left(-\tfrac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^\top\boldsymbol{\Sigma}^{-1}(\mathbf{x}-\boldsymbol{\mu})\right),
N−1(x;μ,Λ)=(2π)−d/2∣Λ∣1/2exp⁡ ⁣(−12(x−μ)⊤Λ(x−μ)).\mathcal{N}^{-1}(\mathbf{x}; \boldsymbol{\mu}, \boldsymbol{\Lambda}) = (2\pi)^{-d/2}|\boldsymbol{\Lambda}|^{1/2}\exp\!\left(-\tfrac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^\top\boldsymbol{\Lambda}(\mathbf{x}-\boldsymbol{\mu})\right).

Equation ((1)) and equation ((2)) are the same density whenever ΛΣ=I\boldsymbol{\Lambda}\boldsymbol{\Sigma}=\mathbf{I}. The choice between them is a computational one, driven by which of the two matrices has nice structure:

FormCheap to doExpensive
Covariance Σ\boldsymbol{\Sigma}sampling, marginalisationconditioning on partial obs
Precision Λ\boldsymbol{\Lambda}conditioning, evidence updatessampling, marginalisation

The structural sparsity also flips:

  • Conditional independence Xi⊥Xj∣X∖ijX_i \perp X_j \mid X_{\setminus ij} shows up as Λij=0\Lambda_{ij} = 0. So Markov / GMRF / state-space models have sparse Λ\boldsymbol{\Lambda} even when Σ\boldsymbol{\Sigma} is dense.
  • Marginal independence Xi⊥XjX_i \perp X_j shows up as Σij=0\Sigma_{ij} = 0. Block-diagonal Σ\boldsymbol{\Sigma} corresponds to genuinely independent groups, which is rarely what we have.

Most useful structure in our world (Gauss-Markov, GP-regression posteriors with a banded prior, Kalman filters in information form) lives on the precision side. That’s why gaussx exposes both.

2. MultivariateNormal — the covariance form

MultivariateNormal(loc, cov_operator, solver=None) takes a mean vector and a lineax operator wrapping the covariance. Internally everything routes through Cholesky on Σ\boldsymbol{\Sigma} — the form recommended by equation 7 in notebook 0.1.

The class is a numpyro distribution, so the surface is what you’d expect: .sample(key, shape), .log_prob(x), .entropy(), .mean, .variance, plus a JIT-friendly PyTree structure (it’s an equinox.Module underneath).

class       : MultivariateNormal
event_shape : (5,)
mean        : [-1.  -0.5  0.   0.5  1. ]
variance    : [1.001 1.001 1.001 1.001 1.001]
entropy     : 5.906610734624831
log_prob(0) : -4.423604950410503
samples     :
 [[-2.18487642 -1.31040824 -0.10887068  1.2756854   1.08020205]
 [-0.30884951 -0.02116252 -0.42299327 -0.03140923 -0.13141221]
 [-1.98641018 -1.98899925 -0.51940089  1.05657527  2.38460391]
 [-1.64650165 -0.29508526  0.04926346  1.27186838  1.96739098]]

3. MultivariateNormalPrecision — the precision form

MultivariateNormalPrecision(loc, prec_operator, solver=None) takes the same mean but a lineax operator wrapping Λ\boldsymbol{\Lambda}. The constructor does not form Σ=Λ−1\boldsymbol{\Sigma} = \boldsymbol{\Lambda}^{-1}. Instead, internal solves invert Λ\boldsymbol{\Lambda} on demand for sampling, and the log-density is computed directly from Λ\boldsymbol{\Lambda} via

log⁡p(x)=−d2log⁡(2π)+12log⁡∣Λ∣−12(x−μ)⊤Λ(x−μ).\log p(\mathbf{x}) = -\tfrac{d}{2}\log(2\pi) + \tfrac{1}{2}\log|\boldsymbol{\Lambda}| - \tfrac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^\top\boldsymbol{\Lambda}(\mathbf{x}-\boldsymbol{\mu}).

Note the sign flip on log⁡∣⋅∣\log|\cdot| — we add half the log-determinant of Λ\boldsymbol{\Lambda} instead of subtracting it on Σ\boldsymbol{\Sigma}, since log⁡∣Λ∣=−log⁡∣Σ∣\log|\boldsymbol{\Lambda}| = -\log|\boldsymbol{\Sigma}|.

class       : MultivariateNormalPrecision
event_shape : (5,)
mean        : [-1.  -0.5  0.   0.5  1. ]
variance    : [1.001 1.001 1.001 1.001 1.001]
entropy     : 5.906610734624831
log_prob(0) : -4.423604950410503
samples     :
 [[-1.88408505 -0.32220482  0.6460971   0.75697977  0.16662948]
 [-0.58592842 -0.98340752 -0.78248253 -0.36021689 -0.35315028]
 [-2.37514015 -0.87866177  0.91630359  1.74900216  2.2819309 ]
 [-1.0179202  -0.06179605  0.5616257   1.68236386  1.16375959]]

4. Round-trip equivalence

Equation ((1)) and equation ((2)) are the same distribution whenever ΛΣ=I\boldsymbol{\Lambda}\boldsymbol{\Sigma} = \mathbf{I}. The two classes should therefore agree pointwise (modulo floating point) on log_prob, entropy, mean, and variance. Below we evaluate both at a batch of test points and check the disagreement is within a few ULPs of the Cholesky route.

max |Δ log_prob|       : 1.42e-14
max |Δ quadratic form| : 0.00e+00
|Δ entropy|            : 0.00e+00
|Δ mean|_inf           : 0.00e+00
|Δ variance|_inf       : 2.22e-16
<Figure size 550x440 with 1 Axes>

5. When precision wins: a banded GMRF

The case for MultivariateNormalPrecision is strongest when Λ\boldsymbol{\Lambda} is sparse — i.e. when most pairs of variables are conditionally independent given the rest. The canonical example is a first-order Gauss-Markov chain:

Xt=ρ Xt−1+σ εt,εt∼N(0,1),X_t = \rho\,X_{t-1} + \sigma\,\varepsilon_t, \qquad \varepsilon_t \sim \mathcal{N}(0,1),

whose joint distribution has a tridiagonal precision matrix

Λtt=1+ρ2σ2    (interior),Λt,t+1=−ρσ2,Λtt=1σ2    (boundary).\Lambda_{tt} = \frac{1+\rho^2}{\sigma^2}\;\;(\text{interior}),\quad \Lambda_{t,t+1} = -\frac{\rho}{\sigma^2},\quad \Lambda_{tt} = \frac{1}{\sigma^2}\;\;(\text{boundary}).

The corresponding Σ=Λ−1\boldsymbol{\Sigma} = \boldsymbol{\Lambda}^{-1} is dense — every XsX_s and XtX_t are marginally correlated, even far-apart ones. So the precision representation has O(n)O(n) non-zeros while the covariance has O(n2)O(n^2).

For this notebook we use a moderate n=64n=64 and dense storage so the sparsity pattern is easy to see. In production gaussx routes this through BlockTriDiag (see Part 1.5) for O(n)O(n) solves; here we only want the visual.

AR(1) precision : nnz fraction = 0.046  (tridiagonal)
AR(1) covariance: nnz fraction = 1.000   (dense)
<Figure size 990x440 with 4 Axes>
log p via Λ : -119.203845
log p via Σ : -119.203845
<Figure size 770x308 with 1 Axes>

6. A taste of natural parameters

There’s a third equivalent representation we’ll see in detail in 0.4 — Mean-cov ↔ natural parameter conversions. Briefly: every Gaussian can be written in natural parameter form

p(x)∝exp⁡ ⁣(η1⊤x+x⊤η2x),η1=Λμ,η2=−12Λ.p(\mathbf{x}) \propto \exp\!\left(\boldsymbol{\eta}_1^\top \mathbf{x} + \mathbf{x}^\top \boldsymbol{\eta}_2 \mathbf{x}\right), \qquad \boldsymbol{\eta}_1 = \boldsymbol{\Lambda}\boldsymbol{\mu}, \qquad \boldsymbol{\eta}_2 = -\tfrac{1}{2}\boldsymbol{\Lambda}.

This form is what makes Bayesian updates pure addition — combining evidence is ηpost=ηprior+ηlik\boldsymbol{\eta}_{\text{post}} = \boldsymbol{\eta}_{\text{prior}} + \boldsymbol{\eta}_{\text{lik}} — and underpins variational inference and natural gradient methods. gaussx ships explicit converters; here’s the round-trip.

eta_1  =  Λ μ      : [-1.10990703e+00  1.85825628e-01 -2.82887645e-16 -1.85825628e-01
  1.10990703e+00]
eta_2  =  -Λ/2     :
[[-0.97606728  0.91615634 -0.60815128  0.33436378 -0.13021749]
 [ 0.91615634 -1.81861765  1.44237175 -0.84085816  0.33436378]
 [-0.60815128  1.44237175 -2.08299373  1.44237175 -0.60815128]
 [ 0.33436378 -0.84085816  1.44237175 -1.81861765  0.91615634]
 [-0.13021749  0.33436378 -0.60815128  0.91615634 -0.97606728]]

round-trip residuals
  max|Δ μ|  : 3.33e-16
  max|Δ Σ|  : 2.22e-16

7. Recap & where to go next

You now know how to build a Gaussian both ways and which one to reach for:

OperationMultivariateNormal (Σ)MultivariateNormalPrecision (Λ)
ConstructorMultivariateNormal(loc, Σ_op)MultivariateNormalPrecision(loc, Λ_op)
Samplingcheap (Cholesky of Σ)requires inverting Λ
log_probuses Cholesky of Σuses Cholesky of Λ directly
Conditioning on partial obsdense Schur block solvetrivial; rows of Λ partition cleanly
Best whenΣ has low-rank / Kron / dense structureΛ is banded / sparse / Markov
Internal log-det−12log⁡∣Σ∣-\tfrac{1}{2}\log\lvert\Sigma\rvert+12log⁡∣Λ∣+\tfrac{1}{2}\log\lvert\Lambda\rvert

Next up.