Getting started
Welcome to the ComposedDistributions documentation. This page is the quickstart. The home page is generated from the README, so it stays short; put the walkthrough a new user needs here and grow it into tutorials as the package develops.
These docs are generated
This site's layout, navigation, and infrastructure are produced by EpiAwarePackageTools. Editing the generated pages by hand is not needed; write your content in the package-owned source pages and let the scaffold render the rest. See Infrastructure and template sync for how the kit keeps this repository in sync.
Installation
using Pkg
Pkg.add("ComposedDistributions")Load the package:
using ComposedDistributionsWhat ComposedDistributions does
ComposedDistributions composes per-event delay distributions into one object that describes a whole record. A composed object is a multi-state event process: named events linked by delays, which the composers wire into a tree. The same object scores observed records with logpdf and simulates new ones with rand, so a model is built once and used in both directions. It composes any Distributions.jl UnivariateDistribution, with no censoring, so it is the generic composition layer.
The building blocks are five composers. Sequential chains steps in series, Parallel fans branches off one shared origin, Resolve and Compete express one_of outcomes (a fixed-probability mixture and racing hazards), and Choose selects a branch from a data field. The compose front-end lowers a NamedTuple, a Tables.jl table, or a nested matrix to the same stack.
The package has four layers, each building on the one before.
Leaves are any Distributions.jl
UnivariateDistribution, used directly as the per-event delays.Composers wire named leaves into an event tree.
Combination and lowering join or collapse whole delays with
convolve_distributions,differenceandobserved_distribution.Parameters and edits read and reshape an assembled tree with
params_table,build_priors,update,pruneandsplice.
The Concepts page maps each modelling concept to the verb that builds it.
A first example
Compose two delays off a shared onset, then simulate and score a record.
using ComposedDistributions, Distributions, Random
tree = compose((onset_admit = Gamma(2.0, 1.0),
admit_death = LogNormal(0.5, 0.4)))
record = rand(Xoshiro(1), tree)(onset_admit = 1.5771947977125587, admit_death = 1.1939403667137392)The composed object scores that record straight back.
logpdf(tree, record)-1.6269591820480291Read its free parameters as a flat table, keyed by edge and parameter name.
params_table(tree)params_table (4 rows)
edge param value support prior
─────────── ───── ───── ────────── ─────
onset_admit shape 2.0 (0.0, Inf)
onset_admit scale 1.0 (0.0, Inf)
admit_death mu 0.5 (0.0, Inf)
admit_death sigma 0.4 (0.0, Inf)Uncertain distributions
A literature-reported delay rarely comes with exact parameters. Wrap the uncertainty inline with uncertain: parameters that are themselves distributions, nestable to any depth. The result is still a univariate distribution, so it composes as a leaf everywhere, and rand draws the marginal (a fresh parameter draw each call); the rest of the surface reports the template's central values until you pin concrete parameters with update (guard against a forgotten collapse with has_uncertain).
u = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2))
utree = compose((onset_admit = u, admit_death = LogNormal(0.5, 0.4)))
has_uncertain(utree)trueAn uncertain leaf is one of two deferred leaves: a leaf that is not yet a concrete distribution but a map to one, resolved before scoring. It maps a latent parameter (a value a sampler draws, with the spec as its prior); its sibling Varying maps an observed covariate (time, stratum), resolved by instantiate against a Context. Both delegate silently to a fallback until resolved, and each has a guard — has_uncertain / has_varying — for a fitting loop to check. See the varying-distributions reference for the observed case.
Key features
Distributions.jl integration. A composed object is a
Distribution, sologpdf,rand,mean,varand the rest of the interface work unchanged, and any Distributions.jl leaf composes with no package-specific hooks.One structure, many front-ends.
composelowers a NamedTuple, a Tables.jl table, or a nested matrix to the same composer stack.A readable, editable tree.
params_tableinventories the free parameters,build_priorsderives priors from their support, andupdate/prune/splicereshape the tree.Convolution built in. The package re-exports
ConvolvedDistributions, soconvolve_distributions,differenceand the quadrature surface are reachable through ComposedDistributions alone.Automatic differentiation. Scoring is differentiable through ForwardDiff, ReverseDiff, Mooncake and Enzyme, so a composed distribution drops into a probabilistic-programming fit.
Learning more
Find the right verb by intent on the Concepts page.
Work through the composers end to end in Composing distributions.
See mutually exclusive outcomes in Competing outcomes and multi-step delays in Delay chains and the linear chain trick.
Want the full interface? See the Public API.
Want to report a problem or ask a question? Open an issue or start a discussion on the GitHub repository.