Skip to content

Repository files navigation

statsim-lang

C++ transpiler that compiles .sm math notation into multiple probabilistic programming backends.

Quick example

p ~ Beta(1, 1)
x ~ Bin(10, p) | 7
sample(5000)

Compiles to ~20 lines of Stan, ~15 lines of PyMC, TFP.js, etc.

Usage

statsim-lang model.sm --target stan # Stan code
statsim-lang model.sm --target tfpjs # TFP.js (JavaScript)
statsim-lang model.sm --target pymc # PyMC (Python)
statsim-lang model.sm --target z3 # Z3 (Python, optimization only)

Available backends

BackendStatus
TFP.js10/10 models validated
Stan10/10 models validated
Z3model 10 validated (constraint/optimization only)
PyMCimplemented (compile + syntax validation tests)
NumPyroplanned

Build

cmake -B build
cmake --build build

Requires C++17. Tests run via CTest + Python (no network fetch required).

Module mode (Python / JavaScript)

Module mode compiles a .sm model into a runner object you can call from host code.

Python (PyMC)

importstatsim_langasslrunner=sl.model("model.sm", target="pymc")
trace=runner.run({"x": data_x, "N": len(data_x)}) # run inferencemodel=runner.build({"x": data_x, "N": len(data_x)}) # get pm.Model

JavaScript (TFP.js)

import{model}from'@statsim/lang'construnner=model(source,'tfpjs')constresults=awaitrunner.run({x: dataX,N: dataX.length})const{ targetLogProb, bijectors }=awaitrunner.build({x: dataX})

Host functions (Call In)

Models can reference functions the compiler doesn't know about. The host provides them at runtime — no special syntax needed.

h = hazard(time, X, beta, gamma)
y ~ Poisson(h), i=1:N
sample(1000)

Python — pass callables as keyword arguments:

defhazard(time, X, beta, gamma):
returnpt.exp(X @ beta+gamma*time)
trace=runner.run(data, hazard=hazard)

JavaScript — pass callables alongside data (auto-separated):

constencode=(images)=>model.predict(images)constresults=awaitrunner.run({ images, labels, encode })

Model composition (Compose Out)

Use runner.build() to get the underlying model object and extend it in host code.

Python — returns a pm.Model:

model=runner.build(data)
withmodel:
f=pm.gp.Latent(cov_func=pm.gp.cov.Matern52(1, ls=1.0))
pm.sample(1000)

JavaScript — returns { targetLogProb, bijectors, stateNames }:

const{ targetLogProb, bijectors }=awaitrunner.build(data)// use with custom MCMC or optimization

Inline functions

Define reusable functions with f(x) = expr syntax:

logistic(x) = 1 / (1 + exp(-x))
p = logistic(alpha + beta * x)
y ~ Bernoulli(p), i=1:N

Emits as native functions in each backend (Python def, JS function, Stan functions {} block).

Language reference

See PLAN.md for the full language spec, spec/syntax.ebnf for the grammar, and spec/distributions.md for the distribution parameter mapping across backends.

Examples

10 reference models in spec/examples/:

ModelFeatures
01_coin_flipBasic sample + observe
02_ab_testMultiple priors, Binomial
03_linear_regPlated observations
04_robust_regStudent-t, heavy tails
05_hierarchicalNested priors, hyperparameters
06_mixtureGaussian mixture, Dirichlet
07_gpGaussian process, matrix ops
08_ar2Autoregressive time series
09_changepointDiscrete switching
10_portfolioOptimization with constraints

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages