Skip to content

Public Documentation

Documentation for ConvolvedDistributions's public interface.

Contents

Index

Public API

ConvolvedDistributions.AbstractCombinedDistribution Type
julia
abstract type AbstractCombinedDistribution{F<:Distributions.VariateForm, S<:Distributions.ValueSupport} <: Distributions.Distribution{F<:Distributions.VariateForm, S<:Distributions.ValueSupport}

Supertype of the multi-base algebraic combinations: Convolved (the sum of independent components) and Difference (Z = X - Y). These combine two or more base distributions by an algebraic operation. Parametric on variate form and value support for symmetry with the wider EpiAware family model (Distribution{F, S}), so the univariate members keep their UnivariateDistribution{Continuous} supertype and existing dispatch is unchanged.

Required of a concrete subtype:

  • params(d);

  • logpdf(d, x) finite on its support;

  • Base.show(io, d).

Verify a subtype with ConvolvedDistributions.TestUtils.test_combined_interface, and family membership with ConvolvedDistributions.TestUtils.test_abstract_membership.


Fields

source
ConvolvedDistributions.AbstractSolverMethod Type
julia
abstract type AbstractSolverMethod

Abstract type for solver methods used in CDF/PDF computation.

Subtypes determine whether analytical solutions are preferred or numerical integration is forced.


Fields

source
ConvolvedDistributions.AnalyticalSolver Type
julia
struct AnalyticalSolver{S} <: ConvolvedDistributions.AbstractSolverMethod

Solver that attempts analytical solutions when available, falling back to numerical integration.

Stores a numerical integration solver for use when no analytical solution exists for a given distribution pair.


Fields

  • solver::Any: Fallback solver for when no analytical solution exists.
source
ConvolvedDistributions.Convolved Type
julia
struct Convolved{C<:Tuple, M<:ConvolvedDistributions.AbstractSolverMethod} <: ConvolvedDistributions.AbstractCombinedDistribution{Distributions.Univariate, Distributions.Continuous}

Distribution of a sum of independent random variables (a convolution).

Convolved represents      where the are independent univariate distributions. It is the keystone primitive for multi-delay epidemiological models, where an observed delay is the sum of several independent stages (e.g. onset-to-death = onset-to-admission admission-to-death).

Components may have negative support (for example a Normal capturing pre-symptomatic transmission timing); minimum and maximum are the sums of the component supports, taking the value where a component is unbounded.

CDF computation

The CDF is computed by integrating one component out against the CDF of the others:

where is the last component (the integration variable) and is the convolution of the remaining components. For more than two components the remaining convolution is folded recursively.

Where an analytical convolution is available (Distributions.convolve applies, e.g. Normal+Normal, equal-scale Gamma, equal-rate Exponential) the two-component result is taken directly from the convolved distribution unless a NumericSolver method is set. All other cases use AD-safe fixed-node Gauss-Legendre quadrature: the integral is mapped from the fixed reference domain   onto the real bounds inside the integrand and reduced as a bare weighted dot product (gl_integrate), which lets every AD backend specialise on the integrand's own type so component Duals and tangents propagate.

The method field selects the CDF/PDF backend: an AnalyticalSolver (the default) uses the analytic convolution when one exists and falls back to quadrature otherwise, while a NumericSolver forces the numeric quadrature path even when an analytic convolution exists; the latter is useful for validation and debugging.

See also


Fields

  • components::Tuple: Tuple of independent component distributions to be summed.

  • method::ConvolvedDistributions.AbstractSolverMethod: Solver method choose the analytic vs numeric quadrature backend.

source
ConvolvedDistributions.Difference Type
julia
struct Difference{X<:(Distributions.UnivariateDistribution), Y<:(Distributions.UnivariateDistribution), M<:ConvolvedDistributions.AbstractSolverMethod} <: ConvolvedDistributions.AbstractCombinedDistribution{Distributions.Univariate, Distributions.Continuous}

Distribution of a difference of two independent random variables.

Difference represents    where X and Y are independent univariate distributions. It is the dual of Convolved (the sum  ): a convolution of X with the reflection of Y. Where a convolution gathers two delays into one longer gap, a difference is the signed gap between two events, so it arises as a derived observation (for example the offset between two independently timed measurements) rather than as a delay leaf.

