Skip to content

Latent Models

Latent models provide a structured way to define commonly used Gaussian Markov Random Fields (GMRFs) by specifying their key components: hyperparameters, precision matrices, mean vectors, and constraints. This abstraction enables easy construction and combination of standard models used in spatial statistics, time series analysis, and Bayesian modeling.

Overview

The LatentModel interface standardizes GMRF construction through a simple pattern:

  1. Define the model structure (e.g., temporal, spatial, independence)

  2. Specify hyperparameters and their validation

  3. Construct GMRFs with automatic constraint handling

julia
using GaussianMarkovRandomFields

# Define a temporal AR1 model
ar1 = AR1Model(100)
hyperparameters(ar1)  # (τ = Real, ρ = Real)

# Construct GMRF with specific parameters
gmrf = ar1=2.0, ρ=0.8)  # Returns GMRF or ConstrainedGMRF automatically

LatentModel Interface

GaussianMarkovRandomFields.LatentModel Type
julia
LatentModel

Abstract type for latent variable models that can be used to construct GMRFs.

A LatentModel provides a structured way to define commonly used GMRFs such as AR1, RW1, and other temporal/spatial models by specifying:

  1. The hyperparameters of the model

  2. How to construct the precision matrix from hyperparameters

  3. How to construct the mean vector from hyperparameters

  4. Any linear constraints that should be applied

Interface

Each concrete subtype must implement:

  • length(model): Return the size/dimension of the latent process

  • hyperparameters(model): Return a NamedTuple describing the hyperparameters

  • precision_matrix(model; kwargs...): Construct precision matrix from hyperparameter values

  • mean(model; kwargs...): Construct mean vector from hyperparameter values

  • constraints(model; kwargs...): Return constraint information or nothing

  • model_name(model): Return a Symbol representing the preferred name for this model type

  • (model)(; kwargs...): Instantiate a concrete GMRF from hyperparameter values

Usage

julia
# Define a model
model = SomeLatentModel(n=100)

# Get hyperparameter specification
params = hyperparameters(model)  # e.g. (τ=Real, ρ=Real)

# Instantiate GMRF with specific parameter values
gmrf = model=2.0, ρ=0.8)  # Returns GMRF or ConstrainedGMRF
source
GaussianMarkovRandomFields.hyperparameters Method
julia
hyperparameters(model::LatentModel)

Return a NamedTuple describing the hyperparameters and their types for the model.

Returns

A NamedTuple where keys are parameter names and values are their expected types.

source
GaussianMarkovRandomFields.precision_matrix Method
julia
precision_matrix(model::LatentModel; kwargs...)

Construct the precision matrix for the model given hyperparameter values.

Arguments

  • model: The LatentModel instance

  • kwargs...: Hyperparameter values as keyword arguments

Returns

A precision matrix (AbstractMatrix or LinearMap) for use in GMRF construction.

source
Statistics.mean Function
julia
mean(model::LatentModel; kwargs...)

Construct the mean vector for the model given hyperparameter values.

Arguments

  • model: The LatentModel instance

  • kwargs...: Hyperparameter values as keyword arguments

Returns

A mean vector (AbstractVector) for use in GMRF construction.

source
GaussianMarkovRandomFields.constraints Function
julia
constraints(model::LatentModel; kwargs...)

Return constraint information for the model given hyperparameter values.

Arguments

  • model: The LatentModel instance

  • kwargs...: Hyperparameter values as keyword arguments

Returns

Either nothing if no constraints, or a tuple (A, e) where A is the constraint matrix and e is the constraint vector such that Ax = e.

source
GaussianMarkovRandomFields.model_name Function
julia
model_name(model::LatentModel)

Return a Symbol representing the preferred name for this model type.

This name is used for parameter prefixing in CombinedModel to avoid conflicts. For example, if two models both have a τ parameter, they become τ_ar1, τ_besag, etc.

Returns

A Symbol that will be used as the suffix in parameter names.

source

Available Models

Temporal Models

GaussianMarkovRandomFields.AR1Model Type
julia
AR1Model(n::Int; alg=LDLtFactorization(), constraint=nothing)

A first-order autoregressive (AR1) latent model for constructing AR1 GMRFs.

The AR1 model represents a temporal process where each observation depends on the previous observation with some correlation ρ and precision τ.

Mathematical Description

