StanBlocks.jl
StanBlocks.jl is a (limited) Julia-to-Stan transpiler: write probabilistic models in Julia syntax and automatically generate compilable Stan code.
Caveats This transpiler has many caveats. See Caveats below. :::
Quick Start
using StanBlocks
import StanLogDensityProblems, JSON
# Model definition (no data bound yet)
earn_height_model = @slic begin
beta ~ flat(;n=2)
sigma ~ flat(;lower=0.)
earn ~ normal(beta[1] + beta[2] * to_vector(height), sigma)
end
# Bind data
earn_height_posterior = earn_height_model(; earn, height)
# Inspect the generated Stan code
println(stan_code(earn_height_posterior))
# Compile and instantiate (requires StanLogDensityProblems.jl + JSON.jl)
earn_height_problem = stan_instantiate(earn_height_posterior)Key Features
Activity Analysis
StanBlocks automatically determines which Stan block each variable belongs to:
| Block | Description |
|---|---|
data | Passed in from Julia (observed quantities) |
transformed_data | Computed once from data (e.g. log_y = log.(y)) |
parameters | Sampled by HMC; determine posterior dimension |
transformed_parameters | Deterministic functions of parameters, evaluated each gradient step |
generated_quantities | Computed per sample, do not enter the likelihood |
Type Inference
Stan requires explicit types and shapes. StanBlocks infers them automatically from passed values and from the model structure. Shapes extracted from data are exposed as integer data in the generated Stan code.
User-Defined Functions
The @deffun macro extends the Stan function library with variadic signatures and limited dynamic dispatch:
@deffun begin
my_normal_lpdf(y, mu, sigma) = normal_lpdf(y, mu, sigma)
my_normal_rng(mu, sigma)::real = normal_rng(mu, sigma)
# Dispatch on function-argument type (higher-order functions)
dispatch_lpdf(y, ::typeof(my_normal), args...) = my_normal_lpdf(y, args...)
endConstraints
Constraints are specified as keyword arguments to distributions. Many distributions (e.g. beta, gamma) infer their bounds automatically:
model = @slic (;y) begin
sigma ~ std_normal(;lower=0.) # half-normal (explicit lower bound)
theta ~ beta(1., 1.) # [0,1] bounds inferred automatically
y ~ normal(0., sigma)
endSub-Models and Composition
Models can be composed by referencing one model inside another:
prior = @slic begin
mu ~ std_normal()
tau ~ std_normal(;lower=0.)
end
hierarchical = @slic (;y) begin
theta ~ prior()
y ~ normal(theta, 1.)
endCaveats
Constant Terms in Log-Density
Stan's ~ statement drops constant terms that do not depend on model parameters. StanBlocks does not drop constants—it always includes the full log-density. This means the absolute value of the log-density will generally differ from a hand-written Stan model, but the posterior geometry is identical and sampling is unaffected.
Limited Coverage
Not all Julia constructs can be transpiled. In particular, arbitrary Julia functions (not defined via @deffun) cannot be transpiled automatically.
Name Resolution
User-defined functions and sub-models currently need to be defined in Main.
See Also
API Reference – full list of exported functions and macros
Case Studies – golf, radon, crowdsourcing, and more
BridgeStan – Stan–Julia bridge used for compilation