Skip to content

Public Documentation

Documentation for ModifiedDistributions's public interface.

ModifiedDistributions.ModifiedDistributions Module
julia
ModifiedDistributions

Unary modifiers that wrap exactly one UnivariateDistribution from Distributions.jl: an affine transform (affine), a likelihood weight (weight), and forward-series transforms (thin / cumulative). Also owns the generic get_dist unwrap protocol.

When ComposedDistributions.jl is loaded, a package extension additionally lets the modifier verbs apply across a composed Sequential chain by modifying the univariate scalar the chain observes (its convolved total).

Examples

julia
using ModifiedDistributions, Distributions

d = affine(LogNormal(1.5, 0.5); scale = 2.0, shift = 1.0)
wd = weight(d, 10.0)
get_dist(wd) === d
source

Contents

Index

Public API

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

Supertype of the single-base modifier leaves that wrap one inner distribution and modify it: Affine, Weighted, Transformed, Modified. CensoredDistributions' TimeChange and Shared leaves stay upstream until the migration (CensoredDistributions#343) lands. Parametric on variate form for symmetry with the upstream hierarchy.

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

  • an inner base reachable as .dist (the default show accessor; override ModifiedDistributions._modified_inner if stored elsewhere) and via get_dist;

  • the univariate interface (pdf / logpdf / cdf / quantile / minimum / maximum / insupport / params), forwarded or specialised;

  • optionally Base.show; the default below prints Name(inner).

The free_leaf / rewrap_leaf round-trip verbs are ComposedDistributions.jl's generics, so they are not part of this package's contract. Their methods for modifier leaves live in this package's own ModifiedDistributionsComposedDistributionsExt, which loads automatically when ComposedDistributions.jl is present.

Verify a subtype with ModifiedDistributions.TestUtils.test_modified_interface.


Fields

source
ModifiedDistributions.Affine Type
julia
struct Affine{D<:(Distributions.UnivariateDistribution), T<:Real, S<:Distributions.ValueSupport} <: ModifiedDistributions.AbstractModifiedDistribution{Distributions.Univariate, S<:Distributions.ValueSupport}

The distribution of a deterministic affine transform Y = scale * X + shift of an inner distribution X, with scale > 0 and any real shift.

For a continuous inner distribution, computed by the change-of-variables for a strictly increasing affine map: with x = (y - shift) / scale,

For a discrete inner distribution, the probability mass moves to the rescaled lattice without the Jacobian term: P(Y = y) = P(X = (y - shift) / scale).

Affine is a UnivariateDistribution with the value support of the inner distribution, so it works anywhere a distribution is expected.

See also


Fields

  • dist::Distributions.UnivariateDistribution: The inner distribution being transformed.

  • scale::Real: The positive multiplicative scale.

  • shift::Real: The additive shift.

source
ModifiedDistributions.CumulativeOp Type
julia
struct CumulativeOp

The forward op carried by cumulative: accumulate a downstream count series with a running sum.

See also


Fields

source
ModifiedDistributions.HazardLink Type
julia
struct HazardLink{G, GI}

A link for the hazard modification carried by a Modified distribution.

The modification acts on the hazard through the link g,

so log gives proportional hazards and identity gives additive hazards. A HazardLink pairs the link g with its inverse invlink (g⁻¹); the three named links (LogLink, IdentityLink, LogitLink) are built-in, and any invertible callable can be wrapped with hazard_link. The log and identity links have analytic forms; a general link takes the numeric cumulative-hazard path, enabled by loading a quadrature backend (using QuadGK).

See also


Fields

  • g::Any: The link g mapping a hazard onto the modification scale.

  • invlink::Any: The inverse link g⁻¹ mapping back to a hazard.

source
ModifiedDistributions.IdentityLink Constant
julia
IdentityLink

The identity link (additive hazards): g = g⁻¹ = identity.

IdentityLink adds to the cumulative hazard from the support minimum m,   , the additive-hazards form. A non-negative effect uses that closed form; a negative effect can push the hazard below zero, so the model is the clamped hazard    and the survival is reconstructed exactly from the base's cumulative hazard between the clamp knots (no quadrature). A finite lower support bound m is required either way (see modify).

Examples

julia
using ModifiedDistributions, Distributions

