Skip to content

Public Documentation

Documentation for ComposedDistributions's public interface.

Contents

Index

Public API

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

Supertype of the composer nodes that combine named child distributions into an event tree: the multivariate Sequential / Parallel / Choose and the univariate one_of family (AbstractOneOf: Resolve / Compete). Parametric on variate form so the one supertype spans both.

Required methods a concrete subtype implements (the node interface):

  • child_nleaves(c), child_logpdf(c, x, offset, n), child_rand!(out, offset, rng, c) — walk the flat event vector;

  • component_names(c) — the child names;

  • params(c) and params_table(c);

  • event_names(c) (flat) and event_tree(c) (nested);

  • Base.show(io, c).

Verify a subtype with ComposedDistributions.TestUtils.test_composed_interface.


Fields

source
ComposedDistributions.AbstractContext Type
julia
abstract type AbstractContext

Supertype of the covariate contexts a composed tree is resolved against.

A subtype carries the covariates a Varying leaf reads. Context is the concrete open-NamedTuple implementation; the abstract type is what the uncertain distributions work can extend with its own sampled-parameter context. instantiate dispatches on AbstractContext.

See also


Fields

source
ComposedDistributions.AbstractMultiChild Type
julia
abstract type AbstractMultiChild{S<:Distributions.ValueSupport} <: ComposedDistributions.AbstractComposedDistribution{Distributions.Multivariate, S<:Distributions.ValueSupport}
julia
AbstractMultiChild{S<:ValueSupport}

Supertype of the positional multi-child composers Sequential and Parallel (subtype of AbstractComposedDistribution{Multivariate, S}). These two store .components / .names and are walked positionally by the tree machinery, so they share dispatch on ::AbstractMultiChild (the supertype the tree walkers key off). Choose (disjoint alternatives) is a sibling, not a multi-child node.


Fields

source
ComposedDistributions.AbstractOneOf Type
julia
abstract type AbstractOneOf <: ComposedDistributions.AbstractComposedDistribution{Distributions.Univariate, Distributions.Continuous}

Shared supertype of the one_of-outcome composers.

The two one_of-outcome nodes — the fixed-probability mixture Resolve (cause and timing independent) and the racing-hazard Compete (the winning probability derived from the hazards, timing coupled) — subtype AbstractOneOf. The tree walkers dispatch on it wherever the behaviour is shared (one event slot per outcome, the shared origin, the per-outcome rand) and on the concrete type only where the scoring arithmetic differs.

AbstractOneOf is the univariate arm of the composer hierarchy: it subtypes AbstractComposedDistribution{Univariate, Continuous}, so it stays a UnivariateDistribution while sharing the composed supertype the multivariate Sequential / Parallel / Choose also sit under.

Examples

julia
using ComposedDistributions, Distributions

r = resolve(:death => (Gamma(1.5, 1.0), 0.3), :disch => Gamma(2.0, 1.5))
r isa ComposedDistributions.AbstractOneOf

See also


Fields

source

Missing docstring.

Missing docstring for ComposedDistributions.AbstractSolverMethod. Check Documenter's build log for details.

Missing docstring.

Missing docstring for ComposedDistributions.AnalyticalSolver. Check Documenter's build log for details.

ComposedDistributions.Choose Type
julia
struct Choose{N, K<:NTuple{N, Symbol}, A<:Tuple} <: ComposedDistributions.AbstractComposedDistribution{Distributions.Multivariate, Distributions.Continuous}

A data-selected disjunction over independent named alternatives.

Choose holds NAMED alternatives , each an independent sub-distribution, and a selector naming the DATA field that picks which alternative applies to a record. Exactly one alternative is active per record, chosen by the selector value, NOT by a branch probability and NOT off a shared origin. This is the disjunctive split that neither Parallel (shared origin, product over branches) nor Resolve (shared origin, probabilistic mixture) expresses: the alternatives are genuinely independent sub-models with different origins, and the data says which one generated the record.

Scoring and model dispatch route to the SELECTED alternative: logpdf(d, x; kind) takes the chosen name as the kind keyword (no default — a Choose has no single distribution to score without a selection). Sampling has two forms: rand(d; kind) draws the named alternative directly, while a bare rand(d) (no kind, the forward-simulation path) samples an alternative uniformly and returns a self-describing record tagging which was drawn (the selector field set to its name plus the alternative's own draw), so logpdf(d, rand(d)) round-trips with no kind argument. The selection walk is type-stable: the selected alternative is found by a hand-rolled recursion over the name tuple that barriers into the chosen alternative's concrete type, so inference of the hot-path logpdf is preserved.

An alternative may itself be any distribution or a nested composer (Sequential, Parallel, Resolve, or another Choose), so a composed tree nests INSIDE a data-selected split. A Choose may ALSO nest the other way, as a child of a Sequential / Parallel / compose composer: the flat, data-free value path (logpdf/rand without a kind) commits to its FIRST alternative, so the node's flat width is that alternative's leaf count; every alternative must share that leaf count for the nested Choose to occupy one fixed flat slot, or the parent's width query errors.

For prior introspection (params_table, build_priors, update) the alternatives' parameters are namespaced per alternative: independent per-branch params live under their alternative name (index.… / sourced.…), so each branch's parameters are inventoried and sampled separately. A parameter tied across alternatives via shared(:tag, ...) is keyed once by its tag and is inventoried once and sampled once, so the tied value is shared by every alternative that uses it.

Fields

  • names: tuple of the alternative names (Symbols).

  • alternatives: tuple of the alternative distributions, one per name.

  • selector: the row field name (Symbol) whose value selects an alternative.

See also

  • choose: friendly constructor over name => dist pairs

  • Resolve: exactly one of several shared-origin outcomes (mixture)

  • Parallel: independent shared-origin branches (product)


Fields

  • names::NTuple{N, Symbol} where N: Tuple of the alternative names (Symbols).

  • alternatives::Tuple: Tuple of the alternative distributions, one per name.

  • selector::Symbol: The row field name (Symbol) whose value selects an alternative.

source
ComposedDistributions.Compete Type
julia
struct Compete{C<:Tuple, D<:Tuple} <: ComposedDistributions.AbstractOneOf

Resolve risks by racing hazards: the dual of convolve_distributions under MINIMUM instead of sum.

Given cause-specific delay distributions D_1, ..., D_n, Compete represents the first-event time T = min_k D_k together with which cause won. The marginal any-event survival is ∏_k S_k(t) and density ∑_j f_j(t) ∏_{k≠j} S_k(t), so it nests as a univariate leaf. Observing a resolved (cause j, time t) scores f_j(t) ∏_{k≠j} S_k(t). The winning probability of each cause is DERIVED from the hazards (P(cause = j) = ∫ f_j ∏_{k≠j} S_k), NOT a free parameter — this is the key difference from the fixed-probability mixture Resolve.

Build it with the compete constructor by giving BARE delays (no branch probabilities): compete(:death => D1, :recover => D2).

Three views must agree: rand draws a latent time per cause and returns the argmin; logpdf is the one_of-risks likelihood (marginal or cause-resolved); and the forward convolve_distributions stream is the per-outcome sub-density, sub-stochastic (not renormalised).Competeships against plainDistributions.ccdf/logccdf, so any stock univariate leaf races without a package-specific interface.

Fields

  • names: tuple of the one_of outcome names (Symbols).

  • delays: tuple of the cause-specific delay distributions.

See also

  • compete: the constructor (bare delays; no branch probabilities).

  • Resolve: the fixed-probability mixture sibling.

  • Distributions.probs: the derived per-cause winning probabilities.

  • convolve_distributions: the sum dual (events in series).


Fields

  • names::Tuple: Tuple of the one_of outcome names (Symbols).

  • delays::Tuple: Tuple of the cause-specific delay distributions.

source
ComposedDistributions.ComposedLogDensity Type
julia
struct ComposedLogDensity{D<:ComposedDistributions.AbstractComposedDistribution, P, T, L, FP}

A PPL-neutral log-density over a composed distribution's flat parameters.

ComposedLogDensity carries everything needed to evaluate the (unnormalised) log-posterior of a composed distribution over its ESTIMATED flat parameter vector, with no DynamicPPL/Turing dependency: the template dist, the per-parameter priors (a nested NamedTuple; the uncertain specs read off the object by default), the observed data, and a loglik reducer scoring data against the reconstructed distribution. Build it with as_logdensity; evaluate it on a flat vector with logdensity.

It is the spec a LogDensityProblems weakdep extension wraps as a standard problem (sampleable by AdvancedHMC / DynamicHMC / Pathfinder); the flat layout is params_table(dist)'s row order restricted to the estimated (spec'd) parameters throughout.