Because the subtraction reflects Y, the support of Z is in general two-sided and can be negative: it runs from   to  , taking the value where a component is unbounded. Z is therefore not a non-negative delay distribution; treat a Difference as an observation or derived quantity, not as a delay leaf.

Independence

The construction assumes X and Y are independent. The density, CDF, mean and variance below all rely on this; they are not correct for dependent components.

Density and CDF computation

The density is the cross-correlation of the two component densities:

and the CDF integrates X's CDF against Y's density:

For a Normal-Normal pair the closed form   is used directly unless a NumericSolver method is set. All other cases use AD-safe fixed-node Gauss-Legendre quadrature (gl_integrate), the same construction Convolved uses: the integral is mapped from the fixed reference domain   onto the integration bounds inside the integrand and reduced as a bare weighted dot product, so every AD backend specialises on the integrand's own type and component Duals and tangents propagate.

The method field selects the backend: an AnalyticalSolver (the default) uses the analytic difference where one exists and falls back to quadrature otherwise, while a NumericSolver forces the numeric path even for a Normal-Normal pair (useful for validation).

See also


Fields

  • x::Distributions.UnivariateDistribution: The minuend component (the X in Z = X - Y).

  • y::Distributions.UnivariateDistribution: The subtrahend component (the Y in Z = X - Y).

  • method::ConvolvedDistributions.AbstractSolverMethod: Solver method choose the analytic vs numeric quadrature backend.

source
ConvolvedDistributions.GaussLegendre Type
julia
struct GaussLegendre{R}

Fixed-node Gauss-Legendre quadrature solver (the package default).

Integrates with a Gauss-Legendre rule of n nodes, evaluated as a bare weighted dot product (see gl_integrate). The constant control flow and the accumulator type being seeded from the integrand make this the AD-safe default: every supported AD backend can differentiate through it, unlike adaptive schemes whose node count depends on integrand values.

The reference nodes and weights are built once at construction and held on the solver, so the differentiated hot path is a pure weighted sum with no shared mutable state. This matters for trace-based reverse-mode backends (Enzyme, ReverseDiff): resolving the rule through a mutated global cache inside the integrand crashes Enzyme reverse, so the rule travels with the solver instead.

n = 64 is accurate to about 1e-13 on the smooth, density-weighted integrands used in this package. This is the core default and needs no heavy dependency. Load Integrals.jl and pass an Integrals.jl algorithm (e.g. QuadGKJL()) when adaptive accuracy is wanted and AD is not.

See also

  • gl_integrate: The underlying quadrature reduction.

  • integrate: The pluggable entry point dispatching on a solver.


Fields

  • n::Int64: Number of Gauss-Legendre nodes.

  • rule::Any: The reference Gauss-Legendre rule (nodes/weights on [-1, 1]).

source
ConvolvedDistributions.NumericSolver Type
julia
struct NumericSolver{S} <: ConvolvedDistributions.AbstractSolverMethod

Solver that always uses numerical integration.

Forces numerical computation even when analytical solutions are available, useful for testing and validation.

The solver field contains the numerical integration solver to use.


Fields

  • solver::Any: Numerical integration solver to use.
source
ConvolvedDistributions._ccdf_ad_safe Function
julia
_ccdf_ad_safe(
    dist::Distributions.UnivariateDistribution,
    u::Real
) -> Any

AD-safe ccdf(dist, u): the survival  .

_ccdf_ad_safe is the survival companion to _cdf_ad_safe. Generic dispatch falls through to Distributions.ccdf; the Gamma method routes through the AD-safe so the survival differentiates w.r.t. the Gamma shape/scale.

Public (not exported): ComposedDistributions.jl imports it and adds methods for its racing-hazard composers, so this is a supported downstream extension point.

Arguments

  • dist: the distribution whose survival is evaluated.

  • u: the evaluation point.

Examples

julia
using ConvolvedDistributions: _ccdf_ad_safe
using Distributions