# Additive-hazards modification of an Exponential delay.
modify(Exponential(1.0), 0.5; link = ModifiedDistributions.IdentityLink)

See also

source
ModifiedDistributions.LogLink Constant
julia
LogLink

The log link (proportional hazards): g = log, g⁻¹ = exp.

LogLink scales the survival function,  , the proportional-hazards form, and is the default link of modify.

Examples

julia
using ModifiedDistributions, Distributions

# Proportional-hazards modification of an Exponential delay.
modify(Exponential(1.0), 0.5; link = ModifiedDistributions.LogLink)

See also

source
ModifiedDistributions.LogitLink Constant
julia
LogitLink

The logit link (discrete-time reporting hazard): g = logit, g⁻¹ = logistic.

LogitLink pairs the logit with its logistic inverse, the link for a discrete-time reporting hazard on a discrete base with a per-bin effect vector, where each bin's hazard is a probability in (0, 1). On a continuous base the hazard is a rate that can exceed one, where the logit is not meaningful; the rate links LogLink and IdentityLink (or a custom hazard_link) are the continuous-base choices.

Examples

julia
using ModifiedDistributions, Distributions

# A discrete-time reporting-hazard modification through LogitLink: a per-bin
# effect vector reshapes a discrete delay's hazard.
grid = collect(0:4)
base = DiscreteNonParametric(grid, fill(0.2, 5))
modify(base, fill(0.3, 5); link = ModifiedDistributions.LogitLink)

See also

source
ModifiedDistributions.Modified Type
julia
struct Modified{D<:(Distributions.UnivariateDistribution), E, L<:ModifiedDistributions.HazardLink, S<:Distributions.ValueSupport} <: ModifiedDistributions.AbstractModifiedDistribution{Distributions.Univariate, S<:Distributions.ValueSupport}

A distribution whose hazard is modified through a link.

Modified carries a base distribution dist, a hazard effect and a HazardLink link, and lazily instantiates the modified hazard

in logpdf/cdf/ccdf/rand, where g is the link and h(t) = f(t)/S(t) the base hazard. The modification is never materialised eagerly, so a Modified composes with everything that consumes a UnivariateDistribution.

The effect is a scalar, a callable effect(t), or a per-bin AbstractVector, and the evaluation path is chosen by dispatch on the base and the link:

  • continuous base, LogLink with a scalar effect: analytic proportional hazards,  ;

  • continuous base, IdentityLink with a scalar effect and a finite lower support bound m: analytic additive hazards. A non-negative effect uses   ; a negative effect uses the clamped hazard   , whose cumulative hazard is summed exactly from the base's own cumulative hazard between the clamp knots (no quadrature);

  • discrete base, per-bin vector effect: exact per-bin PMF reconstruction through the discrete-time reporting hazard, for any link;

  • continuous base, callable effect(t) (any link) or a scalar effect under a general link: the modified cumulative hazard     has no closed form and takes the numeric path, evaluated by quadrature. The Modified constructs freely, but evaluating it needs a quadrature backend loaded (using QuadGK, supplied by ModifiedDistributionsQuadGKExt); without one it throws an ArgumentError pointing at the backend.

Every link works on a discrete base through the per-bin reconstruction.

Fields

  • dist: the base distribution whose hazard is modified.

  • effect: the hazard modification (a scalar, a callable effect(t), or a per-bin vector for a discrete base).

  • link: the hazard link g and its inverse.

See also


Fields

  • dist::Distributions.UnivariateDistribution: The base distribution whose hazard is modified.

  • effect::Any: The hazard modification effect (a scalar, a callable effect(t), or a per-bin vector for a discrete base).

  • link::ModifiedDistributions.HazardLink: The hazard link g and its inverse.

source
ModifiedDistributions.ThinOp Type
julia
struct ThinOp{T<:Real}

The forward op carried by thin: multiply a downstream count series by a fixed factor (thinning / rescaling of expected counts). factor is the public field, so downstream packages can dispatch on Transformed{D, <:ThinOp} and read or rebuild the factor.

See also

  • thin: the constructor verb.

Fields

  • factor::Real: The fixed multiplicative factor applied to the series.