For n observations, the AR1 process has:

  • Zero mean: μ = 0

  • Precision matrix Q with tridiagonal structure:

    • Q[1,1] = τ

    • Q[i,i] = (1 + ρ²)τ for i = 2,...,n-1

    • Q[n,n] = τ

    • Q[i,i+1] = Q[i+1,i] = -ρτ for i = 1,...,n-1

Hyperparameters

  • τ: Precision parameter (τ > 0)

  • ρ: Correlation parameter (|ρ| < 1)

Fields

  • n::Int: Length of the AR1 process

  • alg::Alg: LinearSolve algorithm for solving linear systems

  • constraint::C: Optional constraint, either nothing or (A, e) tuple

Example

julia
model = AR1Model(100)
gmrf = model=2.0, ρ=0.8)  # Construct unconstrained AR1 GMRF

# With sum-to-zero constraint
model = AR1Model(100, constraint=:sumtozero)
gmrf = model=2.0, ρ=0.8)  # Returns ConstrainedGMRF

# With custom constraint
A = [1.0 1.0 zeros(98)...]
e = [0.0]
model = AR1Model(100, constraint=(A, e))
gmrf = model=2.0, ρ=0.8)
source
GaussianMarkovRandomFields.RW1Model Type
julia
RW1Model(n::Int; regularization=1e-5, alg=LDLtFactorization(), additional_constraints=nothing)

A first-order random walk (RW1) latent model for constructing intrinsic GMRFs.

The RW1 model represents a non-stationary temporal process where each observation is the previous observation plus Gaussian noise. This creates a smooth trend model that's popular for temporal smoothing and time-varying effects.

Mathematical Description

The RW1 process defines increments: x[i+1] - x[i] ~ N(0, τ⁻¹) for i = 1,...,n-1. This leads to a singular precision matrix with the tridiagonal structure:

  • Q[1,1] = 1, Q[n,n] = 1

  • Q[i,i] = 2 for i = 2,...,n-1

  • Q[i,i+1] = Q[i+1,i] = -1 for i = 1,...,n-1

Since this matrix is singular (rank n-1), we handle it as an intrinsic GMRF by:

  1. Scaling by τ first, then adding small regularization (1e-5) to diagonal for numerical stability

  2. Always adding sum-to-zero constraint: sum(x) = 0 (required for identifiability)

Hyperparameters

  • τ: Precision parameter (τ > 0)

Fields

  • n::Int: Length of the RW1 process

  • regularization::Float64: Small value added to diagonal after scaling (default 1e-5)

  • alg::Alg: LinearSolve algorithm for solving linear systems

  • additional_constraints::C: Optional additional constraints beyond the required sum-to-zero

Example

julia
model = RW1Model(100)
gmrf = model=1.0)  # Returns ConstrainedGMRF with sum-to-zero constraint

# Add additional constraint (e.g., fix first element to 0)
A_add = reshape([1.0; zeros(99)], 1, 100)
e_add = [0.0]
model = RW1Model(100, additional_constraints=(A_add, e_add))
gmrf = model=1.0)  # Returns ConstrainedGMRF with both sum-to-zero AND additional constraint
source

Spatial Models

GaussianMarkovRandomFields.MaternModel Type
julia
MaternModel{F<:FEMDiscretization,S<:Integer,Alg}(discretization::F, smoothness::S, alg::Alg)

A Matérn latent model for constructing spatial GMRFs from discretized Matérn SPDEs.

The MaternModel provides a structured way to define Matérn Gaussian Markov Random Fields by discretizing the Matérn SPDE using finite element methods. The model stores the discretization and smoothness parameter, while the range parameter is provided at GMRF construction time.

Mathematical Description

The Matérn SPDE is given by: (κ² - Δ)^(α/2) u(x) = W(x), where α = ν + d/2

This leads to a Matérn covariance function with range and smoothness parameters.

Two Construction Modes

  1. Direct construction: Pass a pre-built FEMDiscretization

  2. Automatic construction: Pass points, automatically creates convex hull mesh

Hyperparameters

  • range: Range parameter (range > 0) - controls spatial correlation distance

Fields

  • discretization::F: The finite element discretization

  • smoothness::S: The smoothness parameter (Integer, controls differentiability)

  • alg::Alg: LinearSolve algorithm for solving linear systems

Examples

julia
# Direct construction
disc = FEMDiscretization(grid, interpolation, quadrature)
model = MaternModel(disc; smoothness = 2)
gmrf = model(range=2.0)