Fields

  • dist: the template composed distribution (the structure to reconstruct).

  • priors: nested prior NamedTuple keyed like params(dist), read at the estimated (spec'd) parameters.

  • data: the observed records scored by loglik.

  • loglik: a reducer (d, data) -> Real (default sums logpdf(d, record)).

  • flat_priors: priors flattened once at construction, in estimated-row order, so logdensity does not re-derive it on every evaluation.

See also


Fields

  • dist::ComposedDistributions.AbstractComposedDistribution

  • priors::Any

  • data::Any

  • loglik::Any

  • flat_priors::Any

source
ComposedDistributions.Context Type
julia
struct Context{NT<:NamedTuple} <: AbstractContext

The covariate context a Varying leaf is resolved against.

A Context is an open bag of covariates (a NamedTuple) — calendar time, a region/stratum, or (for the uncertain-distributions work) sampled parameter values. instantiate reads the covariate a leaf names from it. Build one with keyword covariates. It is open (rather than a fixed time field) so it can also carry the uncertain-distributions work's sampled parameters; see design/0001-time-and-covariate-varying-distributions.md for the rationale.

Examples

julia
using ComposedDistributions

ctx = Context(time = 4.0)
ctx.covariates.time

See also


Fields

  • covariates::NamedTuple: The covariates keyed by name (time, region, sampled params, ...).
source

Missing docstring.

Missing docstring for ComposedDistributions.Convolved. Check Documenter's build log for details.

Missing docstring.

Missing docstring for ComposedDistributions.Difference. Check Documenter's build log for details.

Missing docstring.

Missing docstring for ComposedDistributions.GaussLegendre. Check Documenter's build log for details.

ComposedDistributions.NoEvent Type
julia
struct NoEvent <: Distributions.Distribution{Distributions.Univariate, Distributions.Continuous}

Marker distribution for a NO-EVENT (absorbing) outcome of a resolve node: the outcome where nothing happens and no event time is written.

A none => (NoEvent(), q) branch carries no delay; its mass q is the probability that no event occurs. On rand a no-event win yields missing (no time recorded). On logpdf an OBSERVED non-occurrence (an explicit no event by the horizon record) scores the survival term log q (mixture) or the racing-hazard survival ∏ S_k; a latent non-occurrence (a record whose no-event slot is simply missing) contributes no one_of term.

NoEvent is a degenerate placeholder, not a sampling distribution: it has no support and errors if asked for a density or a draw. It exists only to MARK the absorbing branch so the one_of node carries its mass q.

See also

  • resolve: the fixed-probability constructor.

  • Resolve: the mixture one_of node.


Fields

source

Missing docstring.

Missing docstring for ComposedDistributions.NumericSolver. Check Documenter's build log for details.

ComposedDistributions.Parallel Type
julia
struct Parallel{C<:Tuple, N<:Tuple} <: ComposedDistributions.AbstractMultiChild{Distributions.Continuous}

Independent branches composed from any univariate distributions.

Parallel places branch distributions off one origin, with the realisation the vector of branch values . A branch may itself be a Sequential, Parallel, Resolve, Compete or Choose composer, so trees nest recursively and the nesting is the tree.

logpdf is the sum of the per-branch log-densities,

The branches are independent here: this is the plain generic composition. The shared-origin coupling (where every branch shares one latent primary event) is a censored specialisation layered on top elsewhere, not part of this type.

Fields

  • components: tuple of the branch distributions (each univariate or a nested composer).

  • names: tuple of the branch names (Symbols), one per component; the compose front-ends thread the user's names through, positional construction assigns :branch_1, :branch_2, ....

See also


Fields

  • components::Tuple: Tuple of the branch distributions (each univariate or a nested composer).

  • names::Tuple: Tuple of the branch names (Symbols), one per component. The compose NamedTuple/table front-ends use the user's keys; positional construction assigns :branch_1, :branch_2, ....

source
ComposedDistributions.Resolve Type
julia
struct Resolve{C<:Tuple, D<:Tuple, P<:Tuple, S} <: ComposedDistributions.AbstractOneOf

Resolve outcomes composed from any univariate distributions: exactly one of several outcomes occurs, governed by branch probabilities summing to one.

Resolve names each one_of outcome, its delay distribution, and the branch probability of that outcome. It lowers to a Distributions.MixtureModel (see as_mixture) over the outcome delays weighted by the branch probabilities, so the realisation is a single time and the type is univariate. A death-versus-recovery competition makes the death branch probability the case-fatality ratio.

Being univariate, a Resolve nests as a child of Sequential or Parallel. This is the plain generic composition; per-record outcome selection and censoring are not part of this type.

The branch probabilities are ordinarily fixed structure. To ESTIMATE them, attach a simplex-valued Distributions.Dirichlet prior with update(node, (branch_probs = Dirichlet(α),)): the Dirichlet is what you write, but the codec estimates the node through the Dirichlet's K-1 stick-breaking coordinates (:stick_1 … :stick_{K-1}, each a Beta, so every draw lands on the simplex and the gradient is well-defined), and the probabilities are recovered from any draw (via update / Distributions.probs). See update for the full story.

Fields

  • names: tuple of the one_of outcome names (Symbols).

  • delays: tuple of the one_of outcome delay distributions.

  • branch_probs: tuple of the branch probabilities, summing to one.

  • branch_prob_prior: the attached Dirichlet prior when the branch probabilities are uncertain, else nothing (fixed structure).

See also


Fields

  • names::Tuple: Tuple of the one_of outcome names (Symbols).

  • delays::Tuple: Tuple of the one_of outcome delay distributions.

  • branch_probs::Tuple: Tuple of the branch probabilities, summing to one.

  • branch_prob_prior::Any: The attached simplex-valued prior over the branch probabilities (a Distributions.Dirichlet), or nothing when the probabilities are fixed structure. When present the branch probabilities are ESTIMATED through the stick-breaking codec: the user writes the Dirichlet, K-1 stick coordinates are what the sampler estimates, and the probabilities are recovered from any draw (see update).

source
ComposedDistributions.Sequential Type
julia
struct Sequential{C<:Tuple, N<:Tuple} <: ComposedDistributions.AbstractMultiChild{Distributions.Continuous}

A chain of independent steps composed from any univariate distributions.

Sequential links events     through independent step distributions . A realisation is the flat vector of step values (one value per step). A step may itself be a Sequential, Parallel, Resolve, Compete or Choose composer, in which case it contributes its own flat sub-vector, so chains nest recursively and the nesting is the tree.

logpdf sums the per-step log-densities over the matching slices of the value vector:

This is the plain generic composition; censoring and per-record marginalisation are not part of this type. Cumulative event times, if wanted, are the running sum of the step values.

Fields

  • components: tuple of the step distributions (each univariate or a nested composer).

  • names: tuple of the step names (Symbols), one per component; the compose front-ends thread the user's names through, positional construction assigns :step_1, :step_2, ....

See also


Fields

  • components::Tuple: Tuple of the step distributions (each univariate or a nested composer).

  • names::Tuple: Tuple of the step names (Symbols), one per component. The compose NamedTuple front-end uses the user's keys; positional construction assigns :step_1, :step_2, ....

source
ComposedDistributions.Shared Type
julia
struct Shared{D<:(Distributions.UnivariateDistribution)} <: Distributions.UnivariateDistribution{Distributions.ValueSupport}

A name-tagged leaf tied across the branches of a composed distribution.

Shared wraps a leaf distribution with a tag (a Symbol) marking it as a shared parameter group. Two Shared leaves carrying the SAME tag are treated as the SAME free parameter by the prior/params interface: params_table lists the group's parameters ONCE (deduped by tag), a downstream composed_parameters_model samples the group ONCE and places the sampled values in every occurrence, and update updates all occurrences from one entry. The wrapper is transparent to scoring and sampling (every distribution method delegates to the wrapped leaf), so it only changes how parameters are inventoried, sampled and reconstructed.

Fields

  • tag: the shared-parameter group name (Symbol).

  • dist: the wrapped leaf distribution.

See also


Fields

  • tag::Symbol: The shared-parameter group name (Symbol).

  • dist::Distributions.UnivariateDistribution: The wrapped leaf distribution.

source
ComposedDistributions.Uncertain Type
julia
struct Uncertain{VS<:Distributions.ValueSupport, L<:Distributions.Distribution{Distributions.Univariate, VS<:Distributions.ValueSupport}, S<:NamedTuple} <: Distributions.Distribution{Distributions.Univariate, VS<:Distributions.ValueSupport}

A leaf distribution whose parameters are themselves distributions.

Uncertain pairs a concrete template leaf with specs, a NamedTuple mapping parameter names (as in params_table's param column) to distributions. A spec entry may itself be an Uncertain, so parameter uncertainty nests. Parameters without a spec stay fixed at the template's values, and the template's fixed wrapper structure (truncation, censoring) is carried through every draw via free_leaf/rewrap_leaf.

The generative model is hierarchical:

with fixed parameters taken from the template. rand draws the marginal (parameters drawn internally). The rest of the univariate surface (scalar logpdf/pdf/cdf/quantile, the moments) delegates to the template, so it reports the leaf AT the template's central parameter values, NOT the marginal. Collapse an uncertain leaf to a concrete distribution by pinning its parameters with update(tree, params).

Only rand is marginal

Every other method — logpdf/cdf/quantile/... AND the moments mean/var/std — silently reports the template's central values, not the marginal. Scoring or summarising a raw Uncertain leaf therefore answers "as if" its parameters were fixed at the template. Guard a scoring/fitting loop with has_uncertain, and collapse to concrete values first with update(tree, params).

Fields

  • template: the concrete (possibly wrapped) leaf supplying the family, the fixed parameter values, and the fixed wrapper structure.

  • specs: NamedTuple of the uncertain parameters, each value a distribution (possibly itself an Uncertain).

See also

  • uncertain: the public constructor.

  • update: collapse an uncertain leaf to a concrete distribution.


Fields

  • template::Distributions.UnivariateDistribution: The concrete (possibly wrapped) template leaf: family, fixed parameter values, and fixed wrapper structure (truncation / censoring).

  • specs::NamedTuple: NamedTuple of the uncertain parameters: each key a parameter name of the template's free delay, each value a distribution (possibly Uncertain).

source
ComposedDistributions.Varying Type
julia
struct Varying{F, D<:(Distributions.UnivariateDistribution)} <: Distributions.Distribution{Distributions.Univariate, Distributions.Continuous}

A context-indexed leaf: a delay whose distribution varies with a covariate.

Varying holds a map f from a covariate value to a UnivariateDistribution (e.g. t -> Gamma(shape(t), scale)), the covariate name it reads from a Context (default :time), and a reference distribution used whenever the leaf is queried WITHOUT a context. Because Varying <: UnivariateDistribution it drops into Sequential / Parallel / compose as an ordinary leaf, and every Distributions method (logpdf, cdf, mean, rand, params, ...) delegates to the reference, so a tree with varying leaves still scores and samples at its reference by default.

instantiate(d, ctx) is the step that swaps the reference for f evaluated at the context's covariate: instantiate(leaf, Context(time = 4.0)) returns f(4.0). Resolve a whole tree at a context and then score / sample / convolve the concrete result.

Warning

Because the leaf delegates to reference, scoring or sampling a tree that still holds a Varying leaf does NOT error — it silently uses the reference (a wrong answer against real per-record covariates). Always instantiate first, and guard a fitting loop with has_varying.

The varying map f is FIXED STRUCTURE (like a truncation bound or a censoring window), so the introspection interface (params_table, update) treats the reference's parameters as the free parameters and peels/rewraps through the wrapper; the coefficients of f are not (yet) inventoried (see the design note's open questions).

Fields

  • f: map from a covariate value to a UnivariateDistribution.

  • covariate: the Context field name to read (Symbol, default :time).

  • reference: the distribution used when no context is supplied.

See also


Fields

  • f::Any: Map from a covariate value to a UnivariateDistribution.

  • covariate::Symbol: The Context field name this leaf reads (default :time).

  • reference::Distributions.UnivariateDistribution: The distribution used when no context is supplied.

source
ComposedDistributions.as_logdensity Function
julia
as_logdensity(
    dist::ComposedDistributions.AbstractComposedDistribution,
    priors,
    data;
    loglik
) -> ComposedDistributions.ComposedLogDensity{D, P, _A, typeof(ComposedDistributions._default_loglik), FP} where {D<:ComposedDistributions.AbstractComposedDistribution, P<:NamedTuple, _A, FP<:(Vector)}

Assemble a ComposedLogDensity from a composed distribution and data.

as_logdensity(dist, data; loglik) packages the template dist and the observed data into the PPL-neutral log-density spec, reading the priors off the object's uncertain specs (the estimation boundary). The result evaluates the (unnormalised) log-posterior over the ESTIMATED flat parameter vector — the spec'd parameters — via logdensity. A tree with no uncertain leaves estimates nothing: the flat vector is empty and logdensity is the data likelihood at the fixed tree. Promote a tree to estimate its free parameters with default priors through update(tree, param_priors(tree)).

as_logdensity(dist, priors, data) overrides the on-object specs with an explicit nested prior NamedTuple, read at the same estimated (spec'd) rows. loglik defaults to summing logpdf(dist, record) over data; pass a custom reducer for record-aware scoring.

Arguments

  • dist: the template composed distribution, carrying its uncertain specs.

  • priors: (optional) a nested prior NamedTuple keyed like params(dist), overriding the on-object specs at the estimated rows (default: the object's specs).

  • data: the observed records.

Keyword Arguments

  • loglik: a reducer (d, data) -> Real scoring data against the reconstructed distribution (default: sum of logpdf(d, record)).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((
    onset_admit = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2)),
    admit_death = LogNormal(0.5, 0.4)))
data = [[0.5, 2.0], [1.0, 3.0]]
# Public but not exported; reach the spec by the qualified name. Priors read
# off the object's specs; the one estimated parameter is onset_admit.shape.
prob = ComposedDistributions.as_logdensity(tree, data)
ComposedDistributions.logdensity(prob, [2.0])

See also

source
ComposedDistributions.as_mixture Function
julia
as_mixture(c::Resolve) -> Distributions.MixtureModel

Lower a Resolve node to a Distributions.MixtureModel.

Returns the MixtureModel over the outcome delays weighted by the branch probabilities, the marginal time-to-resolution regardless of which outcome occurs.

Examples

julia
using ComposedDistributions, Distributions

node = Resolve(:death => (Gamma(1.5, 1.0), 0.3),
    :disch => (Gamma(2.0, 1.5), 0.7))
as_mixture(node)

See also

source
ComposedDistributions.build_priors Function
julia
build_priors(table; priors, default) -> NamedTuple

Assemble the nested prior NamedTuple from a params_table inventory.

build_priors(table; priors, default) turns the flat parameter table into the nested NamedTuple that a downstream composed_parameters_model (and update) expect, so users define priors against the flat table rows rather than by hand-matching the tree.

For each row the prior is chosen in order:

  1. a user priors override for that (edge, param), if present, else

  2. the row's attached prior (an uncertain parameter's spec rides the table's prior column), if present, else

  3. default(row), the per-row default (support-derived default_prior unless a different default function is given).

By default every row gets a sensible support-derived prior, so build_priors(params_table(tree)) alone yields a complete prior NamedTuple. A user overrides only the parameters they care about (brms-style partial override) through priors.

row is a NamedTuple (; edge, param, value, support) (the table's columns for that row), so a custom default can pick a prior from the parameter's support.

Arguments

  • table: a params_table inventory (any Tables.jl column table with edge, param, value, support columns).

Keyword Arguments

  • priors: per-parameter overrides, either a (edge, param) => prior mapping (e.g. a Dict) or a nested NamedTuple keyed like the tree ((onset_admit = (shape = prior,),)); only the listed parameters are overridden (default: empty).

  • default: a function row -> prior for rows not overridden (default: default_prior, deriving the prior family from the parameter's support).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
tbl = params_table(tree)
# Support-derived defaults everywhere, overriding only one parameter.
nested = build_priors(tbl;
    priors = (onset_admit = (shape = truncated(Normal(2, 0.5); lower = 0),),))
nested.onset_admit.shape

See also

  • params_table: the flat inventory keyed against.

  • default_prior: the support-derived per-row default.

  • composed_parameters_model (downstream), update: consume the result.

source
ComposedDistributions.chain_to_params Function

Read a fitted chain's parameters into the nested NamedTuple update consumes.

chain_to_params(template, chain) walks template (a composed distribution, matching the tree a ~ to_submodel(...)-sampled parameters model was built against) and reads each free parameter back from chain at its dotted prefix.edge.param name, reducing multiple draws with summary (default mean). Pair with update:

julia
ready = update(template, chain_to_params(template, chain))

or call update(template, chain) directly, which does the same in one step.

Reading a chain back onto a template that still holds an Uncertain leaf collapses it to a concrete leaf at the read values (the same collapse update always performs when given concrete parameters); a Varying leaf keeps varying — only its reference's fixed values are updated, so has_varying is unchanged.

This method is available only when both DynamicPPL and FlexiChains are loaded (the method lives in a package extension).

Arguments

  • template: the composed distribution the chain's parameters were sampled against.

  • chain: the fitted FlexiChains chain to read parameter values from.

Keyword Arguments

  • prefix: the submodel variable name the parameters were sampled under (default :d).

  • summary: the reduction AbstractVector -> scalar applied to each parameter's draws (default mean).

  • draws: a subset of iterations to reduce over (a range / index vector, or a predicate over the iteration index); nothing uses every draw.

  • draw: a single iteration index to read (overrides summary/draws).

Examples

julia
using ComposedDistributions, Distributions, DynamicPPL, Turing, Random
using FlexiChains: VNChain

template = compose((onset_admit = Gamma(2.0, 1.0),))

@model function onset_admit_model()
    shape ~ truncated(Normal(2.0, 0.3); lower = 0)
    scale ~ truncated(Normal(1.0, 0.3); lower = 0)
    return (shape = shape, scale = scale)
end
@model function tree_model()
    onset_admit ~ to_submodel(onset_admit_model())
    return (onset_admit = onset_admit,)
end
@model function fit()
    d ~ to_submodel(tree_model())
    return d
end

Random.seed!(1)
chain = sample(fit(), Prior(), 100; chain_type = VNChain, progress = false)
chain_to_params(template, chain)

See also

  • param_draws: the vectorised, every-draw form.

  • update: the NamedTuple-keyed reconstruction this pairs with.

  • strip_prefix: drop the outer submodel prefix from a chain first.

source
ComposedDistributions.child_logpdf Function
julia
child_logpdf(node, x, offset, n)

A composer node's contribution to the joint log density, scoring its n-wide slice x[offset + 1 : offset + n] of the flat event vector. Part of the public composer-node extension contract, alongside child_nleaves and child_rand!; see Writing a new composer node. A univariate leaf scores the one scalar at its slot; a nested node recurses into its children, passing each its own offset.

Arguments

  • node: the composer node or leaf distribution to score.

  • x: the flat event vector being scored.

  • offset: the zero-based start index of this node's slice in x.

  • n: the slice width, child_nleaves(node).

Examples

julia
using ComposedDistributions, Distributions

node = compose((onset = Gamma(2.0, 1.0), report = Gamma(1.5, 1.0)))
n = ComposedDistributions.child_nleaves(node)
x = collect(values(rand(node)))
ComposedDistributions.child_logpdf(node, x, 0, n)

See also

source
ComposedDistributions.child_nleaves Function
julia
child_nleaves(node)

Number of flat event-vector slots a composer node occupies (one per leaf below it). Part of the public composer-node extension contract, alongside child_logpdf and child_rand!; see Writing a new composer node. A univariate leaf occupies one slot; a nested node occupies the sum of its children's widths.

Arguments

  • node: the composer node or leaf distribution whose flat slot width is read.

Examples

julia
using ComposedDistributions, Distributions

node = compose((onset = Gamma(2.0, 1.0), report = Gamma(1.5, 1.0)))
ComposedDistributions.child_nleaves(node)

See also

source
ComposedDistributions.child_rand! Function
julia
child_rand!(out, offset, rng, node)

Draw a composer node in place into its slice out[offset + 1 : offset + n] of the flat output vector, where n is child_nleaves(node). Returns nothing. Part of the public composer-node extension contract, alongside child_nleaves and child_logpdf; see Writing a new composer node. A univariate leaf writes its one slot; a nested node fills its slice by recursing into its children.

Arguments

  • out: the flat output vector to write into.

  • offset: the zero-based start index of this node's slice in out.

  • rng: the random number generator to draw from.

  • node: the composer node or leaf distribution to draw.

Examples

julia
using ComposedDistributions, Distributions, Random

node = compose((onset = Gamma(2.0, 1.0), report = Gamma(1.5, 1.0)))
out = zeros(ComposedDistributions.child_nleaves(node))
ComposedDistributions.child_rand!(out, 0, Random.default_rng(), node)
out

See also

source
ComposedDistributions.choose Function
julia
choose(alternatives::Pair...; selector) -> Choose

Build a Choose data-selected disjunction from name => dist alternatives.

Each alternative is name => dist: the alternative name (a Symbol) and its independent sub-distribution. The selector keyword names the DATA field a record carries to pick an alternative (default :kind). At least two alternatives are required and their names must be unique.

Arguments

  • alternatives: the name => dist pairs, each an independent sub-distribution (a UnivariateDistribution or a nested composer).

Keyword Arguments

  • selector: the row field name (Symbol) whose value picks an alternative (default :kind).

Examples

julia
using ComposedDistributions, Distributions

# An index case (a short delay) vs a sourced case (a longer coupled delay),
# selected by the row's `:kind` field.
d = choose(:index => Gamma(2.0, 1.0),
    :sourced => Gamma(4.0, 1.5))

# Score the alternative the data names.
logpdf(d, 3.0; kind = :index)

See also

source
ComposedDistributions.compete Function
julia
compete(outcomes::Pair...) -> Compete

Build a racing-hazard Compete node from bare name => delay outcomes: the cause-specific delays RACE, the first wins, and the winning probability of each cause is DERIVED from the hazards (cause coupled to timing).

Each outcome is name => delay (a bare delay, NO branch probability). At least two outcomes are required. To give an explicit fixed probability per outcome (a mixture where cause is independent of timing) use resolve instead.

Arguments

  • outcomes: two or more bare name => delay pairs, each giving the outcome name (a Symbol) and its cause-specific delay distribution (no branch probability).

Examples

julia
using ComposedDistributions, Distributions

node = compete(:death => Gamma(2.0, 3.0), :recover => Gamma(3.0, 2.0))
probs(node)

See also

  • Compete: the composer type

  • resolve: the fixed-probability sibling constructor ((delay, prob))

  • Distributions.probs: the derived per-cause winning probabilities

  • compose: the front-end that nests the node as a branch

source
ComposedDistributions.component_names Function
julia
component_names(d::Sequential) -> Tuple

The child names of a composed distribution.

Returns the tuple of names for a composer's direct children: the step names of a Sequential chain, the branch names of a Parallel set, or the outcome names of a Resolve node. These EDGE names key the parameter inventory, distinct from the flat EVENT names of _flat_event_names.

Examples

julia
using ComposedDistributions, Distributions

oa = LogNormal(1.5, 0.4)
ad = Gamma(2.0, 1.0)
tree = compose((onset_admit = [oa, ad],))
ComposedDistributions.component_names(tree)

See also

  • event_names: the public EDGE-name accessor

  • _flat_event_names: the flat EVENT names

source
ComposedDistributions.compose Function

Build a nested composer stack from a friendly front-end input.

compose lowers a NamedTuple, a Tables.jl table, or a nested matrix to the same Sequential / Parallel stack. It is a constructor over the composers, not a new tree type.

Arguments

  • input: the front-end to lower, one of the three forms below.

Inputs

  • NamedTuple (named, recursive): a Parallel over the named children. A child that is itself a NamedTuple nests as a Parallel, a child that is a Vector or Tuple of distributions nests as a Sequential, and a bare UnivariateDistribution is a leaf branch.

  • Tables.jl table with name and dist columns: a Parallel over the rows, the column-table equivalent of a flat NamedTuple. An optional chain column folds rows sharing a non-zero group id into a Sequential branch, and an optional compete/prob column pair folds rows sharing a non-zero compete id into a Resolve node whose prob entries are the branch probabilities (each in and summing to one per group).

  • nested Matrix of distributions: rows are Parallel branches and the columns within a row are Sequential steps. This orientation is canonical, so a one-column matrix is parallel leaf branches (one row each) and a one-row matrix is a Parallel-of-one wrapping a Sequential of the row's columns.

Contract

compose ALWAYS returns a composer, never a bare univariate leaf. A single branch stays a Parallel-of-one and a single step a one-element Sequential; the wrapper is never collapsed away. A bare leaf is used directly at the SCORING layer, where downstream helpers such as record_distributions and composed_distribution_model accept a bare UnivariateDistribution, so callers do not need compose to pass one through.

Examples

julia
using ComposedDistributions, Distributions

# A regular 2x2 grid built three ways, all equal.
nt = (r1 = [Gamma(2.0, 1.0), LogNormal(0.5, 0.4)],
    r2 = [Gamma(1.0, 1.0), Gamma(3.0, 1.0)])
table = (name = [:a, :b, :c, :d],
    dist = [Gamma(2.0, 1.0), LogNormal(0.5, 0.4),
        Gamma(1.0, 1.0), Gamma(3.0, 1.0)],
    chain = [1, 1, 2, 2])
mat = [Gamma(2.0, 1.0) LogNormal(0.5, 0.4); Gamma(1.0, 1.0) Gamma(3.0, 1.0)]
compose(nt) == compose(table) == compose(mat)

The three front-ends are chosen to build identical stacks for the same structure, as the example above shows.

See also

source
ConvolvedDistributions.convolve_distributions Function
julia
convolve_distributions(
    d::Sequential,
    series::AbstractVector{<:Real};
    interval,
    events
) -> Any

Convolve a timeseries through a composed chain's observed delay.

convolve_distributions(chain, series), where series is a numeric timeseries vector, collapses the Sequential chain to its observed total delay (observed_distribution, the convolution of the chain steps) and returns the causal discrete convolution of series with that delay's discretised PMF, truncated to the series window. With series the expected events at unit-spaced 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, driven by a composed delay rather than a bare distribution.

The result is identical to convolve_distributions(observed_distribution(chain), series): the chain is collapsed to its convolved total and then the univariate timeseries method runs.

Pass events to convolve the series to a chosen INTERIM event of the chain rather than its endpoint. A single event name returns the count series at that event; a tuple or vector of names returns a NamedTuple of series keyed by the names. The cumulative delay to an interim event is the observed collapse of the chain PREFIX up to that event (the convolution of the steps leading to it), so selecting the terminal event reproduces the plain whole-chain result. Only a plain continuous chain (every step a delay leaf, no branching) has such per-event cumulative delays; a chain with a branching step is rejected.

Arguments

  • chain: a Sequential chain, collapsed to its observed 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, so this must be 1 (the default); any other value is rejected by the underlying univariate method.

  • events: a chain event name, or a tuple/vector of names, to convolve the series to (the cumulative delay of the chain prefix up to that event). The valid names are the chain's event_names after the origin. nothing (the default) convolves to the endpoint (the whole-chain observed total).

Examples

julia
using ComposedDistributions, Distributions

chain = Sequential(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_distributions(chain, infections)

# The count series at named interim events (here the prefix to each event).
onset_to = sequential(:onset_admit => Gamma(2.0, 1.0),
    :admit_death => LogNormal(0.5, 0.4))
by_event = convolve_distributions(onset_to, infections;
    events = (:admit, :death))

See also

source
ComposedDistributions.default_prior Function
julia
default_prior(
    row
) -> Union{Distributions.Uniform{Float64}, Distributions.Normal, Distributions.Truncated{Distributions.Normal{T}, Distributions.Continuous, T1, _A, Nothing} where {T<:Real, T1<:Real, _A<:Union{Nothing, T1}}}

Pick a default prior for a parameter row, brms-style.

default_prior(row) is the per-row default build_priors uses for rows the user does not override. row is a (; edge, param, value, support) NamedTuple (a params_table row); the prior family follows the parameter's own natural domain (classified by name), not the leaf's variate support:

  • a probability parameter, support [0, 1] (a branch_probs row) -> Uniform(0, 1).

  • a scale/shape/rate-type parameter (:sigma, :scale, :shape, :rate, ...) -> truncated(Normal(value, scale); lower = 0), positive by construction even for a location-family delay (a Normal/Affine(Normal) sigma).

  • a location parameter (:mu, :location, a Uniform bound) -> Normal(value, scale), unconstrained since the location lives on the whole line even for a positive-support delay.

  • otherwise, an unmapped name falls back to the variate support: a non-negative support -> truncated(Normal(value, scale); lower = 0), else Normal(value, scale).

The spread scale defaults to max(abs(value), 1), a weakly-informative width that scales with the parameter's magnitude.

Arguments

Examples

julia
using ComposedDistributions, Distributions

# A positive scale parameter -> a positive-truncated default.
default_prior((; edge = :onset_admit, param = :scale,
    value = 1.0, support = (0.0, Inf)))

See also

  • build_priors: assembles the nested prior NamedTuple, using this as the per-row default and accepting overrides.
source
ConvolvedDistributions.difference Function
julia
difference(
    a::Sequential,
    b;
    kwargs...
) -> Difference{X, Y, AnalyticalSolver{GaussLegendre{ConvolvedDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where {X<:(Distributions.UnivariateDistribution), Y<:(Distributions.UnivariateDistribution)}

Difference of two observed total delays, Z = X - Y.

difference(a, b) accepts a Sequential chain for either operand and collapses it to its observed total delay (observed_distribution) before forming the Difference. With both operands chains, Z is the difference of the two convolved totals; a bare distribution operand is used as-is. This extends the univariate ConvolvedDistributions difference to composed stacks.

Examples

julia
using ComposedDistributions, Distributions

onset = Sequential(Gamma(2.0, 1.0), LogNormal(0.5, 0.4))
report = Sequential(Gamma(1.5, 1.0), Gamma(1.0, 2.0))
gap = difference(onset, report)

See also

source
ComposedDistributions.event Function
julia
event(d)

Fetch a composed distribution's child (event/edge), or descend a name path.

event(d, path...) returns the sub-distribution of d at the named location: a single Symbol fetches a direct child (a branch of a Parallel, a step of a Sequential, an outcome delay of a Resolve, or an alternative of a Choose); multiple Symbols, or a single dotted-path Symbol (:admit_path.admit_death, as in params_table's edge column), descend the tree one name per step. Throws an ArgumentError naming the valid children if a name along the path is not a child at that level (mirroring update/prune/splice).

Arguments

  • d: the composed distribution to look up a child of (or descend into).

  • path: one or more edge/event names (Symbols) from d down to the target, or a single dotted-path Symbol.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((admit_path = compose((onset_admit = Gamma(2.0, 1.0),
        admit_death = LogNormal(0.5, 0.4))),
    onset_recover = Gamma(3.0, 1.0)))
event(tree, :onset_recover)
event(tree, :admit_path, :admit_death)

See also

source
ComposedDistributions.event_names Function
julia
event_names(
    d::Union{ComposedDistributions.AbstractOneOf, Parallel, Sequential}
) -> Union{Tuple{Vararg{Symbol}}, Tuple{Symbol, Vararg{Any}}}

The FLAT event names of a composed distribution.

event_names(d) returns the tuple of event names in flat depth-first order: the root origin event followed by one target event per leaf edge. An inner composer's events are exposed, so compose((path = [a, b],)) lists the inner (:onset, ...) events rather than just the (:path,) edge. Event names are derived from the edge names (an edge :onset_admit gives origin :onset and target :admit); a positional default edge contributes :event_i. These EVENT names key a data ROW, distinct from the nested EDGE/child structure of event_tree (whose first level is the top-level child names).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = LogNormal(1.5, 0.4),
    admit_death = Gamma(2.0, 1.0)))
event_names(tree)

See also

source
ComposedDistributions.event_tree Function
julia
event_tree(d::Union{Parallel, Sequential}) -> NamedTuple

The NESTED tree of event names of a composed distribution.

event_tree(d) returns the event-name structure as data: a nested NamedTuple keyed by child name down to the leaves, mirroring the tree. Its FIRST level is the top-level child names (the old top-level event_names result); a Sequential/Parallel/Choose child recurses to its own nested NamedTuple, a Resolve child to its outcome names, and a leaf to its own name. Pair with event_names for the FLAT per-event layout that matches rand/mean/var.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((admit_path = compose((onset_admit = Gamma(2.0, 1.0),
        admit_death = LogNormal(0.5, 0.4))),
    onset_recover = Gamma(3.0, 1.0)))
event_tree(tree)

See also

  • event_names: the FLAT per-event names

  • event: fetch a child or subtree by name path

source
ComposedDistributions.flat_dimension Function
julia
flat_dimension(
    d::ComposedDistributions.AbstractComposedDistribution
) -> Int64

The estimated parameter dimension of a composed distribution.

flat_dimension(d) is the number of scalar ESTIMATED parameters: the count of uncertain specs across the tree, i.e. the params_table rows whose prior column carries a spec. A fixed (non-uncertain) leaf contributes nothing, so a tree with no uncertain leaves has flat dimension 0. It is the length of the flat vector flatten produces and unflatten consumes.

Arguments

  • d: a composed distribution.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((
    onset_admit = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2)),
    admit_death = LogNormal(0.5, 0.4)))
# Public but not exported; reach it by the qualified name. Only onset_admit's
# shape is uncertain, so the dimension is 1.
ComposedDistributions.flat_dimension(tree)

See also

source
ComposedDistributions.flatten Function
julia
flatten(
    d::ComposedDistributions.AbstractComposedDistribution,
    nt::NamedTuple
) -> Vector

Flatten a nested parameter NamedTuple to the estimated flat vector.

flatten(d, nt) reads nt (keyed like params(d), the shape update consumes) at each ESTIMATED params_table row (an uncertain spec's parameter) and returns those values as a Vector, in table order restricted to the spec'd rows. A fixed parameter is not read. It is the inverse of unflatten: flatten(d, unflatten(d, x)) == x.

Arguments

  • d: the composed distribution whose table fixes the order.

  • nt: a nested parameter NamedTuple keyed like params(d).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((
    onset_admit = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2)),
    admit_death = LogNormal(0.5, 0.4)))
# The estimated vector is 1-long (onset_admit.shape); round-trip it.
# Public but not exported; reach the codec by the qualified name.
nt = ComposedDistributions.unflatten(tree, [2.0])
ComposedDistributions.flatten(tree, nt)

See also

source
ComposedDistributions.free_leaf Function
julia
free_leaf(leaf) -> Any

Innermost free delay of a (possibly wrapped) leaf.

The base identity contract: a plain leaf is its own free leaf, and a Truncated peels to its untruncated inner delay (the truncation bounds are fixed structure, not free parameters). A wrapper type (censoring in CensoredDistributions, the modifiers in ModifiedDistributions) adds its own method dispatching on its own type, so a composed leaf is transparent to the prior/params interface. Pair with rewrap_leaf, which rebuilds the same wrapper around a new inner delay.

Arguments

  • leaf: the (possibly wrapped) leaf distribution to peel.

Examples

julia
using ComposedDistributions, Distributions

free_leaf(truncated(Gamma(2.0, 1.0); upper = 10.0))

See also

source

Missing docstring.

Missing docstring for ComposedDistributions.gl_integrate. Check Documenter's build log for details.

ComposedDistributions.has_uncertain Function
julia
has_uncertain(
    d::Union{ComposedDistributions.AbstractOneOf, Choose, Parallel, Sequential}
) -> Union{Missing, Bool}

Whether a composed distribution still contains an Uncertain leaf.

An Uncertain leaf delegates every Distributions method except rand to its template until it is collapsed with update(tree, params), so scoring or summarising a raw tree that still holds an Uncertain leaf SILENTLY uses the template's central values instead of the marginal — a silent wrong answer, not an error. Guard a scoring/fitting loop with this predicate:

julia
collapsed = update(tree, fitted_params)
@assert !has_uncertain(collapsed)   # catch a forgotten update before scoring
logpdf(collapsed, x)

has_uncertain walks the tree (through Sequential/Parallel/Choose/the one_of composers, and through wrapper leaves via the _uncertain_specsrouting hook so ashared/modifier-wrapped uncertain leaf is still seen) and returnstrueas soon as any leaf carries a spec; a fully collapsed tree returnsfalse.

Arguments

  • d: the composed distribution, node, or leaf to check.

Examples

julia
using ComposedDistributions, Distributions

u = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2))
tree = compose((onset_admit = u, admit_death = LogNormal(0.5, 0.4)))
has_uncertain(tree)   # an uncertain leaf remains

collapsed = update(tree, (onset_admit = (shape = 3.0, scale = 1.5),
    admit_death = (mu = 0.7, sigma = 0.5)))
has_uncertain(collapsed)   # resolved: false

See also

source
ComposedDistributions.has_varying Function
julia
has_varying(d::Varying) -> Bool

Whether a composed distribution still contains an un-resolved Varying leaf.

A Varying leaf delegates every Distributions method to its reference until the tree is resolved with instantiate(tree, ctx), so scoring or sampling a raw tree that still holds a Varying leaf SILENTLY uses the reference (e.g. the t = 0 delay) instead of the per-record value — a silent wrong answer, not an error. Guard a scoring/sampling call in a fitting loop with this predicate:

julia
resolved = instantiate(tree, Context(time = t))
@assert !has_varying(resolved)   # catch a forgotten instantiate before scoring
logpdf(resolved, x)

has_varying walks the tree and returns true as soon as any leaf is a Varying; a fully stationary or fully-instantiated tree returns false.

Arguments

  • d: the composed distribution, node, or leaf to check.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset = varying(t -> Gamma(2.0, 1.0 + 0.1t)),
    admit = LogNormal(0.5, 0.4)))
has_varying(tree)                                    # a varying leaf remains
has_varying(instantiate(tree, Context(time = 5.0)))  # resolved: false

See also

source
ComposedDistributions.inspect Function
julia
inspect(io::IO, d)

Print a composed distribution's full nested detail.

inspect(io, d) walks the same tree as show but prints each leaf's full text/plain representation (every field), so it is the opt-in companion to the compact structural show. A composer node prints its header and recurses; a leaf prints its detailed representation indented under its name. Writes to io (default stdout) and returns nothing.

Arguments

  • io: the IO stream to print to (default stdout).

  • d: the composed distribution (or bare leaf) to inspect.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
inspect(tree)

See also

source
ComposedDistributions.instantiate Function
julia
instantiate(d, _::Nothing) -> Any

Resolve a composed tree (or a leaf) against a Context.

instantiate(d, ctx) walks a composed distribution and returns the SAME tree with every Varying leaf replaced by its distribution at the context's covariate; a fixed leaf is returned unchanged (the identity default), so a stationary tree is untouched and passing nothing is always a no-op. The result is a fully concrete composer that scores, samples and convolves exactly as a hand-built stationary tree would — non-stationarity is resolved HERE, before those steps, so the convolution / renewal layer receives a concrete kernel per context.

Arguments

  • d: a composer, a leaf, or a Varying leaf.

  • ctx: a Context of covariates, or nothing (a no-op).

