| Documentation | Build Status | Code Quality | License & DOI | Downloads |
|---|---|---|---|---|
| ForwardDiff | ReverseDiff (tape) | Enzyme forward | Enzyme reverse | Mooncake reverse | Mooncake forward |
|---|---|---|---|---|---|
Wrappers for Distributions.jl univariate distributions that each change one behaviour — rescaling, likelihood weighting, hazard modification, or a forward transform — while everything else keeps working, plus the generic get_dist unwrap protocol.
- A model routinely needs "the same delay, but weighted, rescaled, or hazard-shifted"; ModifiedDistributions wraps each change as one small, composable piece instead of hand-deriving the change-of-variables maths each time.
- Every wrapper stays a complete distribution — sampling, quantiles, moments — so a modified delay drops into a PPL model exactly like the distribution it wraps.
- Wrappers nest and unwrap cleanly, so a pipeline built from several small changes stays inspectable and reversible rather than collapsing into one opaque function.
- Weighting a likelihood is a one-line wrapper instead of an ad hoc
n * logpdf(...)term scattered through model code. - Hazard-scale changes, such as an intervention that shifts risk, have no Distributions.jl counterpart and are given here in closed form.
- The same wrappers apply across ComposedDistributions.jl chains and ConvolvedDistributions.jl count series, so a delay modified once carries that change through the rest of the pipeline.
See documentation for a full walkthrough.
Modifiers nest, so a real pipeline stacks several changes on one delay: an intervention that halves the hazard of admission, a half-day reporting lag, and a 60% ascertainment fraction tagged for a downstream count series.
using ModifiedDistributions, Distributions
admission = Gamma(2.0, 1.0) # baseline infection-to-admission delay
pipeline = thin(affine(modify(admission, -log(2.0)); shift = 0.5), 0.6)pipeline prints as the nested wrapper it is.
pipelineEach stage compounds the three-day survival: halving the hazard raises it to
its square root, and the reporting lag raises it further (day 3 is now
effectively day 2.5 post-admission); thin does not touch the scalar
distribution at all, only tagging it for later use.
(baseline_survival = ccdf(admission, 3.0),
after_intervention = ccdf(modify(admission, -log(2.0)), 3.0),
after_reporting_lag = ccdf(pipeline, 3.0))Unwrapping recovers the baseline delay underneath every layer.
get_dist_recursive(pipeline) == admissionThe getting started guide
carries this same pipeline further: what thin does once it meets a real
count series, and how modifiers apply across a composed chain.
Distributions.jl already supports affine arithmetic on some distributions (2.0 * X + 1.0) by returning a new parameterisation where one exists.
affine instead wraps any univariate distribution with the exact change-of-variables maths, so it works uniformly and keeps the inner distribution recoverable via get_dist.
Likewise weight replaces ad hoc n * logpdf(d, x) terms in model code with a distribution object that carries its weight, and modify gives hazard-scale transforms that have no Distributions.jl counterpart.
- ComposedDistributions.jl composes distributions into event-tree chains; a package extension here lets the modifier verbs apply across a chain's observed total, and ComposedDistributions.jl's own leaf-protocol support lets a modified leaf compose inside a chain.
- ConvolvedDistributions.jl sums independent delays and convolves count series; a package extension applies
thin/cumulativeto the convolved counts and lets modified distributions serve as convolution components. - LoweredDistributions.jl turns a distribution into a backend-agnostic dynamical-systems representation; a package extension here lowers the modifiers that carry dynamics (an
affinerescale, amodifyhazard change on anExponential) and refuses the observation-only ones (a shift, aweight, a forward transform) rather than approximating them. - CensoredDistributions.jl builds primary-event and interval censoring on distributions, including ones already modified by this package.
- DistributionsInference.jl is the emerging home for probabilistic-programming integrations (Turing.jl, DynamicPPL, Bijectors) that a modified or weighted distribution plugs into.
- Want to get started running code? See the getting started guide.
- Want to understand the API? See the API reference.
- Want to see the code? Check out our GitHub repository.
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.
We welcome contributions and new contributors! This package follows ColPrac and the SciML style.
If you would like to support ModifiedDistributions, please star the repository — such metrics help secure future funding.
If you use ModifiedDistributions in your work, please cite it (the DOI is a placeholder until the first Zenodo release):
@software{ModifiedDistributions_jl,
author = {Sam Abbott and EpiAware contributors},
title = {ModifiedDistributions.jl},
year = {2026},
doi = {10.5281/zenodo.XXXXXXX},
url = {https://github.com/EpiAware/ModifiedDistributions.jl}
}Please note that the ModifiedDistributions project is released with a Contributor Code of Conduct. By contributing, you agree to abide by its terms.