# Automatic construction from points
points = [0.0 0.0; 1.0 0.0; 0.5 1.0]  # N×2 matrix
model = MaternModel(points; smoothness = 1, element_order = 1)
gmrf = model(range=2.0)

# With custom algorithm
model = MaternModel(disc; smoothness = 2, alg = LDLtFactorization())
gmrf = model(range=2.0)
source
GaussianMarkovRandomFields.BesagModel Type
julia
BesagModel(adjacency::AbstractMatrix; regularization::Float64 = 1e-5, normalize_var::Bool = true, singleton_policy::Symbol = :gaussian, alg=CHOLMODFactorization())

A Besag model for spatial latent effects on graphs using intrinsic Conditional Autoregressive (CAR) structure.

The Besag model represents spatial dependence where each node's precision depends on its graph neighbors. This creates a graph Laplacian precision structure that's widely used for spatial smoothing on irregular lattices.

Mathematical Description

For a graph with adjacency matrix W, the precision matrix follows:

  • Q[i,j] = -τ if nodes i and j are neighbors (W[i,j] = 1)

  • Q[i,i] = τ * degree[i] where degree[i] = sum(W[i,:])

  • All other entries are 0

Since this matrix is singular (rank n-1), we handle it as an intrinsic GMRF by:

  1. Scaling by τ first, then adding small regularization (1e-5) to diagonal for numerical stability

  2. Adding sum-to-zero constraint: sum(x) = 0

Hyperparameters

  • τ: Precision parameter (τ > 0)

Fields

  • adjacency::M: Adjacency matrix W (preserves input structure - sparse, SymTridiagonal, etc.)

  • regularization::Float64: Small value added to diagonal after scaling (default 1e-5)

  • alg::Alg: LinearSolve algorithm for solving linear systems

Example

julia
# 4-node cycle graph - can use sparse, SymTridiagonal, or Matrix
W = sparse(Bool[0 1 0 1; 1 0 1 0; 0 1 0 1; 1 0 1 0])
model = BesagModel(W)
gmrf = model=1.0)  # Returns ConstrainedGMRF with sum-to-zero constraint using CHOLMODFactorization

# Or specify custom algorithm
model = BesagModel(W, alg=LDLtFactorization())
gmrf = model=1.0)
source
GaussianMarkovRandomFields.BYM2Model Type
julia
BYM2Model(adjacency::AbstractMatrix; regularization::Float64 = 1e-5, normalize_var::Bool = true, singleton_policy::Symbol = :gaussian, alg=CHOLMODFactorization(), additional_constraints=nothing, iid_constraint=nothing)

Besag-York-Mollié model with improved BYM2 parameterization (Riebler et al. 2016).

The BYM2 model is a reparameterization of the classic BYM model for disease mapping that improves interpretability and facilitates prior specification. It combines spatial (ICAR) and unstructured (IID) random effects with intuitive mixing and precision parameters.

Mathematical Description

The BYM2 model is a 2n-dimensional latent field stacking:

  1. A scaled spatial component: u* ~ ICAR with variance-normalized precision Q*

  2. An unstructured component: v* ~ N(0, I)

The block-diagonal precision matrix is:

Q = [ τ/(1-φ) * Q*    0           ]
    [ 0               τ/φ * I     ]

In the linear predictor, effects are added: η[i] = ... + u_[i] + v_[i]

This parameterization ensures:

  • Var(u*[i]) ≈ (1-φ)/τ (spatial variance)

  • Var(v*[i]) = φ/τ (unstructured variance)

  • Var(u_[i] + v_[i]) = 1/τ (total variance)

  • φ controls the proportion of variance that is unstructured

  • φ = 0: pure spatial model (like scaled Besag)

  • φ = 1: pure unstructured model (like scaled IID)

Hyperparameters

  • τ: Overall precision parameter (τ > 0)

  • φ: Mixing parameter (0 < φ < 1), proportion of unstructured variance

Fields

  • besag::BesagModel: The spatial component (variance-normalized)

  • iid::IIDModel: The unstructured component

  • n::Int: Number of spatial units

  • alg::Alg: LinearSolve algorithm for solving linear systems

Identifiability and Constraints