Examples

julia
using ComposedDistributions, Distributions

chain = sequential(:onset_admit => varying(t -> Gamma(2.0, 1.0 + 0.1t)),
    :admit_death => LogNormal(0.5, 0.4))
at_day5 = instantiate(chain, Context(time = 5.0))  # concrete, stationary chain
observed_distribution(at_day5)                     # the convolution kernel at t = 5

See also

source

Missing docstring.

Missing docstring for ComposedDistributions.integrate. Check Documenter's build log for details.

ComposedDistributions.logdensity Function
julia
logdensity(
    prob::ComposedDistributions.ComposedLogDensity,
    x::AbstractVector
) -> Any

Evaluate a ComposedLogDensity on its estimated flat parameter vector.

logdensity(prob, x) is the (unnormalised) log-posterior at the estimated flat vector x (the spec'd parameters, in params_table(prob.dist) row order): the sum of the specs' log-densities at x plus the data log-likelihood of the distribution reconstructed there (each uncertain leaf collapsed at its draw, fixed parameters held at the template). x is flat_dimension(prob.dist) long — empty for a tree with no uncertain leaves, where logdensity is just the data likelihood.

Arguments

Examples

julia
using ComposedDistributions, Distributions

tree = compose((
    onset_admit = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2)),
    admit_death = LogNormal(0.5, 0.4)))