source
ModifiedDistributions.Transformed Type
julia
struct Transformed{D<:(Distributions.UnivariateDistribution), Op, S<:Distributions.ValueSupport} <: ModifiedDistributions.AbstractModifiedDistribution{Distributions.Univariate, S<:Distributions.ValueSupport}

A distribution carrying a forward-transform op, intended for a count series a downstream convolution layer produces. Transparent to logpdf and to every other distribution method (they delegate to the inner distribution). Construct with the generic series_transform or the specialised thin / cumulative.

See also


Fields

  • dist::Distributions.UnivariateDistribution: The inner distribution.

  • op::Any: The forward op applied to a convolved series.

source
ModifiedDistributions.Weighted Type
julia
struct Weighted{D<:(Distributions.UnivariateDistribution), T<:Union{Missing, Real}, S<:Distributions.ValueSupport} <: ModifiedDistributions.AbstractModifiedDistribution{Distributions.Univariate, S<:Distributions.ValueSupport}

A distribution wrapper that applies a weight to the log-probability of an underlying distribution. This is primarily used where observations have associated counts or weights.

Only the logpdf method is affected by the weight - all other methods (pdf, cdf, sampling, etc.) delegate directly to the underlying distribution.

Weight Types Supported

The Weighted struct supports three different weight scenarios: 2. Real weights: Constructor weight is a specific value (e.g., 2.5)

  1. Missing weights: Constructor weight is missing, allowing weights to be provided at observation time via joint observations (value = x, weight = w)

  2. Zero weights: Handled specially to return -Inf and avoid NaN from 0 * -Inf

Examples

julia
using ModifiedDistributions, Distributions

# Single weighted observation
d = LogNormal(1.5, 0.5)
wd = weight(d, 10.0)  # Observation with weight/count of 10

# Weighted log-probability calculation
observed_value = 2.0
weighted_logpdf = logpdf(wd, observed_value)

# Compare with manual calculation
manual_logpdf = 10.0 * logpdf(d, observed_value)
# weighted_logpdf ≈ manual_logpdf

Fields

  • dist::Distributions.UnivariateDistribution: The underlying distribution being weighted.

  • weight::Union{Missing, Real}: The weight to apply to log-probabilities.

source
ModifiedDistributions.affine Function
julia
affine(
    dist::Distributions.UnivariateDistribution;
    scale,
    shift
) -> ModifiedDistributions.Affine{D, Float64} where D<:(Distributions.UnivariateDistribution)

Create an affine-transformed distribution Y = scale * X + shift.

Arguments

  • dist: the inner distribution X.

Keyword Arguments

  • scale: positive multiplicative factor (default 1).

  • shift: additive offset (default 0).

Examples

julia
using ModifiedDistributions, Distributions

d = affine(LogNormal(1.5, 0.5); scale = 2.0, shift = 1.0)
logpdf(d, 5.0)

See also

source
ModifiedDistributions.apply_hazard_effects Function
julia
apply_hazard_effects(
    pmf::AbstractVector,
    effects::AbstractVector
) -> Any

Modify a delay PMF through its discrete-time hazard with additive logit effects.

apply_hazard_effects(pmf, effects) reshapes a baseline delay pmf by adding effects to its hazard on the logit scale and reconstructing the PMF,

the epinowcast logit-hazard model: a positive effect speeds reporting at that delay and the returned PMF is the modified per-reference-date delay distribution. The maximum-delay hazard stays one, so sums to one.

The map is logit -> add -> logistic -> reconstruct, all AD-safe arithmetic, so Dual/tracked effects differentiate through.

Arguments

  • pmf: the baseline delay PMF over the grid 0:D.

  • effects: the additive logit-hazard effects , one per delay, same length as pmf. Use zeros for no modification.

Examples

julia
using ModifiedDistributions

pmf = [0.2, 0.3, 0.3, 0.2]
# A positive early-delay effect speeds reporting at short delays.
effects = [0.8, 0.4, 0.0, 0.0]
ModifiedDistributions.apply_hazard_effects(pmf, effects)

See also

source
ModifiedDistributions.cumulative Function
julia
cumulative(
    dist::Distributions.UnivariateDistribution
) -> ModifiedDistributions.Transformed{D, ModifiedDistributions.CumulativeOp} where D<:(Distributions.UnivariateDistribution)

Accumulate a distribution's forward count series.

cumulative(d) is series_transform with a running-sum op intended for a downstream count series, giving cumulative counts (cumulative incidence, cumulative deaths). Transparent to logpdf. Under the ConvolvedDistributions extension the carried op applies to the convolved count series.

Arguments

  • d: the inner distribution.

Examples

julia
using ModifiedDistributions, Distributions

d = cumulative(Gamma(2.0, 1.0))
logpdf(d, 2.0) == logpdf(Gamma(2.0, 1.0), 2.0)

See also

source
ModifiedDistributions.delay_hazard Function
julia
delay_hazard(pmf::AbstractVector) -> Any

Discrete-time reporting hazard of a delay PMF.

delay_hazard(pmf) converts a delay probability-mass vector pmf (the probability of report at each delay  ) to the discrete-time hazard vector ,

the conditional probability of report at delay given no report by delay  . The final hazard is clamped to one ( ) so a PMF that does not sum to one over the truncated grid is treated as fully reported by the maximum delay.

The reduction is a cumulative sum and a divide, seeded from the input element type, so Dual/tracked numbers propagate and the hazard differentiates under AD.

Arguments

  • pmf: the delay PMF over the grid 0:D.

Examples

julia
using ModifiedDistributions

pmf = [0.2, 0.3, 0.3, 0.2]
ModifiedDistributions.delay_hazard(pmf)

See also

source
ModifiedDistributions.effective_intensity Function
julia
effective_intensity(tree, path::Tuple) -> Any

Return the effective intensity of a declared factor within a composed tree.

The node at path's declared intensity, scaled by the probability its active period is reached and by the fraction of its kernel mass surviving the competing components above it in the tree. Equivalent to hand-integrating the component-resolved sub-density, but read straight off the tree. Needs ComposedDistributions.jl loaded to descend a non-empty path; an empty path reads tree itself, needing no tree machinery.

A Resolve/Compete ancestor discounts the reach by its branch probability. A Sequential/Parallel/Choose ancestor passes straight through with no discount. Every Sequential/Parallel child always executes, and a Choose alternative is picked by the data rather than a modelled probability. Do not sum effective_intensity across a Choose node's alternatives to get a combined intensity: only one alternative applies per record, so a caller summing over them double-counts.

Arguments

  • tree: the composed tree (or a bare node) to read.

  • path: a tuple of edge names, the same form update/ prune/splice accept, from tree down to the node whose factor to read.

Examples

julia
using ModifiedDistributions, Distributions

node = thin(Gamma(2.0, 1.0), 0.3)
effective_intensity(node, ())

See also

  • intensity: the plain declared-factor reader (no tree context).
source
ModifiedDistributions.get_dist Function
julia
get_dist(d) -> Distributions.UnivariateDistribution

Extract the underlying distribution from a wrapped distribution type.

This protocol provides a consistent interface for extracting the core distribution from the modifier wrappers in this package (and any downstream wrapper that adds a method). For unwrapped distributions, it returns the distribution unchanged.

Arguments

  • d: A distribution or wrapped distribution.

Returns

The underlying distribution. For base distributions, returns d unchanged.

Examples

julia
using ModifiedDistributions, Distributions

# Base distribution - returns unchanged
d1 = Normal(0, 1)
get_dist(d1)

# Affine-transformed distribution
d2 = affine(LogNormal(1.5, 0.5); scale = 2.0)
get_dist(d2)
source
julia
get_dist(
    d::ModifiedDistributions.Affine
) -> Distributions.UnivariateDistribution

Extract the underlying distribution from an affine-transformed distribution.

Returns the inner distribution before the affine transform was applied.

source
julia
get_dist(
    d::ModifiedDistributions.Weighted
) -> Distributions.UnivariateDistribution

Extract the underlying distribution from a weighted distribution.

Returns the base distribution before weighting was applied.

source
julia
get_dist(
    d::ModifiedDistributions.Transformed
) -> Distributions.UnivariateDistribution

Extract the underlying distribution from a forward-transformed distribution.

Returns the inner distribution before the forward-transform op was attached.

source
julia
get_dist(
    d::ModifiedDistributions.Modified
) -> Distributions.UnivariateDistribution