When using BYM2 with a fixed intercept, the model can be unidentifiable because the unstructured component v* can absorb any constant shift. To handle this:

  1. No intercept (recommended): Use y ~ 0 + bym2(region) in formulas

  2. Constrain IID: Pass iid_constraint=:sumtozero to ensure identifiability

The spatial component u* always has a sum-to-zero constraint (one per connected component).

Example

julia
# 4-node cycle graph
W = sparse(Bool[0 1 0 1; 1 0 1 0; 0 1 0 1; 1 0 1 0])

# Standard BYM2 (use with y ~ 0 + ...)
model = BYM2Model(W)
gmrf = model=1.0, φ=0.5)  # Equal spatial and unstructured variance

# BYM2 with IID constraint (use with y ~ 1 + ... to include intercept)
model_constrained = BYM2Model(W; iid_constraint=:sumtozero)
gmrf = model_constrained=1.0, φ=0.5)  # Both components sum to zero

# More spatial smoothing (90% spatial, 10% unstructured)
gmrf = model=1.0, φ=0.1)

# More unstructured variation (10% spatial, 90% unstructured)
gmrf = model=1.0, φ=0.9)

References

Riebler, A., Sørbye, S. H., Simpson, D., & Rue, H. (2016). An intuitive Bayesian spatial model for disease mapping that accounts for scaling. Statistical Methods in Medical Research, 25(4), 1145-1165.

source

Independence Models

GaussianMarkovRandomFields.IIDModel Type
julia
IIDModel(n::Int; alg=DiagonalFactorization(), constraint=nothing)

An independent and identically distributed (IID) latent model for constructing simple diagonal GMRFs.

The IID model represents independent Gaussian random variables with identical precision τ. This is the simplest possible latent model, equivalent to a scaled identity precision matrix.

Mathematical Description

Each element is independent: x[i] ~ N(0, τ⁻¹) for i = 1,...,n. The precision matrix is simply: Q = τ * I(n)

This model is useful for:

  • Modeling independent effects or noise

  • Baseline comparisons with structured models

  • Teaching/demonstration purposes

Hyperparameters

  • τ: Precision parameter (τ > 0)

Fields

  • n::Int: Length of the IID process

  • alg::Alg: LinearSolve algorithm for solving linear systems

  • constraint::C: Optional constraint, either nothing or (A, e) tuple

Example

julia
model = IIDModel(100)
gmrf = model=2.0)  # Returns unconstrained GMRF

# With sum-to-zero constraint (common in INLA for separating global offset)
model = IIDModel(100, constraint=:sumtozero)
gmrf = model=2.0)  # Returns ConstrainedGMRF with sum-to-zero constraint
source
GaussianMarkovRandomFields.FixedEffectsModel Type
julia
FixedEffectsModel(n::Int; λ::Real = 1e-6, alg=DiagonalFactorization())

Weakly regularized fixed-effects latent component.

Encodes standard GLM-style fixed effects inside the latent vector with a small ridge precision λ * I(n).

  • No hyperparameters (returns NamedTuple())

  • No constraints

  • Name: :fixed (used for parameter prefixing in CombinedModel)

Fields

  • n::Int: Length of the fixed effects vector

  • λ::Float64: Ridge regularization parameter

  • alg::Alg: LinearSolve algorithm for solving linear systems

Example

julia
model = FixedEffectsModel(10)
gmrf = model()  # Returns GMRF with precision λ * I(10) using DiagonalFactorization

# Or specify custom algorithm
model = FixedEffectsModel(10, alg=CHOLMODFactorization())
gmrf = model()
source

Model Composition

GaussianMarkovRandomFields.CombinedModel Type
julia
CombinedModel(components::Vector{<:LatentModel}; alg=CHOLMODFactorization())

A combination of multiple LatentModel instances into a single block-structured GMRF.

This enables modeling with multiple latent components, such as the popular BYM model (Besag-York-Mollié) which combines spatial (Besag) and independent (IID) effects.

Mathematical Description

Given k component models with sizes n₁, n₂, ..., nₖ:

  • Combined precision matrix: Q = blockdiag(Q₁, Q₂, ..., Qₖ)

  • Combined mean vector: μ = vcat(μ₁, μ₂, ..., μₖ)

  • Combined constraints: Block-diagonal constraint structure preserving individual constraints

Parameter Naming

To avoid conflicts when multiple models have the same hyperparameters (e.g., multiple τ), parameters are automatically prefixed with model names:

  • Single occurrence: τ_besag, ρ_ar1

  • Multiple occurrences: τ_besag, τ_besag_2, τ_besag_3