_ccdf_ad_safe(Gamma(2.0, 1.0), 3.0)
source
ConvolvedDistributions._logccdf_ad_safe Function
julia
_logccdf_ad_safe(
    dist::Distributions.UnivariateDistribution,
    u::Real
) -> Any

AD-safe logccdf(dist, u): the log survival  .

_logccdf_ad_safe is the log-survival companion to _logcdf_ad_safe. Generic dispatch falls through to Distributions.logccdf; the Gamma method routes through the AD-safe so a survival term differentiates w.r.t. the Gamma shape/scale (the stock logccdf(::Gamma) calls _gammalogccdf, which has no ForwardDiff.Dual shape method and errors).

Public (not exported): ComposedDistributions.jl imports it and adds methods for its racing-hazard composers, so this is a supported downstream extension point.

Arguments

  • dist: the distribution whose log survival is evaluated.

  • u: the evaluation point.

Examples

julia
using ConvolvedDistributions: _logccdf_ad_safe
using Distributions

_logccdf_ad_safe(Gamma(2.0, 1.0), 3.0)
source
ConvolvedDistributions._pdf_ad_safe Function
julia
_pdf_ad_safe(
    dist::Distributions.UnivariateDistribution,
    t::Real
) -> Any

AD-safe pdf(dist, t) for the component density inside the quadratures.

_pdf_ad_safe is the density companion to _cdf_ad_safe: the numeric convolution and difference integrands evaluate component densities through it. Generic dispatch falls through to Distributions.pdf, and a downstream extension can add a method for a component whose stock pdf routes through functions that are not differentiable under the supported AD backends.

Public (not exported): ModifiedDistributions.jl hooks it so its modified components stay differentiable inside the quadrature, the same pattern as _ccdf_ad_safe.

Arguments

  • dist: the component distribution whose density is evaluated.

  • t: the evaluation point.

Examples

julia
using ConvolvedDistributions: _pdf_ad_safe
using Distributions

_pdf_ad_safe(Gamma(2.0, 1.0), 3.0)
source
ConvolvedDistributions.convolve_series Function
julia
convolve_series(
    delay::Distributions.UnivariateDistribution,
    series::AbstractVector{<:Real};
    interval
) -> Any

Convolve a timeseries with the discretised delay PMF of a distribution.

convolve_series(delay, series) discretises delay to a PMF over the unit grid and returns the causal discrete convolution of series with that PMF, truncated to the series window. With series the expected events at times 0, 1, ..., t (e.g. infections), the result is the expected downstream event counts at the same times (the EpiNow2-style latent / renewal observation layer).

The PMF masses are the raw CDF differences    over the grid (no renormalisation), so delay mass beyond the series window — and any mass below zero — is truncated. The masses depend differentiably on the delay parameters, so gradients flow under the supported AD backends.

Unlike convolved, which combines distributions into a single Convolved distribution, this returns a numeric series; the separate verb keeps convolved strictly for distribution construction.

Arguments

  • delay: the delay distribution (any UnivariateDistribution, including a Convolved total delay).

  • series: the input timeseries (expected events at unit-spaced times from 0).

Keyword Arguments

  • interval: the discretisation grid width, which is also the series time-step. The series is unit-spaced and the causal convolution shifts by integer series steps, so this must be 1 (the default); any other value is rejected with an ArgumentError to avoid conflating the grid width with the series step.

Examples

julia
using ConvolvedDistributions, Distributions

delay = convolved(Gamma(2.0, 1.0), LogNormal(0.5, 0.4))
infections = [0.0, 1.0, 3.0, 6.0, 8.0, 5.0, 2.0]
expected_counts = convolve_series(delay, infections)

See also