Extract the underlying distribution from a hazard-modified distribution.

Returns the base distribution before the hazard modification was applied.

source
julia
get_dist(
    d::Distributions.Product
) -> AbstractVector{T} where {S<:Distributions.ValueSupport, T<:Distributions.UnivariateDistribution{S}}

Extract the component distributions from a product distribution.

Returns a vector containing the underlying distribution of each component, so get_dist_recursive can unwrap vectorised forms such as weight(dist, weights).

Note

Unlike the other get_dist methods this returns a vector of distributions rather than a single distribution.

source
ModifiedDistributions.get_dist_recursive Function
julia
get_dist_recursive(d) -> Any

Recursively extract the underlying distribution from nested wrapper types.

This function keeps applying get_dist until it reaches a distribution that doesn't have a specialised method, meaning no further unwrapping is possible.

Arguments

  • d: A distribution or nested wrapped distribution.

Returns

The deeply underlying distribution after all unwrapping is complete.

Examples

julia
using ModifiedDistributions, Distributions

# Single wrapper - same as get_dist
wd = weight(LogNormal(1.5, 0.75), 2.0)
get_dist_recursive(wd)

# Nested wrappers
nested = weight(affine(Normal(0, 1); scale = 2.0), 3.0)
get_dist_recursive(nested)

# Base distribution - returns unchanged
get_dist_recursive(Normal(0, 1))

Note

For a wrapper that unwraps to a vector of components, this function applies recursive extraction to each component, potentially returning mixed types of underlying distributions.

source
ModifiedDistributions.get_effect Function
julia
get_effect(d::ModifiedDistributions.Modified) -> Any

Return the hazard effect of a Modified distribution.

The hazard modification on the link scale (see modify). It is a scalar, a callable effect(t), or a per-bin vector for a discrete base, returned as stored.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = modify(LogNormal(1.5, 0.5), -log(2.0); link = log)
get_effect(d)

See also

source
ModifiedDistributions.get_factor Function
julia
get_factor(op::ModifiedDistributions.ThinOp) -> Real

Return the multiplicative factor of a ThinOp.

The fixed factor a thin op multiplies into a count series. Combine with get_op to read a Transformed's thinning factor without reaching struct fields.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = thin(LogNormal(1.5, 0.5), 0.3)
get_factor(get_op(d))

See also

source
ModifiedDistributions.get_link Function
julia
get_link(
    d::ModifiedDistributions.Modified
) -> ModifiedDistributions.HazardLink

Return the hazard link of a Modified distribution.

The HazardLink pairing the link g with its inverse (see modify).

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = modify(LogNormal(1.5, 0.5), 0.2; link = identity)
get_link(d)

See also

source
ModifiedDistributions.get_op Function
julia
get_op(d::ModifiedDistributions.Transformed) -> Any

Return the forward op of a Transformed distribution.

The op applied to a downstream count series — a ThinOp, a CumulativeOp, or any callable series -> series (see series_transform).

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = thin(LogNormal(1.5, 0.5), 0.3)
get_op(d)

See also

source
ModifiedDistributions.get_scale Function
julia
get_scale(d::ModifiedDistributions.Affine) -> Real

Return the multiplicative scale of an Affine distribution.

The positive factor scale in Y = scale * X + shift.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = affine(LogNormal(1.5, 0.5); scale = 2.0, shift = 1.0)
get_scale(d)

See also

source
ModifiedDistributions.get_shift Function
julia
get_shift(d::ModifiedDistributions.Affine) -> Real

Return the additive shift of an Affine distribution.

The offset shift in Y = scale * X + shift.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = affine(LogNormal(1.5, 0.5); scale = 2.0, shift = 1.0)
get_shift(d)

See also

source
ModifiedDistributions.get_weight Function
julia
get_weight(
    d::ModifiedDistributions.Weighted
) -> Union{Missing, Real}

Return the likelihood weight of a Weighted distribution.

The weight the wrapper applies to logpdf. It is a real value, or missing when the weight is supplied at observation time (see weight).

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = weight(Normal(2.0, 1.0), 10.0)
get_weight(d)
source
ModifiedDistributions.hazard_link Function
julia
hazard_link(g, invlink) -> ModifiedDistributions.HazardLink

Wrap a link and its inverse as a HazardLink.

