Every dependency is a commitment. This document records what we depend on and why, and what we deliberately do not.
Three hosting modes:
- Core
[deps]— always loaded; every user pays the cost. - Weakdep + extension — loaded only when the user brings the trigger package. The extension cannot export new symbols, only extend methods on types owned by the core package (Julia 1.9+ rule).
- Sub-package — separately-installed package in
packages/that depends on the core. Can freely export new symbols; has its own release cadence, test matrix, and Project.toml.
When a heavy integration (Turing, Rasters, Pardiso) is needed, a
sub-package is preferred over a weakdep because it gates the cost
behind an explicit Pkg.add, makes failure modes visible, and does not
inflate the core's test matrix. Extensions are kept for lightweight
convenience integrations (Makie recipes, GeoInterface acceptance,
ChainRules AD rules for Zygote/Enzyme users).
| Package | Purpose | Notes |
|---|---|---|
| SparseArrays | Sparse matrix representation of Q | stdlib |
| LinearAlgebra | Dense linear algebra, BLAS calls | stdlib |
| Random | RNG interface | stdlib |
| Graphs | Graph structure, connected components, adjacency | JuliaGraphs |
| LinearSolve | Swappable sparse factorization backend (CHOLMOD / KLU / Pardiso) | SciML |
| Distributions | Priors as first-class distribution objects | standard |
| Statistics | Statistical summaries | stdlib |
| ChainRulesCore | AD rules — deferred to v0.2, removed from [deps] in Phase E1 hardening because no rrules were written (would have failed Aqua's stale-deps check). Re-add with the first shipped rule. |
standard |
| SelectedInversion | diag(Q⁻¹) on the sparse Cholesky pattern; default marginal_variances path |
see ADR-012 |
Weakdeps (extensions):
| Package | Extension | Purpose |
|---|---|---|
| MakieCore | GMRFsMakieExt |
Plotting recipes (MakieCore only — the recipes half, lightweight) |
| Package | Purpose | Notes |
|---|---|---|
| GMRFs | This ecosystem | core dep |
| LinearAlgebra, Random, SparseArrays, Statistics | stdlib | |
| Distributions | Likelihoods and priors | standard |
| LogDensityProblems | Standard interface for posterior log-density — the seam for downstream samplers | standard |
| Optimization, OptimizationOptimJL | Outer θ-mode finding | SciML |
| FastGaussQuadrature | Gauss-Hermite nodes | standard |
| QuadGK | 1D marginal integration | standard |
| ADTypes | AD backend selection | SciML |
| FiniteDiff | Finite-difference fallbacks | SciML |
| Printf | Summary formatting | stdlib |
NonlinearSolve and Roots were declared in early drafts; the actual
implementations use a custom Newton (in-place over FactorCache) and a
robust bisection on λ for the BYM2 PC prior. Both were removed in
Phase E1 hardening to keep [deps] honest under Aqua's stale-dep scan;
re-add when a real call site lands.
Weakdeps (extensions):
| Package | Extension | Purpose |
|---|---|---|
| MakieCore | LGMMakieExt |
Posterior plot recipes |
| HCubature | LGMHCubatureExt |
Adaptive cubature for posterior expectations |
| Integrals | LGMIntegralsExt |
SciML-style quadrature backend selection |
| Package | Purpose | Notes |
|---|---|---|
| LatentGaussianModels | This ecosystem | core dep |
| Meshes | 2D/3D mesh representation, topology | JuliaEarth |
| DelaunayTriangulation | Constrained Delaunay mesh generation | standard |
| SciMLOperators | Lazy projector operators | SciML |
| CoordRefSystems | CRS-aware distances, great-circle Matérn on sphere | JuliaEarth |
Weakdeps (extensions):
| Package | Extension | Purpose |
|---|---|---|
| GeoInterface | INLASPDEGeoInterfaceExt |
Accept any GeoInterface geometry |
| MakieCore | INLASPDEMakieExt |
Mesh + field plotting |
Each has its own CLAUDE.md, plans/plan.md, and Project.toml under
packages/. Users install only what they need.
| Sub-package | Depends on (ecosystem + outside) | Role |
|---|---|---|
LGMFormula.jl |
LatentGaussianModels + StatsModels | Tier-2 @lgm formula sugar. Defer to Phase 3 tail. See ADR-008. |
LGMTuring.jl |
LatentGaussianModels + Turing + AdvancedHMC | HMC/NUTS bridge, INLA-within-MCMC. Defer to Phase 3 tail / Phase 5. See ADR-009. |
GMRFsPardiso.jl |
GMRFs + Pardiso | MKL Pardiso / Panua Pardiso factorization backend. License-gated; explicit install makes failure modes visible. |
INLASPDERasters.jl |
INLASPDE + Rasters | Covariate extraction + prediction surfaces. Rasters transitively pulls GDAL_jll/Proj_jll (~hundreds of MB) — too heavy for a weakdep. |
- Export new symbols.
@lgm,NUTSconvenience constructors, aPardiso.PardisoFactorization()re-export — none of these can be exported from a weakdep extension. - Heavy transitive deps. Turing (20–40 s TTFX), Rasters
(GDAL_jll, Proj_jll), Pardiso (license-gated MKL or Panua) all inflate
even an unused weakdep's install footprint. A sub-package gates the
cost behind an explicit
Pkg.add. - Independent release cadence. Turing and Rasters evolve on their own schedules. Pinning core LGM's CI to their master branches would be churn.
- Clear failure modes. If
LGMTuring.jlis broken on a given Julia version, core INLA still works. Weakdep extensions can fail at load time in ways that look like core-package bugs.
- DynamicPPL / Turing as core deps. Turing is a downstream consumer
via
LogDensityProblems.LGMTuring.jlbridges it; core LGM has no Turing dep of any kind. - MLJ. Out of scope. A separate
MLJLatentGaussianModels.jlcould provide a bridge later. - DataFrames anywhere in the ecosystem. Tables.jl-compatible inputs
are fine; DataFrames adds no affordance over Tables. An earlier draft
had
LGMDataFramesExt; dropped. - Reimplementing SuiteSparse / CHOLMOD. LinearSolve.jl already abstracts this.
- fmesher wrapping in core. Native Julia mesh generation via
DelaunayTriangulation.jl is the Phase-4 plan. A BinaryBuilder-based
wrapper of
fmesheris a possible sub-package if DelaunayTriangulation proves inadequate. See ADR-007. - Makie (full) in core deps. MakieCore weakdep only. Users who plot bring Makie themselves.
- StatsModels as a core dep of LGM. It lives in
LGMFormula.jl, nowhere else.
- Target Julia 1.10 LTS and current stable minor. Nightly in CI.
- Use
[compat]bounds on every[deps]entry. Pin major versions; bump minor when we test against them. Inter-package deps within this monorepo (GMRFs = "0.1", etc.) also carry compat bounds — a breaking change in one should not ripple silently into the others. - LinearSolve, NonlinearSolve, Optimization, Meshes, Turing, Rasters all evolve faster than our cadence. CI includes a nightly job against the master branches of the core-dep ones to catch breakages early; for sub-package deps (Turing, Rasters), each sub-package runs its own nightly matrix.
Before adding a new entry to [deps] anywhere:
- Check this file — is it explicitly forbidden or deferred?
- Is the right host a weakdep extension, or a new sub-package?
- If a sub-package, scaffold
packages/<Name>.jl/with its own CLAUDE.md + plans/plan.md + Project.toml. - Write an ADR in
plans/decisions.mdwith the rationale and link the PR.
Earlier drafts had it as a core dep. It is not, because the θ-integration
in INLA exploits the Gaussian shape of π(θ ∣ y) around its mode — CCD,
grid, and Gauss-Hermite in the eigenbasis of −H(θ*) are not adaptive
cubature, and a generic black-box integrator would waste Cholesky
evaluations. CCD and grid are hand-written on top of FastGaussQuadrature
plus raw arrays. Integrals is useful for user-facing posterior
expectations, which is a weakdep.
For connected-component detection (disconnected ICAR sum-to-zero
correctness), Kronecker graph products, user-facing adjacency
construction, and interop with the rest of JuliaGraphs. At extreme
scales (SPDE meshes with 10⁶+ nodes) we may provide a lazy
AbstractGraph wrapper on top of SparseMatrixCSC to avoid
materializing SimpleGraph; the interface is open enough.