Fields

  • components::Vector{<:LatentModel}: The individual latent models

  • component_sizes::Vector{Int}: Cached sizes of each component

  • total_size::Int: Total size of the combined model

  • alg::Alg: LinearSolve algorithm for solving linear systems

Example - BYM Model

julia
# BYM model: spatial Besag + independent IID effects
W = sparse(adjacency_matrix)  # Spatial adjacency
besag = BesagModel(W)         # Spatial component
iid = IIDModel(n)            # Independent component

# Vector constructor
bym = CombinedModel([besag, iid])
# Or variadic constructor (syntactic sugar)
bym = CombinedModel(besag, iid)

# With custom algorithm
bym = CombinedModel([besag, iid], alg=LDLtFactorization())

# Usage with automatically prefixed parameters
gmrf = bym(τ_besag=1.0, τ_iid=2.0)
source
GaussianMarkovRandomFields.SeparableModel Type
julia
SeparableModel{T<:Tuple{Vararg{LatentModel}}, Alg} <: LatentModel

Represents a separable (Kronecker product) latent model for multi-dimensional processes.

The precision matrix is the Kronecker product of the component precision matrices:

Q = Q_1 ⊗ Q_2 ⊗ ... ⊗ Q_N

where the rightmost component varies fastest in the vectorized representation.

For example, SeparableModel(temporal, spatial) produces Q_time ⊗ Q_space, yielding a block-tridiagonal structure when Q_time is tridiagonal (e.g., RW1).

Fields

  • components::T: Tuple of LatentModel components

  • alg: Linear solver algorithm

Example

julia
# Space-time separable model (standalone)
temporal = RW1Model(n_time)
spatial = BesagModel(adjacency_matrix)
st_model = SeparableModel(temporal, spatial)  # Q = Q_time ⊗ Q_space

# Instantiate with hyperparameters
# Standalone: τ_rw1, τ_besag
# In CombinedModel: τ_rw1_separable, τ_besag_separable
gmrf = st_model(τ_rw1=1.0, τ_besag=2.0)

Notes

  • Requires at least 2 components

  • Component ordering: rightmost component varies fastest (e.g., space in time×space model)

  • Follows R-INLA convention: Q = Q_group ⊗ Q_main

  • Hyperparameters are suffixed with component model names (e.g., τ_rw1, τ_besag)

  • When used in CombinedModel, an additional _separable suffix is added by the parent

  • Constraints from each component are composed via Kronecker products with identity matrices

  • Redundant constraints are automatically removed to ensure full row rank

source

Usage Examples

Basic Model Construction

julia
# Temporal AR1 process
ar1 = AR1Model(100)
gmrf = ar1=2.0, ρ=0.8)

# Spatial Matérn model from points
points = [0.0 0.0; 1.0 0.0; 0.5 1.0]  # N×2 matrix
matern = MaternModel(points; smoothness = 2)
gmrf = matern(range=1.5)

# Spatial Besag model
W = sparse_adjacency_matrix
besag = BesagModel(W)
gmrf = besag=1.0)  # Returns ConstrainedGMRF with sum-to-zero constraint

Model Composition

julia
# Classic BYM model: spatial + independent effects
W = spatial_adjacency_matrix
bym = CombinedModel(BesagModel(W), IIDModel(n))

# Check combined hyperparameters
hyperparameters(bym)  # (τ_besag = Real, τ_iid = Real)

# Construct combined GMRF
gmrf = bym(τ_besag=1.0, τ_iid=2.0)

# BYM2 model: improved parameterization (recommended)
# Uses mixing parameter φ instead of separate precisions
bym2 = BYM2Model(W)
hyperparameters(bym2)  # (τ = Real, φ = Real)
gmrf = bym2=1.0, φ=0.5)  # φ ∈ (0,1): proportion unstructured

# Continuous spatial field + independent effects
points = generate_observation_points()
spatial_matern = MaternModel(points; smoothness = 1)
independent_effects = IIDModel(length(points))
combined = CombinedModel(spatial_matern, independent_effects)
gmrf = combined(range=2.0, τ_iid=0.1)

Smart Parameter Naming

CombinedModel automatically handles parameter naming conflicts:

julia
# Single occurrence: no suffix
CombinedModel(AR1Model(10), BesagModel(W))  # τ_ar1, ρ_ar1, τ_besag