The link g maps a hazard onto the scale the additive effect acts on, and invlink maps back. Use the built-in LogLink or IdentityLink for the analytic choices; this constructor is for a user-supplied invertible callable. A general link takes the numeric cumulative-hazard path, so modify with one needs a quadrature backend (using QuadGK) to evaluate.

On a continuous base the hazard is a rate in [0, ∞), so g must accept that whole range: a rate link (like log) works, but a probability link whose domain is (0, 1) (logit, cloglog) errors where the base hazard exceeds one. The cloglog example below is a valid rate transform only on a base whose hazard stays below one.

Arguments

  • g: the link function g.

  • invlink: the inverse link g⁻¹.

Examples

julia
using ModifiedDistributions

# A complementary-log-log link.
cloglog = ModifiedDistributions.hazard_link(
    h -> log(-log1p(-h)), x -> -expm1(-exp(x)))

See also

  • modify: the verb that consumes a link.
source
ModifiedDistributions.hazard_to_pmf Function
julia
hazard_to_pmf(h::AbstractVector) -> Any

Delay PMF reconstructed from a discrete-time hazard.

hazard_to_pmf(h) is the inverse of delay_hazard: given a hazard vector over delays it returns the report-probability PMF,

With   the returned PMF sums to one. The reduction carries a running survival term, seeded from the input element type, so Dual/tracked hazards propagate under AD.

Arguments

  • h: the discrete-time hazard over the grid 0:D, each entry in .

Examples

julia
using ModifiedDistributions

pmf = [0.2, 0.3, 0.3, 0.2]
h = ModifiedDistributions.delay_hazard(pmf)
ModifiedDistributions.hazard_to_pmf(h)

See also

source
ModifiedDistributions.intensity Function
julia
intensity(d::ModifiedDistributions.Transformed) -> Real

Return the declared intensity (expected-count factor) a thin node carries.

The same factor get_factor(get_op(d)) reads, under a name of its own so "declared" is a first-class idea, distinguishable from effective_intensity's derived quantity. Errors clearly for any node with no declared factor (a plain distribution, or a Transformed carrying a CumulativeOp or a bare callable op).

Arguments

Examples

julia
using ModifiedDistributions, Distributions

node = thin(Gamma(2.0, 1.0), 0.3)
intensity(node)

See also

source
ModifiedDistributions.is_defective Function
julia
is_defective(d::ModifiedDistributions.Modified) -> Any

Report whether a Modified law is sub-stochastic (defective).

true when total_mass(d) < 1.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = modify(Exponential(1.0), -0.5; link = ModifiedDistributions.IdentityLink)
is_defective(d)

See also

source
ModifiedDistributions.modify Function
julia
modify(
    dist::Distributions.UnivariateDistribution,
    effect;
    link
) -> Distributions.UnivariateDistribution

Modify the hazard of a distribution through a link.

modify(d, effect; link = log) returns a Modified distribution whose hazard is   , where g is the link (log for proportional hazards, identity for additive hazards). The modification is instantiated lazily, so the result composes everywhere a UnivariateDistribution does.

The effect widens beyond a scalar: it is a scalar, a callable effect(t), or a per-bin AbstractVector (a time-varying hazard). The evaluation path is chosen by dispatch:

  • a scalar effect on a continuous base with the log link (or the identity link) uses a closed form. The identity link accepts a negative effect too, modelling the clamped hazard   whose survival is reconstructed exactly from the base cumulative hazard (no quadrature); it needs a base with a finite lower support bound m;

  • a per-bin vector effect requires a discrete base and reshapes each delay bin's reporting hazard on the link scale, reconstructing the PMF exactly, for any link (including :logit or a user callable);

  • a callable effect(t) on a continuous base (any link), or a scalar effect under a general link, is time-varying and takes the numeric cumulative-hazard path. It constructs freely, but evaluating it needs a quadrature backend loaded (using QuadGK); without one it throws an ArgumentError naming the backend.

A general link (a custom hazard_link) on a continuous base takes the same numeric path. The :logit link is a probability link for a discrete base; on a continuous base, whose hazard is a rate that can exceed one, use a rate link (log, identity, or a custom hazard_link).