source
ConvolvedDistributions.convolved Function
julia
convolved(
    components::AbstractVector{<:Distributions.UnivariateDistribution};
    method
) -> ConvolvedDistributions.Convolved{C, AnalyticalSolver{ConvolvedDistributions.GaussLegendre{ConvolvedDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where C<:Tuple

Create the distribution of a sum of independent delays (a convolution).

Accepts either two or more positional component distributions, or a single vector/tuple of components. Returns a Convolved distribution.

Arguments

  • components: Two or more UnivariateDistributions, or a vector/tuple of them.

Keyword Arguments

  • method: The solver method, an AnalyticalSolver (the default) or NumericSolver. NumericSolver forces numeric quadrature even when an analytic convolution is available.

Examples

julia
using ConvolvedDistributions, Distributions

# Sum of two delays
d = convolved(Gamma(2.0, 1.0), LogNormal(1.5, 0.5))
cdf_at_5 = cdf(d, 5.0)

# Sum of three delays from a vector
d3 = convolved([Gamma(2.0, 1.0), Gamma(1.0, 1.0), Normal(0.0, 1.0)])
mean_sample = rand(d3)

# Force numeric quadrature even for an analytic pair
dn = convolved(Normal(0.0, 1.0), Normal(1.0, 2.0);
    method = NumericSolver())
cdf_numeric = cdf(dn, 2.0)

See also

source
ConvolvedDistributions.difference Function
julia
difference(
    x::Distributions.UnivariateDistribution,
    y::Distributions.UnivariateDistribution;
    method
) -> Difference{X, Y, AnalyticalSolver{ConvolvedDistributions.GaussLegendre{ConvolvedDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where {X<:(Distributions.UnivariateDistribution), Y<:(Distributions.UnivariateDistribution)}

Create the distribution of a difference of two independent variables.

Returns a Difference representing   . This is the dual of convolved: a convolution forms the sum of two delays, a difference the signed gap between two events. The support of Z can be negative, so Z is an observation or derived quantity rather than a non-negative delay leaf (see Difference).

X and Y are assumed independent.

Arguments

  • x: The minuend distribution (the X in Z = X - Y), a UnivariateDistribution.

  • y: The subtrahend distribution (the Y in Z = X - Y), a UnivariateDistribution.

Keyword Arguments

  • method: The solver method, an AnalyticalSolver (the default) or NumericSolver. NumericSolver forces numeric quadrature even for a Normal-Normal pair, mirroring convolved.

Examples

julia
using ConvolvedDistributions, Distributions

# Difference of two delays; mean is the difference of the means (≈ 3)
d = difference(Normal(5.0, 1.0), Normal(2.0, 1.0))
mean(d)

See also

source
ConvolvedDistributions.gl_integrate Function
julia
gl_integrate(f, lo, hi) -> Any
gl_integrate(
    f,
    lo,
    hi,
    rule::ConvolvedDistributions._GL
) -> Any

Integrate a scalar function f over [lo, hi] by fixed-node Gauss-Legendre quadrature.

The reference domain [-1, 1] is mapped onto [lo, hi] inside the integrand and the result reduced as a weighted dot product, so the accumulator's element type is taken from the integrand and AD Duals and tangents propagate. Returns a typed zero when hi <= lo.

Arguments

  • f: The scalar integrand.

  • lo: Lower integration bound.

  • hi: Upper integration bound.

  • rule: Gauss-Legendre rule to use (default: the 192-node convolution rule).

Examples

julia
using ConvolvedDistributions

# Integrate x^2 over [0, 1] (exact value 1/3)
approx = ConvolvedDistributions.gl_integrate(x -> x^2, 0.0, 1.0)

See also

source
ConvolvedDistributions.integrate Function
julia
integrate(
    solver::ConvolvedDistributions.GaussLegendre,
    f,
    lower,
    upper
) -> Any

Integrate a scalar function f over [lower, upper] using solver.

This is the pluggable integration entry point: every integral in the package calls integrate, dispatching on the solver type. The default GaussLegendre solver routes to gl_integrate. Loading the optional Integrals.jl extension adds a method for Integrals.jl algorithms (e.g. QuadGKJL()), which builds an IntegralProblem and calls solve.

Arguments

  • solver: The integration backend. GaussLegendre by default; any Integrals.jl algorithm when that extension is loaded.

  • f: The scalar integrand.

  • lower: Lower integration bound.

  • upper: Upper integration bound.

Examples

julia
using ConvolvedDistributions

solver = ConvolvedDistributions.GaussLegendre(; n = 64)
approx = ConvolvedDistributions.integrate(solver, x -> x^2, 0.0, 1.0)

See also

source