prob = ComposedDistributions.as_logdensity(
    tree, [[0.5, 2.0], [1.0, 3.0]])
ComposedDistributions.logdensity(prob, [2.0])

See also

source
ComposedDistributions.observed_distribution Function
julia
observed_distribution(
    d::Distributions.UnivariateDistribution
) -> Distributions.UnivariateDistribution

The univariate scalar a downstream observation observes for a composer.

An observation model observes one quantity, so lowering a composer first reduces it to that quantity:

  • a Convolved or Resolve is already univariate (the observed sum, resp. the marginal time-to-resolution) and is returned unchanged;

  • a Sequential chain's observed quantity is the total elapsed time from origin to the terminal event, the convolution of its steps, returned as a Convolved.

A Parallel has several independent endpoints and so no single observed scalar; it is not lowered here.

Examples

julia
using ComposedDistributions, Distributions

seq = Sequential(Gamma(2.0, 1.0), LogNormal(0.5, 0.4))
observed_distribution(seq)

See also

source
ComposedDistributions.occurrence_probability Function
julia
occurrence_probability(c::Resolve) -> Any

The probability that ANY (non-no-event) outcome occurs for a fixed-probability Resolve node: one minus the no-event branch mass.

See also: Distributions.probs

source
julia
occurrence_probability(c::Compete) -> Any

