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.

Conditional distributions & the Schur complement

Two faces of the same Gaussian:

  • Notebook 0.6 showed how to absorb evidence sequentially — each new observation is one natural-parameter addition.
  • This notebook shows the static version. Stack everything you know and don’t know into one big joint Gaussian, then read off the conditional in closed form.

For Gaussians these two views are mathematically identical. Operationally they’re complementary:

ViewWhen to useAPI
Sequential (0.6)Streaming data, online filtering, Kalman recursionsnatural-form addition + to_expectation
Conditioning (this notebook)All data in hand, GP prediction, joint surveysgaussx.conditional, schur_complement

The single algebraic object that makes the conditioning view work is the Schur complement. We

  1. recall the joint-partition formulae from 0.1;
  2. tour gaussx.conditional, gaussx.schur_complement, and gaussx.conditional_variance;
  3. verify GP regression matches both the natural-form recipe from ((5)) and the joint-conditioning recipe;
  4. close with gaussx.cov_transform — the forward counterpart, propagating uncertainty through a linear map.

Prerequisites: 0.1 — Multivariate Gaussian (especially ((8)) and ((9))), 0.6 — Bayesian updates.

The Schur complement, in one breath

Partition a joint Gaussian per ((6)):

[xaxb]∼N ⁣([μaμb],  [ΣaaΣabΣbaΣbb]).\begin{bmatrix} x_a \\ x_b \end{bmatrix} \sim \mathcal{N}\!\left( \begin{bmatrix} \mu_a \\ \mu_b \end{bmatrix},\; \begin{bmatrix} \Sigma_{aa} & \Sigma_{ab} \\ \Sigma_{ba} & \Sigma_{bb} \end{bmatrix} \right).

The conditional xa∣xb=bx_a \mid x_b = b is again Gaussian, with mean and covariance from ((8)) and ((9)):

μa∣b  =  μa+Σab Σbb−1 (b−μb),Σa∣b  =  Σaa−Σab Σbb−1 Σba.\mu_{a \mid b} \;=\; \mu_a + \Sigma_{ab}\,\Sigma_{bb}^{-1}\,(b - \mu_b), \qquad \Sigma_{a \mid b} \;=\; \Sigma_{aa} - \Sigma_{ab}\,\Sigma_{bb}^{-1}\,\Sigma_{ba}.

The conditional covariance Σa∣b\Sigma_{a \mid b} has a name independent of Gaussians: it’s the Schur complement of the bbbb block in the joint matrix:

  Σaa∣bb  =  Σaa  −  Σab Σbb−1 Σba  \boxed{\;\Sigma_{aa \mid bb} \;=\; \Sigma_{aa} \;-\; \Sigma_{ab}\,\Sigma_{bb}^{-1}\,\Sigma_{ba}\;}

((3)) is the algebraic backbone of every “low-rank correction to a covariance” you’ll meet — GP prediction, Kalman update, sparse-GP marginals, woodbury identities, the information form posterior covariance ((5)). Each is ((3)) with different letter assignments.

Step 1 — Schur on a hand-picked joint

Build a 5×5 joint covariance, partition into a={0,1},b={2,3,4}a = \{0, 1\}, b = \{2, 3, 4\}, and check gaussx.schur_complement against an explicit solve + matmul. The point is to see ((3)) is just a low-rank correction.

schur op type: LowRankUpdate
||S_schur - S_manual||_F = 0.00e+00
Schur block:
 [[ 1.69139834 -1.45474751]
 [-1.45474751  5.99356689]]

Step 2 — gaussx.conditional — high-level API

gaussx.conditional(loc, cov, obs_idx, obs_values) is the all-in-one wrapper: pass the joint mean/cov, the indices that are observed, and their values. Out comes the conditional mean/cov over the remaining indices. Internally it does ((2)) — including the Schur complement.

Below: same 5×5 joint, observe the last three coordinates at random values, condition on the first two.

||mu_cond  - mu_ref ||  = 0.00e+00
||Sig_cond - Sig_ref|| = 1.78e-15

Step 3 — GP regression is conditioning a joint

The standard “GP predictive” formula

μ⋆  =  K⋆f (Kff+σn2I)−1 y,Σ⋆  =  K⋆⋆  −  K⋆f (Kff+σn2I)−1 Kf⋆\mu_\star \;=\; K_{\star f}\,(K_{ff} + \sigma_n^2 I)^{-1}\,y, \qquad \Sigma_\star \;=\; K_{\star\star} \;-\; K_{\star f}\,(K_{ff} + \sigma_n^2 I)^{-1}\,K_{f\star}

is exactly ((2)) applied to the augmented joint over [y, f⋆][y,\, f_\star]:

[yf⋆]∼N ⁣(0,  [Kff+σn2IKf⋆K⋆fK⋆⋆]).\begin{bmatrix} y \\ f_\star \end{bmatrix} \sim \mathcal{N}\!\left(\mathbf{0},\; \begin{bmatrix} K_{ff} + \sigma_n^2 I & K_{f\star} \\ K_{\star f} & K_{\star\star} \end{bmatrix} \right).

The conditional covariance Σ⋆\Sigma_\star is the Schur complement ((3)). The same posterior emerges from the natural-form addition ((5)); the two recipes differ only in which block they invert.

We verify both routes agree on a 30-point sin GP.

max |mu_A  - mu_B|  = 5.31e-06
max |Sig_A - Sig_B| = 1.98e-06
KL( route A || route B ) = 1.76e-09
<Figure size 935x396 with 1 Axes>

Step 4 — Diagonal predictive variance only

Often we only need the marginal variance at each test point — the diagonal of Σ⋆\Sigma_\star. Forming the full n⋆×n⋆n_\star \times n_\star Schur block costs O(n⋆2ntrain)O(n_\star^2 n_{\rm train}); pulling out only the diagonal needs O(n⋆ntrain)O(n_\star n_{\rm train}) via

σ⋆2(i)  =  K⋆⋆(i,i)  −  (K⋆f Kff−1 Kf⋆)(i,i),i=1,…,n⋆.\sigma_\star^2(i) \;=\; K_{\star\star}(i, i) \;-\; \bigl(K_{\star f}\,K_{ff}^{-1}\,K_{f\star}\bigr)(i, i), \qquad i = 1, \ldots, n_\star.

For the exact GP this is just einx-summing the Hadamard product K_sf * (K_ff^{-1} K_fs)^\top, no full Schur block needed. For the sparse / variational GP, gaussx.conditional_variance(K_xx_diag, A_x, S_u) adds the variational correction diag(Ax Su Ax⊤)\mathrm{diag}(A_x\,S_u\,A_x^\top) on top — same formula, but SuS_u is the variational covariance over inducing points instead of the prior.

max |diag(Schur) - diag-only formula| = 1.98e-06
max |K_ss_diag - diag(A K_ff A^T) - exact pred_var| = 1.98e-06

Step 5 — Forward propagation: cov_transform

The Schur complement runs backward — we condition on observed coordinates and project the joint covariance onto the unobserved ones. The dual operation runs forward: given a Gaussian on xx and a linear map z=Jxz = J x, the induced Gaussian on zz has covariance

Σz  =  J Σx J⊤.\Sigma_z \;=\; J\,\Sigma_x\,J^\top.

gaussx.cov_transform(J, Sigma_op) returns this as a structured operator — no matrices materialised when Σx\Sigma_x is itself structured (Kronecker, low-rank, etc.). This is the basic step in:

  • linearised filters (UKF / EKF prediction step),
  • linear sensitivity analysis,
  • variational inference (computing HΣH⊤+RH \Sigma H^\top + R),
  • delta-method confidence intervals.
||cov_transform - J Sigma J^T||_F = 7.16e-15

Where the Schur complement lives

SettingLettersReference
GP predictiona=⋆, b=a = \star,\ b = train((4)), this notebook
Kalman update covariancea=a = state,\ b=b = innovation((4))
Information-form posteriorΛ+=Λ+H⊤R−1H\Lambda^+ = \Lambda + H^\top R^{-1} H((5))
Sparse-GP predictive (FITC / SVGP)a=a = test,\ b=b = inducingPart 6
Bayesian linear regressiona=a = weights,\ b=b = dataConjugate update via ((2))
Causal / structural marginalsa=a = effect,\ b=b = confoundersStatistics literature
Block matrix inversionInverse of partitioned matrix is built from the two Schur complementsLinear-algebra textbook identity

Recap

  • The Gaussian conditioning theorem ((2)) reduces to the Schur complement ((3)).
  • gaussx.conditional is the all-in-one API; schur_complement returns a structured LowRankUpdate so downstream solve/logdet can exploit the rank correction; conditional_variance short-cuts to the diagonal.
  • GP regression with a Gaussian likelihood matches both this conditioning recipe (((4))) and the natural-form recipe from ((5)), to machine precision and in KL.
  • The forward dual cov_transform propagates uncertainty Σz=JΣxJ⊤\Sigma_z = J \Sigma_x J^\top through linear maps — the building block for filter prediction steps and sensitivity analysis.

References

  • Rasmussen, C. E. & Williams, C. K. I. (2006). Gaussian Processes for Machine Learning. MIT Press, §2.2.
  • Bishop, C. M. (2006). Pattern Recognition and Machine Learning. Springer, §2.3.1.
  • Boyd, S. & Vandenberghe, L. (2004). Convex Optimization, Appendix A.5 (Schur complements).