Arguments

  • d: the base distribution (continuous for a scalar/callable effect, discrete for a per-bin vector effect).

  • effect: the hazard modification — a scalar, a callable effect(t), or a per-bin vector on a discrete base.

Keyword Arguments

  • link: the hazard link. The functions log (default) and identity, the symbols :log/:identity/:logit, or a HazardLink.

Examples

julia
using ModifiedDistributions, Distributions

# Proportional hazards: halve the hazard of a LogNormal delay.
d = modify(LogNormal(1.5, 0.5), -log(2.0); link = log)
ccdf(d, 2.0)

# Additive hazards: a constant extra hazard (a negative effect is allowed too).
da = modify(LogNormal(1.5, 0.5), 0.2; link = identity)
cdf(da, 2.0)

# Discrete-time reporting hazard: a per-bin effect vector on a discrete delay.
grid = collect(0:4)
base = DiscreteNonParametric(grid, fill(0.2, 5))
dr = modify(base, [0.4, 0.2, 0.0, -0.2, 0.0]; link = :logit)
sum(pdf(dr, Float64(b)) for b in grid)

See also

source
julia
modify(
    dist::Distributions.UnivariateDistribution,
    ::Nothing;
    link
) -> Distributions.UnivariateDistribution

Return the distribution unmodified when the effect is nothing.

This lets callers thread an optional hazard effect through modify(dist, effect) and pass nothing to mean "no modification": the distribution is returned unchanged, mirroring weight(dist, nothing).

Examples

julia
using ModifiedDistributions, Distributions

d = LogNormal(1.5, 0.5)
modify(d, nothing) === d
source
ModifiedDistributions.series_transform Function
julia
series_transform(
    d::Distributions.UnivariateDistribution,
    op
) -> ModifiedDistributions.Transformed

Map a distribution's convolved count series through a forward op.

series_transform(d, op) carries op (a thin/cumulative op or any callable series -> series) intended for the series a downstream convolution layer produces. Transparent to logpdf. Prefer thin / cumulative for the common cases; use series_transform for an arbitrary deterministic series map. Renamed from transform so it cannot clash with DataFrames.transform (#35).

Arguments

  • d: the inner distribution.

  • op: a forward op or a callable series -> series.

Examples

julia
using ModifiedDistributions, Distributions

d = series_transform(Gamma(2.0, 1.0), s -> 0.5 .* s)
logpdf(d, 2.0) == logpdf(Gamma(2.0, 1.0), 2.0)

See also

source
ModifiedDistributions.thin Function
julia
thin(
    dist::Distributions.UnivariateDistribution,
    p::Real
) -> ModifiedDistributions.Transformed{D, Op} where {D<:(Distributions.UnivariateDistribution), Op<:ModifiedDistributions.ThinOp}

Thin a distribution's forward count by a probability p.

thin(d, p) is series_transform with a fixed factor p ∈ [0, 1] intended to be multiplied into a downstream count series (e.g. ascertainment of cases, the infection fatality ratio for deaths). Transparent to logpdf. thin(d, nothing) returns d unchanged. Under the ConvolvedDistributions extension the carried op applies to the convolved count series.

Arguments

  • d: the inner distribution.

  • p: the thinning probability in .

Examples

julia
using ModifiedDistributions, Distributions

d = thin(LogNormal(1.5, 0.5), 0.3)
logpdf(d, 2.0) == logpdf(LogNormal(1.5, 0.5), 2.0)

See also

source
ModifiedDistributions.total_mass Function

Return the total probability mass a Modified law holds.

1 for a proper law; below 1 for a sub-stochastic (defective) law, where a negative additive-hazard effect (or a clamped numeric hazard modification) has left part of the base's mass escaping past the support. The complementary ccdf reports the residual deficit consistently: ccdf(d, x) converges to 1 - total_mass(d) as x grows through the support.

Arguments

Examples

julia
using ModifiedDistributions, Distributions

d = modify(Exponential(1.0), -0.5; link = ModifiedDistributions.IdentityLink)
total_mass(d) < 1

See also

source
ModifiedDistributions.weight Function
julia
weight(
    dist::Distributions.UnivariateDistribution,
    w::Real
) -> ModifiedDistributions.Weighted{D, T} where {D<:(Distributions.UnivariateDistribution), T<:Real}

Create a weighted distribution where the log-probability is scaled by w.

A Weighted distribution will contribute w * logpdf(dist, x) to the log-probability when evaluating logpdf(weighted_dist, x). Unlike an ad hoc w * logpdf(dist, x) term in model code, the result is still a real distribution whose sampling delegates to dist, so a Turing.jl model (or any PPL built on Distributions.jl) that uses it stays a complete generative model with working prior and posterior-predictive simulation.

Examples

julia
using ModifiedDistributions, Distributions

# For aggregated count data
y_obs = 3.5  # Observed value
n_count = 25  # Number of times this value was observed

d = Normal(2.0, 1.0)
weighted_d = weight(d, n_count)

# Weighted log-probability calculation
weighted_logpdf = logpdf(weighted_d, y_obs)
# equivalent to: n_count * logpdf(d, y_obs)
source
julia
weight(
    dist::Distributions.UnivariateDistribution,
    _::Nothing
) -> Distributions.UnivariateDistribution

Return the distribution unweighted when the weight is nothing.

This lets callers thread an optional weight through weight(dist, w) and pass nothing to mean "no weight": the distribution is returned unchanged.

Examples

julia
using ModifiedDistributions, Distributions

d = Normal(2.0, 1.0)
weight(d, nothing) === d
source
julia
weight(
    dist::Distributions.UnivariateDistribution,
    weights::AbstractVector{<:Real}
) -> Any

Create a product distribution of weighted distributions, each with a different weight.

A Product distribution of Weighted distributions suitable for vectorised observations.

Arguments

  • dist: The univariate distribution to be replicated and weighted for each observation

  • weights: Vector of weights to apply to each copy of the distribution

Examples

julia
using ModifiedDistributions, Distributions

y_obs = [3.5, 4.2, 3.8]  # Observed values
n_counts = [25, 10, 15]  # Counts for each observation

d = Normal(2.0, 1.0)
weighted_dists = weight(d, n_counts)

# Weighted log-probability calculation
weighted_logpdf = logpdf(weighted_dists, y_obs)
# equivalent to: sum(n_counts .* logpdf.(d, y_obs))

See also

  • Weighted: The underlying weighted distribution type
source
julia
weight(
    dists::AbstractVector{<:Distributions.UnivariateDistribution},
    weights::AbstractVector{<:Real}
) -> Any

Create a product distribution of weighted distributions, where each distribution has its own weight.

A Product distribution of Weighted distributions suitable for vectorised observations with different distributions.

Examples

julia
using ModifiedDistributions, Distributions

y_obs = [3.5, 4.2, 3.8]  # Observed values
dists = [Normal(2.0, 0.5), Normal(2.5, 0.8), Normal(1.8, 0.6)]
n_counts = [25, 10, 15]  # Counts for each observation
weighted_dists = weight(dists, n_counts)
source
julia
weight(
    dist::Distributions.UnivariateDistribution
) -> ModifiedDistributions.Weighted{D, Missing} where D<:(Distributions.UnivariateDistribution)

Create a weighted distribution with missing constructor weight.

Useful for creating distributions where weights will be provided at observation time. Uses missing as constructor weight, enabling observation weight to be used directly.

Examples

julia
using ModifiedDistributions, Distributions

d = Normal(2.0, 0.5)

# Create weighted distribution with missing constructor weight
weighted_dist = weight(d)

# Weight provided at observation time via joint observations
logpdf(weighted_dist, (value = 3.5, weight = 25))
source
julia
weight(
    dists::AbstractVector{<:Distributions.UnivariateDistribution}
) -> Any

Create a product distribution of weighted distributions with missing constructor weights.

Useful for creating distributions where weights will be provided at observation time. Each distribution uses missing as constructor weight, enabling observation weight to be used directly.

Examples

julia
using ModifiedDistributions, Distributions

y_obs = [3.5, 4.2, 3.8]  # Observed values
dists = [Normal(2.0, 0.5), Normal(2.5, 0.8), Normal(1.8, 0.6)]

# Create weighted distributions with missing constructor weights
weighted_dists = weight(dists)

# Weights provided at observation time via joint observations
logpdf(weighted_dists, (values = y_obs, weights = [25, 10, 15]))
source