The probability that ANY (non-no-event) outcome occurs for a one_of node.

For a racing-hazard Compete node occurrence_probability is the sum of the derived per-cause split Distributions.probs returns (one for proper, eventually-certain causes; the resolved mass for a defective node). For a fixed-probability Resolve node it is one minus the no-event branch mass.

Arguments

  • c: the Compete node whose any-event probability to read.

Examples

julia
using ComposedDistributions, Distributions

node = compete(:death => Gamma(2.0, 3.0), :recover => Gamma(3.0, 2.0))
occurrence_probability(node)

See also

  • Distributions.probs: the per-outcome winning split this sums.
source
ComposedDistributions.parallel Function
julia
parallel(branches::Pair...) -> Parallel

Compose univariate distributions into Parallel branches.

Lowercase verb mirroring sequential / resolve: the public constructor for a Parallel branch set. Pass branch distributions positionally (default names :branch_1, :branch_2, ...) or name => dist pairs to name the branches; a branch may itself be a Sequential, Resolve, Compete, Choose or nested set. Prefer this verb over the bare struct constructor.

Arguments

  • branches: the branch distributions, either as positional distributions or as name => dist pairs naming each branch.

Examples

julia
using ComposedDistributions, Distributions

d = parallel(:admit => Gamma(2.0, 1.0), :notif => LogNormal(1.0, 0.5))
event_names(d)

See also

source
ComposedDistributions.param_draws Function

Read every draw of a fitted chain into a vector of parameter NamedTuples.

param_draws(template, chain) is the vectorised form of chain_to_params: where chain_to_params reduces the draws to one NamedTuple, param_draws keeps every draw, so a per-draw distribution, trajectory, or posterior-predictive summary maps update over the result:

julia
draws = param_draws(template, chain)
update.(Ref(template), draws)

This method is available only when both DynamicPPL and FlexiChains are loaded (the method lives in a package extension).

Arguments

  • template: the composed distribution the chain's parameters were sampled against.

  • chain: the fitted FlexiChains chain to read every draw from.

Keyword Arguments

  • prefix: the submodel variable name the parameters were sampled under (default :d).

  • draws: a subset of iterations to keep (a range / index vector, or a predicate over the iteration index); nothing keeps every draw.

Examples

julia
using ComposedDistributions, Distributions, DynamicPPL, Turing, Random
using FlexiChains: VNChain

template = compose((onset_admit = Gamma(2.0, 1.0),))

@model function onset_admit_model()
    shape ~ truncated(Normal(2.0, 0.3); lower = 0)
    scale ~ truncated(Normal(1.0, 0.3); lower = 0)
    return (shape = shape, scale = scale)
end
@model function tree_model()
    onset_admit ~ to_submodel(onset_admit_model())
    return (onset_admit = onset_admit,)
end
@model function fit()
    d ~ to_submodel(tree_model())
    return d
end

Random.seed!(1)
chain = sample(fit(), Prior(), 100; chain_type = VNChain, progress = false)
draws = param_draws(template, chain)
length(draws)

See also

  • chain_to_params: the single-draw / reduced read this vectorises.

  • update: map over the result to rebuild a distribution per draw.

source
ComposedDistributions.param_priors Function
julia
param_priors(tree; kwargs...) -> NamedTuple

Build the nested prior NamedTuple straight from a composed distribution.

param_priors(tree; priors, default) is a thin convenience over build_priors(params_table(tree)): it reads the parameter inventory of the composed distribution tree and assembles the nested prior NamedTuple in one call, forwarding the same keyword surface. It adds no prior logic of its own.

The result is spec-shaped (a nested NamedTuple of distributions keyed like the tree), so it feeds update directly: update(tree, param_priors(tree)) promotes every free parameter to uncertain with its default prior — the explicit estimate-everything path under uncertain-first (a bare tree estimates nothing). Pass priors to swap in your own spec for named parameters.

Arguments

  • tree: a composed distribution from compose.

Keyword Arguments

  • priors: per-parameter overrides, either a (edge, param) => prior mapping or a nested NamedTuple keyed like the tree; only the listed parameters are overridden (default: empty).

  • default: a function row -> prior for rows not overridden (default: default_prior).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
priors = param_priors(tree)
priors.onset_admit.shape

See also

source
ComposedDistributions.params_table Function
julia
params_table(
    d::Union{ComposedDistributions.AbstractOneOf, Choose, Parallel, Sequential}
) -> ComposedDistributions.ParamsTable{@NamedTuple{edge::Vector{Symbol}, param::Vector{Symbol}, value::Vector{Any}, support::Vector{Any}, prior::Vector{Any}}}

Flatten a composed distribution's parameters into a prior-definition table.

params_table(d) returns a Tables.jl column table (a ParamsTable wrapping a NamedTuple of equal-length column vectors, so Tables.istable(params_table(d)) is true and it prints as a padded table); wrap it in DataFrame for a DataFrame. It has one row per scalar free parameter of the composed distribution d, with columns:

  • edge: the dotted path of names to the parameter's edge/leaf (e.g. :onset_admit, or :resolution.branch_probs inside a Resolve).

  • param: the parameter name (e.g. :mu, :sigma; positional :param_i where the family is unmapped).

  • value: the current parameter value.

  • support: the (minimum, maximum) variate support of that edge's distribution, the domain a prior over the edge must respect (from minimum/ maximum/support).

  • prior: the attached prior of an uncertain parameter (its spec distribution), or nothing for a fixed parameter. build_priors uses a non-nothing entry ahead of its per-row default.

Define priors against the rows of this table instead of hand-matching parameter names. Built from params (nested, name-keyed values) plus the edge distributions' support.

For a Choose node the alternatives' independent per-branch params are namespaced per alternative (index.… / sourced.…), one row-group per alternative. A parameter tied across alternatives via shared(:tag, ...) is inventoried ONCE under its tag edge and sampled once, so a value tied across the index and sourced branches appears as a single row-group.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = LogNormal(1.5, 0.4),
    admit_death = Gamma(2.0, 1.0)))
tbl = params_table(tree)
tbl.edge  # a column; wrap the table in `DataFrame(tbl)` for a DataFrame

See also

source
ComposedDistributions.prune Function
julia
prune(
    d::Union{Choose, Parallel, Resolve, Sequential},
    path::Symbol
) -> Union{Choose, Parallel, Resolve, Sequential}

Drop a branch from a composed distribution (a topology edit).

prune(d, path) removes the node addressed by path from its parent, CHANGING the tree shape. A Resolve arm is removed and the remaining branch probabilities are renormalised to sum to one; a Choose alternative or a Sequential/Parallel step is removed. The parent must keep at least the minimum number of children (two for Resolve/Choose, one for Sequential/Parallel). The result is a valid composed distribution that scores and rands. path accepts the same forms as event: varargs Symbols, a dotted Symbol, or a tuple of edge names.

prune and splice are the two topology edits (they change the tree shape); update keeps the same shape and replaces contents.

Arguments

  • d: the composed distribution to edit.

  • path: the branch to drop, as varargs Symbols, a dotted Symbol, or a tuple of edge names.

Examples

julia
using ComposedDistributions, Distributions

node = resolve(:death => (Gamma(1.5, 1.0), 0.3),
    :disch => (Gamma(2.0, 1.5), 0.5),
    :transfer => (Gamma(1.0, 1.0), 0.2))
tree = compose((resolution = node, onset = Gamma(1.0, 1.0)))
tree2 = prune(tree, :resolution, :transfer)
event_names(event(tree2, :resolution))

See also

  • splice: insert a before/after step at a node (the other topology edit)

  • update: replace a node or its values (keeps the shape)

source
ComposedDistributions.resolve Function
julia
resolve(
    outcomes::Pair...
) -> Resolve{C, D, P, Nothing} where {C<:Tuple, D<:Tuple, P<:Tuple}

Build a fixed-probability Resolve node from name => (delay, branch_prob) outcomes: exactly one outcome RESOLVES, with cause independent of timing.

Each outcome is name => (delay, branch_prob); the branch probabilities must each lie in and sum to one, and at least two outcomes are required.

The LAST outcome's probability may be OMITTED (a bare name => delay): it then takes the residual 1 - sum(of the others), so a probability that is fully determined by the rest need not be written out (and cannot disagree with them). The leading probabilities must sum to at most one. Omitting any outcome but the last, or more than one, is rejected. To omit EVERY probability (a racing-hazard node where the winning probability is derived from the hazards) use compete instead.

Arguments

  • outcomes: two or more name => (delay, branch_prob) pairs, each giving the outcome name (a Symbol), its delay distribution, and the probability that the outcome occurs. The last pair's probability may be omitted (a bare name => delay), taking the residual 1 - sum(of the others).

Examples

julia
using ComposedDistributions, Distributions

cfr = 0.3
node = resolve(:death => (Gamma(1.5, 1.0), cfr),
    :disch => (Gamma(2.0, 1.5), 1 - cfr))
mean(node)
julia
using ComposedDistributions, Distributions

# The discharge probability is the residual `1 - cfr`, so it is omitted.
cfr = 0.3
node = resolve(:death => (Gamma(1.5, 1.0), cfr),
    :disch => Gamma(2.0, 1.5))
mean(node)

See also

source
ComposedDistributions.rewrap_leaf Function
julia
rewrap_leaf(leaf, inner) -> Any

Rebuild the same wrapper around a new inner delay inner.

The inverse of free_leaf: the base identity returns inner, and a Truncated re-applies its bounds around the rebuilt inner delay. A wrapper type adds its own method on its own type, so rewrap_leaf(leaf, free_leaf_of_new) carries the fixed structure across a parameter update.

Arguments

  • leaf: the wrapped leaf whose fixed structure is re-applied.

  • inner: the new inner delay to wrap.

Examples

julia
using ComposedDistributions, Distributions

rewrap_leaf(truncated(Gamma(2.0, 1.0); upper = 10.0), Gamma(3.0, 1.5))

See also

source
ComposedDistributions.sequential Function
julia
sequential(steps::Pair...) -> Sequential

Compose univariate distributions into a Sequential chain.

Lowercase verb mirroring parallel / resolve: the public constructor for a Sequential chain. Pass step distributions positionally (default names :step_1, :step_2, ...) or name => dist pairs to name the steps; a step may itself be a Parallel, Resolve, Compete, Choose or nested chain. Prefer this verb over the bare struct constructor.

Arguments

  • steps: the step distributions, either as positional distributions or as name => dist pairs naming each step.

Examples

julia
using ComposedDistributions, Distributions

d = sequential(:onset_admit => Gamma(2.0, 1.0),
    :admit_death => LogNormal(0.5, 0.4))
event_names(d)

See also

source
ComposedDistributions.shared Function
julia
shared(
    name::Symbol,
    dist::Distributions.UnivariateDistribution
) -> Shared

Tag a leaf distribution as a shared parameter group named name.

shared(name, dist) marks dist as a tied parameter so multiple occurrences of the same name in a composed distribution are handled ONCE by the prior/params interface (inventoried, sampled and updated as a single free parameter), with the shared value placed in every occurrence. The result is transparent to scoring and sampling.

shared(name, dist) is the LEAF-LOCAL spelling of the tie, applied where the leaf is built. tie(d, paths...; name) is the TREE-LEVEL spelling of the SAME tie: it walks a composed d to the named leaves and wraps each in the exact shared(name, leaf) artefact this produces. Use whichever is convenient; the tagged occurrences are one free parameter either way.

Arguments

  • name: the shared-parameter group name (Symbol).

  • dist: the leaf distribution to tag.

Examples

julia
using ComposedDistributions, Distributions

# The same incubation `inc` tied across two branches of a `choose`.
inc = shared(:inc, Gamma(2.0, 1.0))
d = choose(:index => inc,
    :sourced => compose((src = LogNormal(0.5, 0.4), inc = inc)))
event_names(d)

See also

  • Shared: the tagged-leaf type.

  • tie: the tree-level, path-based spelling of the same tie.

source
ComposedDistributions.splice Function
julia
splice(
    d::Union{Choose, Parallel, Resolve, Sequential},
    path::Symbol;
    before,
    after
)

Splice before/after steps around a node in a composed distribution (a topology edit).

splice(d, path; before, after) replaces the node at path with a Sequential chain of before, the original node, then after (any of which may be omitted). This inserts a change-point step around the addressed node without rebuilding the rest of the tree, e.g. an extra delay before a branch or a follow-up step after it, CHANGING the tree shape. The result is a valid composed distribution that scores and rands. path accepts the same forms as event: varargs Symbols, a dotted Symbol, or a tuple of edge names.

splice and prune are the two topology edits (they change the tree shape); update keeps the same shape and replaces contents.

Arguments

  • d: the composed distribution to edit.

  • path: the node to wrap, as varargs Symbols, a dotted Symbol, or a tuple of edge names.

Keyword Arguments

  • before: a name => dist step inserted before the node (default: none).

  • after: a name => dist step inserted after the node (default: none).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
tree2 = splice(tree, :admit_death; after = :death_report => Gamma(1.0, 2.0))
event_names(event(tree2, :admit_death))

See also

  • prune: drop a branch (the other topology edit)

  • update: replace a node or its values (keeps the shape)

source
ComposedDistributions.strip_prefix Function

Drop the outer submodel prefix from a fitted chain's parameter names.

A parameter sampled through d ~ to_submodel(...) carries the submodel prefix in its chain name (e.g. d.onset_admit.shape). strip_prefix(chain) removes that one leading prefix, so chain_to_params / param_draws can read it back with prefix = Symbol("").

This method is available only when both DynamicPPL and FlexiChains are loaded (the method lives in a package extension).

Arguments

  • chain: the fitted FlexiChains chain to strip.

Keyword Arguments

  • prefix: the submodel variable name to remove (default :d).

Examples

julia
using ComposedDistributions, Distributions, DynamicPPL, Turing, Random
using FlexiChains: FlexiChains, VNChain

@model function onset_admit_model()
    shape ~ truncated(Normal(2.0, 0.3); lower = 0)
    scale ~ truncated(Normal(1.0, 0.3); lower = 0)
    return (shape = shape, scale = scale)
end
@model function tree_model()
    onset_admit ~ to_submodel(onset_admit_model())
    return (onset_admit = onset_admit,)
end
@model function fit()
    d ~ to_submodel(tree_model())
    return d
end

Random.seed!(1)
chain = sample(fit(), Prior(), 100; chain_type = VNChain, progress = false)
stripped = strip_prefix(chain)
collect(FlexiChains.parameters(stripped))

See also

source
ComposedDistributions.tie Function
julia
tie(
    d::Union{ComposedDistributions.AbstractOneOf, Choose, Parallel, Sequential},
    paths...;
    name
)

Tie leaves at named paths of a composed distribution into one shared group.

tie(d, paths...; name) walks the composed distribution d to each leaf named by paths and wraps it in a Shared group tagged name, returning the rebuilt composed distribution. This is the tree-level, path-based spelling of shared: tie(d, p1, p2; name = :inc) produces the EXACT same artefact as building d with shared(:inc, leaf) at each of those leaves, so every tag consumer (params_table, build_priors, update, a downstream composed_parameters_model) inventories, samples and updates the tied leaves as a single free parameter.

Each path takes the SAME forms event and update accept: a bare Symbol direct child, a dotted-path Symbol (:"sourced.inc", as in params_table's edge column), or a tuple of edge names from the root. Every path must resolve to a leaf (not a composer subtree), and the tied leaves must be parameter-compatible (same inner family and parameter structure), since they become one group.

Arguments

  • d: the composed distribution to tie leaves in.

  • paths: one or more leaf paths to tie together.

Keyword Arguments

  • name: the shared-parameter group name (Symbol, required).

Examples

julia
using ComposedDistributions, Distributions

d = choose(:index => compose((inc = Gamma(2.0, 1.0),)),
    :sourced => compose((src = LogNormal(0.5, 0.4), inc = Gamma(2.0, 1.0))))
tied = tie(d, (:index, :inc), (:sourced, :inc); name = :inc)
params_table(tied)

See also

  • shared: the leaf-local spelling of the same tie.

  • event, update: share the path forms tie accepts.

source
ComposedDistributions.uncertain Function
julia
uncertain(
    template::Distributions.UnivariateDistribution;
    kwargs...
)

Attach parameter uncertainty to a distribution: parameters that are themselves distributions, nestable to any depth.

uncertain has three forms:

  • uncertain(template; kwargs...) wraps a concrete template leaf so the named parameters are drawn from the given distributions rather than fixed. Each keyword is a parameter name of the template's free delay (as in params_table's param column); a distribution value makes that parameter uncertain, a Real value re-pins it to a new fixed value.

  • uncertain(Family, args...) (a type, e.g. Gamma) takes one positional argument per parameter, in the family's constructor order: a UnivariateDistribution makes that parameter uncertain, a Real fixes it. The template is the family's default instance with the Real slots pinned; the uncertain slots are driven by their specs.

  • uncertain(Family; kwargs...) is the keyword form on the family's default-constructed template; every parameter must then be given explicitly.

A spec may itself be an uncertain distribution, so hyper-uncertainty nests. The template may be a wrapped leaf (truncated(...), a censoring wrapper): the wrapper is fixed structure re-applied to every draw. Apply such wrappers INSIDE the template. truncated is the exception: applied outside it pushes itself into the template automatically.

The result is a Distributions.UnivariateDistribution and composes as a leaf everywhere (sequential, parallel, resolve, compete, choose, shared): rand draws the marginal, and update(tree, params) collapses an uncertain leaf to its concrete template. In params_table an uncertain parameter's spec rides the row's prior column, so build_priors picks it up without an explicit override.

Only rand is marginal

Every other query on the result — logpdf/cdf/quantile/... and the moments mean/var/std — silently reports the template's central values, not the marginal. Guard a scoring/fitting loop with has_uncertain before assuming a tree is fully concrete.

