Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Playground

Everything on this page runs the real fugue crate, compiled to WebAssembly. The editor below speaks a subset of the prob! macro language; when you press Run, your model text is parsed in Rust, folded into actual Model combinators, and handed to the same inference kernels this book documents — adaptive Metropolis–Hastings one transition at a time, Hamiltonian Monte Carlo with dual-averaging warmup, adaptive tempered SMC with a log-evidence estimate. The draws you watch stream in are fugue's draws, not a JavaScript imitation of them.

What the editor understands

The playground accepts the statement forms of prob!, with data arrays provided as JSON (an object of named arrays, or a bare array bound to data):

let p <- sample(addr!("p"), Beta(2.0, 2.0));   // sample a latent
let m = 2.0 * p - 1.0;                          // deterministic let
observe(addr!("y"), Normal(m, 0.8), 1.4);       // condition on data
factor(-0.5 * m * m);                           // add a log-weight
for i in 0..data.len() { ... }                  // plates
pure(p)                                         // the model's return value

Rust spellings from the docs paste in unchanged — Normal::new(0.0, 1.0).unwrap() parses the same as Normal(0.0, 1.0). Available distributions: Normal, Uniform, LogNormal, Exponential, Beta, Gamma, InverseGamma, StudentT, Cauchy, Laplace, Weibull, ChiSquared, Bernoulli, Binomial, Poisson, Categorical, DiscreteUniform — the same constructors, parameterizations, and support checks as the crate, because they are the crate. Expressions know + - * /, exp, ln, sqrt, abs, pow, min, max, floor, sin, cos, tanh, array indexing y[i], and .len().

Two honest limitations: parameter regions that would make a distribution invalid (say, a negative scale reached through your arithmetic) score as impossible (-inf) rather than erroring, exactly how the samplers treat leaving a support; and the interpreter covers the statement subset above, not arbitrary Rust — for that, there is cargo add fugue-ppl.

Things to try

  1. Watch R̂ earn its keep. Run the coin-flip preset with 3 chains: the chains start from independent prior draws, disagree, then R̂ falls toward 1.00 as their histograms merge — the same split-R̂ computation fugue::inference::diagnostics runs in production.
  2. Break a model, kindly. Change a flip observation to 2.0 (a coin that landed on its edge?). Bernoulli observes a boolean, so anything nonzero coerces to true — then make the prior Beta(0.5, 0.5) and watch the posterior bend toward the edges.
  3. Compare kernels on the same posterior. Run the eight-schools preset under MH, then under HMC. Single-site MH updates one coordinate at a time and mixes slowly through the funnel; HMC moves all ten coordinates jointly. The ESS readout is the receipt.
  4. Ask for evidence. Switch to SMC on any preset: you get weighted posterior particles and log Z, the marginal likelihood MH and HMC never give you.
  5. Make it yours. Replace the data JSON with your own numbers. The model recompiles as you type — the ✓/✗ line is fugue's parser talking.

How this works

crates/fugue-wasm (in the fugue repository) exposes wasm-bindgen entry points over the crate: compile a model source + data payload, then drive step(n) per animation frame and read draws and diagnostics back as typed arrays. Sampler state lives in Rust — traces, adaptation state, tuned step sizes — and every run is seeded, so a seed is a replayable recording here too. The interactive figures in the explorables chapters use the same package for their samplers; only their canvas rendering is JavaScript.

Go deeper