Skip to content

Add a 'stanli' backend - #1966

Open
seantalts wants to merge 2 commits into
paul-buerkner:masterfrom
seantalts:stanli-backend
Open

seantalts wants to merge 2 commits into
paul-buerkner:masterfrom
seantalts:stanli-backend

Conversation

@seantalts

@seantalts seantalts commented Nov 5, 2026 •

Copy link
Copy Markdown

This adds backend = "stanli". stanli runs Stan models (Stan 2.40) without a C++ toolchain or a per-model compile.

How it works. Fits are converted with stanli::as_stanfit(), so brmsfit$fit is a stanfit and post-processing uses the existing rstan paths. log_prob()-based methods use the stanli model kept in the fit.

Supported: every algorithm (Pathfinder runs one path), init, control (adapt_delta, max_treedepth, metric, stepsize, adapt_engaged), threads, cores, exclude, brm_multiple(). Not supported: OpenCL, future, expose_functions().

Dependency. stanli (>= 0.25.0) in Suggests, from R-universe (binaries for macOS, Windows and Linux), plus a one-time stanli::stanli_install(). Tests skip on CRAN and when stanli is missing.

Evidence (in the stanli repo):

  • brms end to end: 124 formulas through brm() with this backend and with cmdstanr. All fit with both, posterior means agree within Monte Carlo error, and the post-processing methods behave the same. Convergence is the same too: in a rerun over 8 seeds, the borderline models miss rhat < 1.01 about equally often with either backend.
  • Corpus status: log density and gradients checked against CmdStan for the brms models in CI.
  • Benchmarks and how it's tested.

Fit models with the stanli package, which runs Stan models without a C++
toolchain or a per-model compilation step. backend = "stanli" supports
every algorithm: sampling and fixed_param through stanli::sample_model(),
meanfield and fullrank through variational_model(), pathfinder (a single
path) and laplace. init accepts "random", 0, a radius, a function or one
list per chain, and lists may leave parameters out. control passes
adapt_delta, max_treedepth, metric, stepsize and adapt_engaged; other
settings are ignored with a warning.

The fit is converted with stanli::as_stanfit(), so brmsfit$fit is a
stanfit and post-processing takes the existing rstan paths. log_prob()
and the parameter transforms go through the stanli model kept in that
object; update_misc_env() rebuilds it from the code and data, which needs
no compiler. OpenCL, future and expose_functions() are not supported.

stanli is in Suggests, from its R-universe repository. The tests skip on
CRAN and when stanli or its runtime is not installed.
@seantalts
seantalts marked this pull request as ready for review November 5, 2026 13:44
…sampler problems

stanli 0.24.0 and 0.25.0 fix silently wrong answers from integer division,
from 2-D int arrays filled one row at a time, and from in-place writes in
long loops, so the backend now requires 0.25.0.

Init lists may contain entries that are not parameters, such as
b_Intercept, as rstan allows. They are ignored.

stanli prints divergence, treedepth and E-BFMI warnings only when
refresh > 0. With refresh = 0, which silent = 2 sets, the backend now
raises them as R warnings with rstan's wording.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant