Liking cljdoc? Tell your friends :D

foerster

Clojars Project CircleCI cljdoc Slack

Probabilistic inference in forkable worlds, for Clojure and ClojureScript.

We built Foerster to reuse stochastic Clojure application code for inference. A model can call ordinary application functions and inspect managed state that already exists. On Spindel, a forkable functional reactive runtime, supported particle methods can explore copies of that state without committing their speculative writes to the caller.

Foerster follows Anglican's tradition of interpreting sample and observe checkpoints. Spindel and Partial-CPS supply explicit suspension scopes, rather than a separate modeling language. Native Clojure control flow works inside a spin; effectful helpers return their own spins and callers explicitly await them. Fork isolation covers managed runtime state and registered forkable systems, not arbitrary host mutation or external I/O.

What it does

A probabilistic program is a Spindel spin with sample, observe and factor sites. Inference interprets these sites as savepoints: points where execution can be scored, resumed or forked. Numerical methods additionally require explicit block densities and, for gradient methods, gradients.

(require '[org.replikativ.foerster.core :as infer :refer [sample observe factor]]
         '[org.replikativ.foerster.dist :as dist]
         '[org.replikativ.spindel.core :as sp :refer [spin]])

;; programs run in a spindel world (an execution context)
(def world (sp/create-execution-context))

(defn model []
  (spin
   (let [mu (sample (dist/normal 0.0 1.0) :id :mu)]
     (observe (dist/normal mu 1.0) 1.0 :id :y)
     mu)))

;; inference returns a spin; at the REPL, deref it
(def posterior (sp/with-context world @(infer/infer (model) {:method :smc :particles 1000})))

(:mean (infer/query posterior identity))   ; ≈ 0.5, the posterior is N(0.5, 0.707²)

Inside another spin, await it instead of dereferencing (org.replikativ.spindel.effects.await).

Where to start

The concepts guide distinguishes worlds, traces, measures, populations and numerical blocks. See checking a model for posterior diagnostics and validation; a successful run alone is not a fit check.

Documentation

  • Causal inference — queries and identifiability: native mechanism fitting and held-out checks, shared-noise counterfactual worlds, graphical ID/IDC, attribution and finite actual-cause search. From data to repairs runs the workflow against known truth, including bootstrap uncertainty and a misspecified model.

  • GSDM research experiment — native amortized abduction: Raster graph attention, DDPM training and counterfactual replay, checked against an analytic posterior; CPU numerical and checkpoint checks for future backend qualification.

  • Amortized inference — simulator-to-artifact integration: derive RV schemas and attention masks from simulator source, train conditional samplers, and reconstruct causal noise. Includes finite RVs, observation encoders and data checkpoints; current Raster backend is CPU/JVM.

  • Tutorials — runnable notebooks, rendered at replikativ.github.io/foerster: getting started, choosing an algorithm, every inference method with its papers, models in worlds, blocks and HMC, streaming SMC, trace programming, interventions and counterfactuals, steering a process, a gallery of classic models, models from the PyMC gallery, and marketing mix modeling — each checked against an exact answer or a known truth.

  • Guides — doc/: the language, the algorithms, posteriors, checking a model and its inference, coming from Stan, PyMC, Turing, Gen, Anglican or WebPPL, extending, worlds, distributions and reproducibility, the design, the literature.

  • API reference — cljdoc.

Inference and capabilities

  • a common entry point for built-in batch inference methods: (infer/infer model {:method :smc :particles 1000})
  • programmable populations: scoped initialization, target advancement, resampling, invariant moves and scored transport over traces or numerical values, composed using ordinary spin control flow
  • exact enumeration of finite discrete models over forked worlds
  • SMC and streaming SMC, importance sampling, tempered SMC (also waste-free, and on numerical blocks), resample-move and SMCP3; arrival-batched SMC and the particle cascade, which do not wait for the slowest particle; sequential core-set Monte Carlo with GIGA for streams in bounded memory
  • particle MCMC: PIMH, particle Gibbs (with exact resample-move), PGAS, IPMCMC; PMMH and SMC² for static parameters
  • MCMC over traces: single-site and random-walk Metropolis–Hastings, block Gibbs, involutive MCMC with reversible jump, custom proposal programs, delayed acceptance with a cheap coarse density; NUTS (Stan's adaptation, or nutpie's Fisher-divergence metric) and HMC on numerical blocks, with constrained latents; non-reversible parallel tempering; kernels composed by k/cycle and k/mixture
  • MAP (L-BFGS), the Laplace approximation and Pathfinder on blocks; BBVI (black-box variational inference); evidence maximization for a model's parameters (foerster.learn)
  • Anglican's toolkit: mem, Chinese restaurant processes, nested inference (infer/conditional)
  • checking: R-hat, bulk and tail ESS and MCSE as ArviZ computes them, PSIS-LOO, WAIC and model comparison, posterior predictive checks (also on new inputs and under interventions), export to ArviZ; simulation-based calibration and a posteriordb profile (ten reference posteriors, accuracy and speed of NUTS, tempered SMC and parallel tempering)
  • steering a process — a language model's turns, a simulator — by SMC over scored steps, twisted by a value estimate (foerster.steer), with the trajectories as training data (foerster.learn)
  • guides: a sample site's :proposal draws from a distribution the program computes, weighted by log p − log q
  • counterfactuals and interventions (Pearl's do), selectors over sites
  • a Gen-style generative function interface
  • reproducible runs from a :seed, for particles and chains alike, the same draws on the JVM and in JavaScript
  • sandboxed use (foerster.sandbox): namespaces for an interpreter sandbox such as dvergr's agent sandbox, with plain-data results, work limits, per-session seeds and background jobs

Worlds

Pure models run in fresh worlds (:world-policy :fresh, the default). The particle methods (importance sampling, SMC, particle MCMC, BBVI) also run in canonical forks of the caller's world (:world-policy :fork), for models that read or change the systems of the world they run in (databases, repositories, a business book); Markov chains run in fresh worlds only:

  • every particle starts from a frozen copy of the caller's managed state and runs the whole model; writes to forkable managed systems stay local. Ordinary Clojure atoms and arbitrary external I/O are outside this boundary;
  • on the JVM particles are copies of worlds: systems that must not be duplicated (live handles, unsettleable linear state) are refused before the model runs, and with a resource authority particles split the inference's budget instead of multiplying it (in ClojureScript particles are forks, without these checks);
  • however inference ends, every world is discarded before the result is delivered, and the posterior keeps each particle's world descriptor.

See the worlds guide.

Numerical blocks

A block is a group of latents sampled at one site, with a log density and its gradient. HMC moves blocks jointly. foerster-raster compiles block densities with raster (JVM, WASM, GPU) and reverse-mode AD.

Platforms

The sources are .cljc, and inference runs on the JVM and in JavaScript. Distributions (foerster.dist) are portable Clojure, named and parameterized like raster's, and the random generator draws the same numbers for a seed on both platforms. Copying worlds for canonical particles is JVM-only; in ClojureScript canonical particles are forks.

History

A "bit" of information is definable as a difference that makes a difference. — Gregory Bateson, Steps to an Ecology of Mind

Act always so as to increase the number of choices. — Heinz von Foerster

A Förster is a forester: someone who tends a forest, grows branches, prunes them, and decides which trees continue. That is what inference over spindel worlds does. Particles branch from a world, resampling prunes the unlikely ones and copies the likely ones, and Markov chains walk the tree of worlds. The name also honours Heinz von Foerster, whose cybernetics put the observer inside the system it observes, as agents inferring inside the worlds they act in are here.

Monte Carlo began on ENIAC: Stanisław Ulam's idea (1946), John von Neumann's design, Klára Dán von Neumann's code for the first runs (1948), and Nicholas Metropolis's name for it. The Metropolis algorithm followed in 1953.

The idea was to try out thousands of such possibilities and, at each stage, to select by chance, by means of a "random number" with suitable probability, the fate or kind of event, to follow it in a line, so to speak, instead of considering all branches. — Stanisław Ulam

Lineage

foerster stands on earlier probabilistic programming systems:

  • Anglican, probabilistic programming in Clojure: a model is a program whose sample and observe are checkpoints, and inference is a continuation-passing interpreter over them (SMC, PIMH, PGibbs, PGAS, IPMCMC, LMH, BBVI). foerster's sites are those checkpoints as spindel savepoints, and its benchmarks reuse Anglican's ground truths.
  • Daphne, a probabilistic programming compiler in Clojure, following An Introduction to Probabilistic Programming: first-order programs compiled to graphical models, and those to amortized inference networks.
  • Gen (Gen.jl), programmable inference through the generative function interface — simulate, generate, assess, update, regenerate over traces — which foerster implements (foerster.gfi), and involutive MCMC.

foerster grew inside spindel and was split out with its history.

License

Copyright © 2026 Christian Weilbach. MIT License. Releases up to and including 0.1.104 were published under the Apache License 2.0.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close