# Multiple occurrences: numbered suffixes  
CombinedModel(IIDModel(5), IIDModel(10), IIDModel(15))  # τ_iid, τ_iid_2, τ_iid_3

Advanced Compositions

julia
# Spatiotemporal model with three components
W = spatial_adjacency(n_regions)
model = CombinedModel(
    BesagModel(W),           # Spatial structure
    RW1Model(n_time),        # Temporal trend
    IIDModel(n_regions * n_time)  # Independent effects
)

gmrf = model(τ_besag=1.0, τ_rw1=2.0, τ_iid=0.1)

Separable (Kronecker Product) Models

For multi-dimensional data with separable structure, use SeparableModel to compose components via Kronecker products. This is particularly efficient for space-time models:

julia
# Space-time separable model: Q = Q_time ⊗ Q_space
# (space component varies fastest in vectorized form)
temporal = RW1Model(n_time)
spatial = BesagModel(W)
spacetime = SeparableModel(temporal, spatial)

# Hyperparameters use suffix naming
hyperparameters(spacetime)  # (τ_rw1 = Real, τ_besag = Real)

# Construct GMRF with block-tridiagonal structure
gmrf = spacetime(τ_rw1=1.0, τ_besag=2.0)

# 3-way separable model: Q = Q_time ⊗ Q_space ⊗ Q_age
three_way = SeparableModel(
    RW1Model(n_time),
    BesagModel(W),
    IIDModel(n_age)
)
gmrf = three_way(τ_rw1=1.0, τ_besag=2.0, τ_iid=0.5)

Key Features

Automatic Constraint Handling

Models automatically determine GMRF type based on constraints:

julia
ar1 = AR1Model(10)     # No constraints → GMRF
rw1 = RW1Model(10)     # Sum-to-zero constraint → ConstrainedGMRF
mixed = CombinedModel(ar1, rw1)  # Inherits constraints → ConstrainedGMRF

Custom Constraints

Latent models support adding custom linear equality constraints Ax = e. This is particularly useful for INLA-style modeling where you want to learn a global offset separately from the latent field.

Models with Optional Constraints

For models without built-in constraints (AR1, IID, FixedEffects, Matern), use the constraint parameter:

julia
# Sum-to-zero constraint (shorthand)
ar1 = AR1Model(100, constraint=:sumtozero)
gmrf = ar1=1.0, ρ=0.8)  # Returns ConstrainedGMRF

# Custom constraint: fix first two elements to sum to 1
A = [1.0 1.0 0.0 0.0 0.0]  # 1×n constraint matrix
e = [1.0]                   # Constraint value
iid = IIDModel(5, constraint=(A, e))
gmrf = iid=2.0)          # x[1] + x[2] = 1.0

Intrinsic Models with Additional Constraints

Intrinsic models (RW1, Besag) already have built-in constraints. Use additional_constraints to add extra constraints without removing the built-in ones:

julia
# RW1 already has sum-to-zero; add constraint to fix first element
A_extra = [1.0 0.0 0.0 0.0 0.0]  # Fix x[1] = 0
e_extra = [0.0]
rw1 = RW1Model(5, additional_constraints=(A_extra, e_extra))
gmrf = rw1=1.0)  # Both sum(x) = 0 AND x[1] = 0

# Besag with additional constraint
besag = BesagModel(W, additional_constraints=(A_extra, e_extra))
gmrf = besag=1.0)  # Component-wise sum-to-zero + extra constraint

Don't Remove Required Constraints

Intrinsic models like RW1 and Besag require their built-in constraints for identifiability. Attempting to use constraint=:sumtozero on RW1Model will throw an error since it already has this constraint. Always use additional_constraints for these models.

Parameter Validation

All models include built-in parameter validation:

julia
ar1 = AR1Model(100)
ar1=-1.0, ρ=0.8)   # ArgumentError: τ must be positive
ar1=1.0, ρ=1.5)    # ArgumentError: |ρ| must be < 1

Efficient Sparse Operations

  • Block-diagonal precision matrices are always sparse

  • Input matrix structures (sparse, SymTridiagonal) are preserved

  • Minimal memory allocations through size caching

See Also

Formula Terms

Prefer writing models with formulas? The latent components discussed here can be constructed via formula terms and assembled automatically into a combined model and design matrix. See the Formula Interface reference for details: