Skip to content

Getting started

Welcome to the DistributionsInference documentation. This page is the quickstart. The home page is generated from the README and already carries the install instructions, so start here with what a new user does once the package is loaded, and grow it into tutorials as the package develops.

julia
using DistributionsInference, Distributions, Random

A first example: fit a toy object with no PPL

A type becomes fittable by naming its scalar parameters and how to rebuild itself from a flat vector — no other change needed, and no probabilistic programming language required.

julia
struct ToyDelay
    shape::Float64
    scale::Float64
end

Distributions.logpdf(d::ToyDelay, y::Real) = logpdf(Gamma(d.shape, d.scale), y)

function DistributionsInference.parameter_rows(d::ToyDelay)
    return [(name = :shape, value = d.shape,
            prior = LogNormal(log(2.0), 0.2), support = (0.0, Inf)),
        (name = :scale, value = d.scale, prior = nothing,
            support = (0.0, Inf))]
end

function DistributionsInference.reconstruct(d::ToyDelay, x::AbstractVector)
    return ToyDelay(x[1], d.scale)
end

parameter_rows is the whole estimation boundary: shape carries a prior, so it is estimated; scale carries none, so it stays fixed.

julia
leaf = ToyDelay(2.0, 1.0)
DistributionsInference.parameter_rows(leaf)
2-element Vector{NamedTuple{(:name, :value, :prior, :support)}}:
 (name = :shape, value = 2.0, prior = Distributions.LogNormal{Float64}(μ=0.6931471805599453, σ=0.2), support = (0.0, Inf))
 (name = :scale, value = 1.0, prior = nothing, support = (0.0, Inf))

as_logdensity packages the template object and observed data into a log-density over just the estimated rows, and flat_dimension counts them.

julia
data = [1.5, 2.0, 3.2, 1.8, 2.6]
prob = DistributionsInference.as_logdensity(leaf, data)
DistributionsInference.flat_dimension(leaf)
1

logdensity scores a candidate flat vector: the prior's log-density at that value, plus the data log-likelihood of the object reconstructed there.

julia
DistributionsInference.logdensity(prob, [2.5])
-7.664026948568271

prob implements the LogDensityProblems interface, so any compatible sampler can drive it. Here is the tiniest one, a ten-line random-walk Metropolis, so this example stays self-contained with no extra dependency.

julia
function toy_sample(prob, x0, n; step = 0.2, rng = Xoshiro(1))
    x, lp = copy(x0), DistributionsInference.logdensity(prob, x0)
    draws = Vector{Vector{Float64}}(undef, n)
    for i in 1:n
        prop = x .+ step .* randn(rng, length(x))
        if all(>(0), prop)
            lp_prop = DistributionsInference.logdensity(prob, prop)
            log(rand(rng)) < lp_prop - lp && ((x, lp) = (prop, lp_prop))
        end
        draws[i] = copy(x)
    end
    return draws
end

draws = toy_sample(prob, [2.0], 500)
length(draws)
500

to_flexichain keys the raw draws by the estimated rows' dotted names, the same naming contract a real PPL's sampler output would carry.

julia
chain = DistributionsInference.to_flexichain(leaf, draws)
╭─FlexiChain (500 iterations, 1 chain) ────────────────────────────────────────
 ↓ iter  = 1:500
 → chain = 1:1

 Parameters (1) ── Symbol
  Float64  shape                                                              

 Extras (0)
  (none)
╰──────────────────────────────────────────────────────────────────────────────╯

readback reduces the chain to a fitted ToyDelay (the posterior mean of shape by default); readback_draws keeps every draw instead, for a per-draw posterior-predictive summary.

julia
fit = DistributionsInference.readback(leaf, chain)
fit.shape
2.3461617417131464
julia
length(DistributionsInference.readback_draws(leaf, chain))
500

Loading DynamicPPL activates as_turing, a light wrapper over the same prob that samples with Turing instead of the toy sampler above; the same readback call reads its chain back too. Fitting an object carries leaf through both routes in full, then runs the identical calls against a ComposedDistributions tree in place of a hand-written type.

Learning more

  • Carry this example further in Fitting an object: sampling with Turing as well as the toy sampler above, and fitting a ComposedDistributions tree with the same calls.

  • Want the full interface? See the Public API.

  • Want the packages DistributionsInference works alongside? See Related packages on the home page.

Getting help

For usage questions, ask on the Julia Discourse (the SciML or usage categories) or the epinowcast community forum, our home for epidemiological modelling questions. Please use GitHub issues for bug reports and feature requests only.

The layout, navigation, and infrastructure of this site are generated by EpiAwarePackageTools. Its docs cover customising the generated pages and how template sync keeps this repository current.