glmm
Standalone f64 GLM(M) fit kernels — OLS → GLM → LMM → GLMM — in pure Rust on faer.
Fits fixed-effect and mixed (random-intercept/random-slope) models for Gaussian, Binomial (logit/probit/cloglog), Poisson, Gamma, Negative-Binomial, and (fixed-effect GLM only) Inverse-Gaussian outcomes, validated against R/lme4 and Julia/MixedModels.jl goldens.
Beta. Handles the usual mixed models, supports AGQ more widely than lme4,
and is typically several times faster on them. Some lme4 features are still
missing (see docs). Version 1.0 will add a built-in test
for whether a random effect matters — currently you need the separate RLRsim
package, and it only works for normal (Gaussian) outcomes.
New to the crate? Start with tutorial-rust.md — a
single-page, three-layer walkthrough (cold fit → warm fit → advanced loop)
plus a short section on parsing an R-style formula string instead of building
inputs by hand. Python and R packages are also available — see
Python and R below.
One crate, one fit
A single entry point covers the whole linear-regression family. fit reads
ModelSpec and routes on family × random effects × weights:
flowchart LR
F["fit(x, y, ModelSpec)"] --> RE{"re?"}
RE -- "None" --> FAM1{"family?"}
FAM1 -- "Gaussian" --> OLS["OLS - WLS with weights"]
FAM1 -- "other" --> GLM["GLM - IRLS"]
RE -- "Some" --> FAM2{"family?"}
FAM2 -- "Gaussian" --> LMM["LMM - profiled REML"]
FAM2 -- "other" --> GLMM["GLMM - PIRLS, Laplace/AGQ"]
This is the pitch view. Every branch point, solver path, and tuning knob is
traced to code in the full algorithm map:
documentation/algorithms.md, with the LMM
and GLMM legs detailed in
documentation/algorithms-lmm.md and
documentation/algorithms-glmm.md.
Documentation
The fuller map — entry point, tutorials, examples, migration guides, reference,
and internals, all in one tiered table — lives in
documentation/index.md. The table below is this
README's own copy of the essentials, not the whole set.
| File | Purpose |
|---|---|
documentation/tutorial-rust.md |
Three-layer Rust walkthrough: cold fit → warm fit → advanced loop, plus the formula frontend |
documentation/tutorial-python.md |
The Python package (glmm) walkthrough |
documentation/tutorial-r.md |
The R package (fastglmm) walkthrough |
documentation/supported_families.md |
Family × link support matrix, canonical-link notes, dispersion conventions |
documentation/algorithms.md |
Algorithm map entry point: full dispatch graph, knob index, OLS/GLM paths |
documentation/algorithms-lmm.md |
LMM: θ-Cholesky, profiled REML, closed-form shortcut, BOBYQA, boundary handling |
documentation/algorithms-glmm.md |
GLMM: PIRLS, Laplace vs AGQ, dense vs sparse Z, NB outer loop, warm starts |
documentation/glmm-design.md |
Algorithmic design rationale: the differences from lme4/MixedModels.jl and why each one is faster |
documentation/installation.md |
Installing the Rust crate, Python package, and R package |
documentation/formula.md |
What the formula parser accepts and rejects, with workarounds |
documentation/conventions.md |
Estimation, standard-error, dispersion, and variance-component conventions, and the flags on a fit result |
documentation/validation.md |
How glmm is validated against lme4 and MixedModels.jl, what's covered, and known tolerances/exemptions |
documentation/coming-from-lme4.md |
Call mapping from lme4, what's deliberately missing, and behavioral differences to watch (covers both the R and Python surface) |
documentation/coming-from-statsmodels.md |
Migrating from statsmodels MixedLM/GLM to glmm.fit (Python only) |
documentation/troubleshooting.md |
Fixes for singular fits, non-convergence, NotImplementedError, and rejected formulas |
Scope and stability (0.3.x)
The semver-covered surface is fit_cold/fit_warm + ModelSpec + GroupIds.
| Model | Fixed-only (re: None) |
Mixed (re: Some) |
|---|---|---|
| Gaussian | OLS | LMM — dense, or sparse-Z when an extra grouping carries a random slope |
| Binomial (logit/probit/cloglog) | GLM | GLMM — dense, or sparse-Z over-envelope |
| Poisson (log) | GLM | GLMM — dense, or sparse-Z over-envelope |
| Gamma (log/inverse) | GLM | GLMM — dense, or sparse-Z over-envelope |
| Negative-Binomial (log) | GLM | GLMM — dense, or sparse-Z over-envelope |
| Inverse-Gaussian (log / 1/μ²) | GLM | not supported (faults) |
Every wired family, except Inverse-Gaussian (fixed-effects only), fits
through both routes — there is no reachable panic for falling outside the
dense solver's envelope (too many extra groupings, or an extra grouping too
wide); classification just routes to the sparse-Z solver instead. See tutorial-rust.md and
documentation/algorithms-glmm.md for the
dense/sparse routing envelope.
The loop_advanced cargo feature (off by default) exposes an unstable
scratch-explicit hot-path surface for warm-start callers like MCPower's
simulation loop — no semver guarantees; do not depend on it outside a
pinned revision.
The orchestrate cargo feature (off by default) exposes the string-typed fit
orchestration the Python and R packages are built on — one definition of the
family/link string vocabulary, the formula-and-data lowering, and the
flattened result both ports publish. No semver guarantees, for the same
reason as loop_advanced: its shape follows the ports' needs.
The parallel cargo feature (off by default, experimental) enables
in-fit parallelism — the AGQ cluster loop and the FD-Hessian SE grid — via
rayon, and is additionally gated at runtime by FitOptions::parallel_inner
(also off by default): both the feature and the flag must be on for any
thread to spawn. Parallel results are bit-identical to serial ones, but the
kernels are new and their performance envelope isn't characterized yet —
treat as opt-in only. A no-op on wasm32 (compile-time excluded, rayon never
pulled in).
Quick example
use ;
// y ~ x + (1 | group), Gaussian — a random-intercept LMM.
let model = ModelSpec ;
let ids = GroupIds ;
// target_indices = which coefficients get a standard error; here, both.
let opts = FitOptions ;
let fit = fit_cold;
assert!;
See tutorial-rust.md for the full walkthrough: warm
starts, the advanced hot-loop surface, and building x/ModelSpec/GroupIds
from a formula string with glmm::formula (the formula feature, on by default)
instead of by hand.
Python and R
The same kernel ships as a Python package and an R package. Both take a data table and an R-style formula — no design matrices by hand.
Python (glmm on PyPI; Python 3.10+, NumPy is the only dependency):
= # data: dict / pandas / polars
The public surface is eight names: glmm.fit, glmm.Fit, and the six warning
categories the diagnostics channel raises. See the
Python README and
tutorial-python.md.
R (fastglmm, via r-universe):
fit <-
# plus fixef, ranef, fitted, vcov, VarCorr, confint, logLik, isSingular
Deliberately scoped to fast fitting — anything the engine cannot compute
honestly (predict, residuals) errors with the reason instead of guessing.
See the R README and
tutorial-r.md.
Design
| Property | Detail |
|---|---|
No unsafe |
zero unsafe (workspace baseline unsafe_code = "warn") |
| Deterministic | no RNG, no global state, no I/O in the fit path |
| Linear algebra | faer 0.24, pinned |
| MSRV | Rust 1.85 (floor set by the bobyqa dep) |
Origin
glmm was carved out of MCPower's
simulation engine — the numerics here are the same validation-pinned kernels that
power MCPower's Monte Carlo fits, split out so they're usable standalone. The
loop_advanced feature above exists specifically to serve MCPower's
warm-start hot loop as a consumer of this crate.
License
GPL-3.0-or-later (coupled to the GPL-3 MCPower flagship).
Paweł Lenartowicz — Freestyler Scientist · GitHub · ORCID