A template whose parameters are themselves composite (e.g. a Convolved/ Difference node from the ConvolvedDistributions interop, whose parameters are its components' own parameter tuples rather than scalars) is refused with an informative ArgumentError: attach uncertainty to an individual COMPONENT instead, either by building the composite from uncertain components or by targeting one through update at its component_i path (that interop sees through a composite leaf to its component parameters).

Arguments

  • template: the concrete (possibly wrapped) leaf distribution, or a distribution type (e.g. Gamma).

  • args...: for the positional family form, one value per parameter (a distribution for an uncertain parameter, a Real for a fixed one).

Keyword Arguments

  • kwargs...: parameter name = spec pairs. A distribution spec makes the parameter uncertain; a Real re-pins the template's fixed value.

Examples

julia
using ComposedDistributions, Distributions

# A literature-reported Gamma delay with an uncertain shape.
u = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2))
rand(u)

# The positional family form: shape uncertain, scale fixed at 1.0.
uncertain(Gamma, LogNormal(log(2.0), 0.2), 1.0)

# Nested: the shape's prior location is itself uncertain.
uncertain(Gamma(2.0, 1.0);
    shape = uncertain(LogNormal(log(2.0), 0.2); mu = Normal(log(2.0), 0.1)))

See also

  • Uncertain: the wrapper type.

  • update: collapse an uncertain leaf to a concrete distribution.

source
ComposedDistributions.unflatten Function
julia
unflatten(
    d::ComposedDistributions.AbstractComposedDistribution,
    x::AbstractVector
) -> NamedTuple

Rebuild the full nested parameter NamedTuple from an estimated flat vector.

unflatten(d, x) maps the estimated flat vector x (the spec'd parameters, e.g. a draw from a sampler) back to the full nested NamedTuple update consumes: each estimated parameter takes its value from x, each fixed parameter its template value. It is the inverse of flatten, so update(d, unflatten(d, x)) collapses every uncertain leaf at the draw while holding the fixed parameters at the template.

Arguments

  • d: the composed distribution whose table fixes the layout.

  • x: an estimated flat vector of length flat_dimension(d).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((
    onset_admit = uncertain(Gamma(2.0, 1.0); shape = LogNormal(log(2.0), 0.2)),
    admit_death = LogNormal(0.5, 0.4)))
# One estimated parameter (onset_admit.shape); the rest stay at the template.
# Public but not exported; reach it by the qualified name.
update(tree, ComposedDistributions.unflatten(tree, [3.0]))

See also

  • flatten: the inverse, nested NamedTuple -> flat vector.

  • update: rebuild the distribution from the result.

source
ComposedDistributions.update Function

Update a composed distribution's parameters, replace named nodes, or read parameters from a fitted chain — the single verb for every shape-preserving edit, dispatching on the second argument.

  • a nested NamedTuple of parameter values/specs (below): fixes or re-specs free parameters, the fine-grained value edit;

  • one or more path => new_node pairs (update(d, edits::Pair...) in intervene.jl): replaces whole nodes, coarser than a value edit but still SAME-shape;

  • a fitted DynamicPPL/FlexiChains chain (extension-only, in ComposedDistributionsFlexiChainsExt): reads posterior parameter values straight into the template.

For topology edits that change the tree SHAPE, use prune or splice instead.

update(d, params::NamedTuple) — set free parameters

update(d, params) returns a new distribution of the SAME structure as d with its parameters set from params, a nested NamedTuple mirroring the tree: a Sequential/Parallel is keyed by its edge names, a leaf by its parameter names (as in params_table's param column), and a Resolve by its outcome names plus an optional branch_probs entry. A censored leaf is transparent: supply only the inner delay's parameters and the censoring is carried through.

The value type at a leaf parameter decides what happens (the object-level spelling of "distribution in the slot = estimate, value = fix"):

  • a Real pins the parameter to that fixed value, collapsing any uncertain spec on it. A NamedTuple of all-Real values replaces every free parameter (each key required), the plain concrete update;

  • a distribution makes the parameter uncertain with that spec. Passing distributions switches to a partial update: only the named parameters change (an absent parameter keeps its current spec or fixed value), so update(tree, (onset = (shape = LogNormal(log(2), 0.2),),)) makes just onset's shape uncertain. Promote a whole tree to uncertainty over its free parameters with default priors via update(tree, param_priors(tree)) — the explicit estimate-everything path.

A Resolve node's branch_probs are a node-level parameter, not a leaf: attach a simplex-valued Distributions.Dirichlet at the branch_probs slot to make them uncertain, update(node, (branch_probs = Dirichlet(ones(K)),)). The Dirichlet is the prior you WRITE; the codec ESTIMATES the node through the Dirichlet's K-1 stick-breaking coordinates (labelled :stick_1 … :stick_{K-1} in params_table and a fitted chain), each a Beta in (0, 1), so every draw lands on the probability simplex and the gradient is well-defined. The probabilities are RECOVERED from any draw: a strict update from the stick coordinates (as read back from a chain) collapses the node to concrete probabilities summing to one (read them with Distributions.probs). Promote attaches a flat Dirichlet(ones(K)) per Resolve.

Pair with chain_to_params to read posterior means or a single draw from a fitted chain into the right NamedTuple, so update(template, means) returns a ready-to-rand/inspect distribution — or call update(template, chain) directly (below) once DynamicPPL and FlexiChains are loaded.

Arguments

  • d: the composed distribution (or bare leaf) to update.

  • params: a nested NamedTuple keyed like d, each leaf value a Real (fix) or a UnivariateDistribution (make uncertain).

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
# Concrete values pin the parameters.
tree2 = update(tree, (onset_admit = (shape = 3.0, scale = 1.5),
    admit_death = (mu = 0.7, sigma = 0.5)))
event(tree2, :onset_admit)
# A distribution makes just that parameter uncertain (a partial update).
est = update(tree, (onset_admit = (shape = LogNormal(log(2.0), 0.2),),))
has_uncertain(est)

update(d, path => new_node, ...) — replace nodes

update(d, path => new_node, ...) returns a new composed distribution of the SAME outer structure as d with the node addressed by each path replaced by new_node. A path is a Symbol (a top-level child), a dotted Symbol (:admit_path.admit_resolution.death, as in event / params_table), or a tuple of edge names from the root (e.g. (:admit_path, :admit_resolution, :death)); the same address event READS is the one this WRITES. new_node may be a leaf distribution or a nested composer. This shares the recursive reconstruction with the value-update form above, so the result scores and rands. It preserves the tree SHAPE; for shape changes use prune or splice.

Arguments

  • d: the composed distribution to edit.

  • edits: one or more path => new_node pairs.

Examples

julia
using ComposedDistributions, Distributions

tree = compose((onset_admit = Gamma(2.0, 1.0),
    admit_death = LogNormal(0.5, 0.4)))
tree2 = update(tree, :admit_death => Gamma(3.0, 1.5))
event(tree2, :admit_death)

update(template, chain) — read from a fitted chain

Available only when both DynamicPPL and FlexiChains are loaded. Reads chain (sampled through a ~ to_submodel(...)-based parameters model) into the nested NamedTuple and rebuilds template with those values, so the workflow is one call instead of update(template, chain_to_params(template, chain)). By default it reduces each parameter's draws with mean; pass any summary reduction, restrict to a subset of draws with draws (a range / index vector, or a predicate over the iteration index), or pass draw=i for a single iteration. The prefix keyword names the submodel variable the parameters were sampled under (default :d).

Arguments

  • template: the composed distribution the chain's parameters were sampled against.

  • chain: the fitted FlexiChains chain to read parameter values from.

Keyword Arguments

  • prefix: the submodel variable name the parameters were sampled under (default :d).

  • summary: the reduction AbstractVector -> scalar applied to each parameter's draws (default mean).

  • draws: a subset of iterations to reduce over (a range / index vector, or a predicate over the iteration index); nothing uses every draw.

  • draw: a single iteration index to read (overrides summary/draws).

See also

source
ComposedDistributions.varying Function
julia
varying(f; covariate, reference) -> Varying

Build a Varying context-indexed leaf.

varying(f; covariate = :time, reference = f(0.0)) wraps a map f (a covariate value to a UnivariateDistribution) as a leaf that varies with the named covariate. The reference distribution is used when the leaf is queried without a context; it defaults to f(0.0) (the map at the origin), which suits a :time covariate — pass an explicit reference for a categorical covariate where f(0.0) is not meaningful.

Arguments

  • f: map from a covariate value to a UnivariateDistribution.

Keyword Arguments

  • covariate: the Context field name to read (default :time).

  • reference: the distribution used without a context (default f(0.0)).

Examples

julia
using ComposedDistributions, Distributions

# An onset->admit delay whose mean shortens over calendar time.
d = varying(t -> Gamma(2.0, 1.0 + 0.1 * t); covariate = :time)
mean(d)                                   # the reference (t = 0)
mean(instantiate(d, Context(time = 5.0))) # the delay at t = 5

See also

source
ComposedDistributions.with_covariates Function
julia
with_covariates(ctx::Context; covariates...) -> Context

Add or override covariates on a Context, returning a new context.

with_covariates(ctx; kwargs...) is how the sampling layer of the uncertain distributions work threads its LATENT index into the same covariate channel an OBSERVED covariate uses: starting from a per-record observed context (calendar time, region), it adds the parameter values it has sampled (with_covariates(ctx; inc_shape = θ)), and a Varying leaf keyed on that name resolves against them exactly as a time-varying leaf resolves against time. Observed and latent indices are the same covariate channel; the only difference is who fills the slot — the data, or the sampler. Later keys win over earlier ones.

Arguments

Keyword Arguments

  • covariates...: covariate name = value pairs to add or override.

Examples

julia
using ComposedDistributions

base = Context(time = 4.0)                       # observed covariates
drawn = with_covariates(base; inc_shape = 2.3)   # sampler adds a latent param
(drawn.covariates.time, drawn.covariates.inc_shape)

See also

source