ComposedDistributions
A verb grammar for n-ary composition over any Distributions.jl distribution.
Why ComposedDistributions?
Compose delays into chains (
sequential), independent branches (parallel), fixed-probability or racing one_of outcomes (resolve/compete) and data-selected disjunctions (choose), over anyUnivariateDistribution.One object scores an observed record with
logpdfand simulates one withrand, so a model is built once and used in both directions.Build a whole tree from a
NamedTuple, aTables.jltable, or a nested matrix withcompose, and read its structure withparams_table,event_names,event, andevent_tree.Turn the parameter table into a nested prior with
build_priors, and edit the tree withupdate,prune, andsplice.Attach parameter uncertainty with
uncertain(parameters that are themselves distributions, nestable):randdraws the marginal, andupdate(tree, params)collapses an uncertain leaf to its concrete template.Hard-deps and re-exports
ConvolvedDistributions(a chain collapses to a convolved total viaobserved_distribution), so its convolution and quadrature surface is reachable through this package alone.No censoring: this is the generic composition layer.
Getting started
See documentation for a full walkthrough.
using ComposedDistributions, Distributions
# A two-step delay chain, then its parameter table and a default prior set.
tree = compose((onset_admit = [Gamma(2.0, 1.0), LogNormal(0.5, 0.4)],))
params_table(tree)
priors = build_priors(params_table(tree))
# A death-vs-discharge competition (the death branch probability is the CFR).
node = resolve(:death => (Gamma(1.5, 1.0), 0.3), :disch => Gamma(2.0, 1.5))
mean(node)2.55Relationship to Distributions.jl
ComposedDistributions builds on Distributions.jl rather than replacing it. Every leaf is a Distributions.jl UnivariateDistribution, and a composed object is itself a Distribution, so logpdf, rand, mean, var and the rest of the interface work unchanged.
| Aspect | Distributions.jl | ComposedDistributions |
|---|---|---|
| Scope | one distribution | many delays wired into an event tree |
| Question | "what is this delay?" | "how do these events relate?" |
| Builds on | — | any Distributions.jl UnivariateDistribution as a leaf |
| Adds | — | compose, the five composers, a parameter table and structural edits |
Because a composed object is a Distribution, it also works with truncated() from Distributions.jl and drops into any code that expects a distribution.
What packages work well with ComposedDistributions?
Distributions.jl supplies the leaf distributions and the interface a composed object implements.
ConvolvedDistributions.jl is re-exported, so convolution (
convolve_distributions,difference) and quadrature are reachable through ComposedDistributions alone.Tables.jl sources build a composer through
compose, andparams_tablereturns a Tables.jl table.Turing.jl and the wider probabilistic-programming ecosystem, where automatic-differentiation-friendly scoring lets a composed distribution drop into a Bayesian fit.
Where to learn more
Want to get started running code? See the getting started guide.
Want the right verb by intent? See the Concepts page.
Want to understand the API? See the API reference.
Want to chat about
ComposedDistributions? Post on our GitHub Discussions.Want to see the code? Check out our GitHub repository.
Contributing
We welcome contributions and new contributors! This package follows ColPrac and the SciML style.
Supporting and citing
If you would like to support ComposedDistributions, please star the repository — such metrics help secure future funding.
If you use ComposedDistributions in your work, please cite it:
@software{ComposedDistributions_jl,
author = {Sam Abbott and EpiAware contributors},
title = {ComposedDistributions.jl},
year = {2026},
doi = {10.5281/zenodo.XXXXXXX}, # replace once released
url = {https://github.com/EpiAware/ComposedDistributions.jl}
}Code of conduct
Please note that the ComposedDistributions project is released with a Contributor Code of Conduct. By contributing, you agree to abide by its terms.