Public Documentation
Documentation for CensoredDistributions.jl's public interface.
See the Internals section of the manual for internal package docs covering all submodules.
Contents
Index
CensoredDistributions.AbstractSolverMethodCensoredDistributions.AnalyticalSolverCensoredDistributions.ConvolvedCensoredDistributions.ExponentiallyTiltedCensoredDistributions.ExponentiallyTiltedCensoredDistributions.GaussLegendreCensoredDistributions.IntervalCensoredCensoredDistributions.NumericSolverCensoredDistributions.PrimaryCensoredCensoredDistributions.WeightedCensoredDistributions.convolve_distributionsCensoredDistributions.double_interval_censoredCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_distCensoredDistributions.get_dist_recursiveCensoredDistributions.gl_integrateCensoredDistributions.integrateCensoredDistributions.interval_censoredCensoredDistributions.interval_censoredCensoredDistributions.primary_censoredCensoredDistributions.primary_censoredCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_cdfCensoredDistributions.primarycensored_logcdfCensoredDistributions.primarycensored_uniform_cdf_formulaCensoredDistributions.weightCensoredDistributions.weightCensoredDistributions.weightCensoredDistributions.weightCensoredDistributions.weight
Public API
CensoredDistributions.AbstractSolverMethod Type
abstract type AbstractSolverMethodAbstract type for solver methods used in CDF computation.
Subtypes determine whether analytical solutions are preferred or numerical integration is forced.
Fields
sourceCensoredDistributions.AnalyticalSolver Type
struct AnalyticalSolver{S} <: CensoredDistributions.AbstractSolverMethodSolver that attempts analytical solutions when available, falling back to numerical integration.
Stores a numerical integration solver for use when no analytical solution exists for a given distribution pair.
Fields
solver::Any
CensoredDistributions.Convolved Type
struct Convolved{C<:Tuple} <: Distributions.Distribution{Distributions.Univariate, Distributions.Continuous}Distribution of a sum of independent random variables (a convolution).
Convolved represents
Components may have negative support (for example a Normal capturing pre-symptomatic transmission timing); minimum and maximum are the sums of the component supports, taking the value
CDF computation
The CDF is computed by integrating one component out against the CDF of the others:
where
Where an analytical convolution is available (Distributions.convolve applies, e.g. Normal+Normal, equal-scale Gamma, equal-rate Exponential) the two-component result is taken directly from the convolved distribution unless force_numeric is set. All other cases use AD-safe fixed-node Gauss-Legendre quadrature: the integral is mapped from the fixed reference domain gl_integrate), which lets every AD backend specialise on the integrand's own type so component Duals and tangents propagate.
The force_numeric field forces the numeric quadrature path even when an analytic convolution exists, mirroring primary_censored; it is useful for validation and debugging.
See also
convolve_distributions: Constructor function
Fields
components::Tuple: Tuple of independent component distributions to be summed.force_numeric::Bool: Force numeric quadrature even when an analytic convolution exists.
CensoredDistributions.ExponentiallyTilted Type
struct ExponentiallyTilted{T<:Real} <: Distributions.Distribution{Distributions.Univariate, Distributions.Continuous}A continuous distribution on interval [min, max] with exponential tilting controlled by parameter r. This distribution generalises the uniform distribution by allowing exponential weighting of values within the interval.
Mathematical Definition
The probability density function is:
for x ∈ [min, max] and r ≠ 0.
The cumulative distribution function is:
for x ∈ [min, max].
The quantile function (inverse CDF) is:
for p ∈ [0, 1].
When r → 0, all functions reduce to the uniform distribution on [min, max].
For r > 0: distribution is tilted towards higher values (increasing density)
For r < 0: distribution is tilted towards lower values (decreasing density)
Fields
min::Real: Lower bound of the distribution support.max::Real: Upper bound of the distribution support.r::Real: Growth rate parameter (tilting parameter).
CensoredDistributions.ExponentiallyTilted Method
Create an exponentially tilted distribution.
An exponentially tilted distribution on interval [min, max] with growth rate r. For r > 0, the distribution is tilted towards higher values; for r < 0, towards lower values. When r ≈ 0, it approaches a uniform distribution.
Examples
using CensoredDistributions, Distributions
# Exponentially increasing distribution
d1 = ExponentiallyTilted(0.0, 1.0, 2.0)
pdf(d1, 0.5)
# Nearly uniform distribution (small r)
d3 = ExponentiallyTilted(0.0, 1.0, 1e-10)
rand(d3, 5)CensoredDistributions.GaussLegendre Type
struct GaussLegendre{R}Fixed-node Gauss-Legendre quadrature solver (the package default).
Integrates with a Gauss-Legendre rule of n nodes, evaluated as a bare weighted dot product (see gl_integrate). The constant control flow and the accumulator type being seeded from the integrand make this the AD-safe default: every supported AD backend can differentiate through it, unlike adaptive schemes whose node count depends on integrand values.
The reference nodes and weights are built once at construction and held on the solver, so the differentiated hot path is a pure weighted sum with no shared mutable state. This matters for trace-based reverse-mode backends (Enzyme, ReverseDiff): resolving the rule through a mutated global cache inside the integrand crashes Enzyme reverse, so the rule travels with the solver instead.
n = 64 is accurate to about 1e-13 on the smooth, density-weighted integrands used in this package. This is the core default and needs no heavy dependency. Load Integrals.jl and pass an Integrals.jl algorithm (e.g. QuadGKJL()) when adaptive accuracy is wanted and AD is not.
See also
gl_integrate: The underlying quadrature reduction.integrate: The pluggable entry point dispatching on a solver.
Fields
n::Int64: Number of Gauss-Legendre nodes.rule::Any: The reference Gauss-Legendre rule (nodes/weights on[-1, 1]).
CensoredDistributions.IntervalCensored Type
struct IntervalCensored{D<:(Distributions.UnivariateDistribution), T} <: Distributions.UnivariateDistribution{Distributions.ValueSupport}Interval-censored distribution where continuous values are observed only within intervals.
Supports both:
Regular intervals: fixed-width intervals (e.g., daily reporting)
Arbitrary intervals: custom interval boundaries
Fields
dist::Distributions.UnivariateDistribution: The underlying continuous distributionboundaries::Any: Either a scalar (regular intervals) or vector (boundaries for arbitrary intervals)
CensoredDistributions.NumericSolver Type
struct NumericSolver{S} <: CensoredDistributions.AbstractSolverMethodSolver that always uses numerical integration.
Forces numerical computation even when analytical solutions are available, useful for testing and validation.
The solver field contains the numerical integration solver to use.
Fields
solver::Any
CensoredDistributions.PrimaryCensored Type
struct PrimaryCensored{D1<:(Distributions.UnivariateDistribution), D2<:(Distributions.UnivariateDistribution), M<:CensoredDistributions.AbstractSolverMethod} <: Distributions.Distribution{Distributions.Univariate, Distributions.Continuous}Represents the distribution of observed delays when the primary event time is subject to censoring.
The dist field contains the delay distribution from primary event to observation. The primary_event field contains the primary event time distribution. The method field determines computation strategy:
AnalyticalSolver: Uses closed-form solutions when available (Gamma, LogNormal, Weibull with Uniform primary), falls back to numeric otherwiseNumericSolver: Always uses quadrature integration
See also
primary_censored: Constructor functionprimarycensored_cdf: CDF computation with method dispatch
Fields
dist::Distributions.UnivariateDistribution: The delay distribution from primary event to observation.primary_event::Distributions.UnivariateDistribution: The primary event time distribution.method::CensoredDistributions.AbstractSolverMethod: The solver method for CDF computation.
CensoredDistributions.Weighted Type
struct Weighted{D<:(Distributions.UnivariateDistribution), T<:Union{Missing, Real}} <: Distributions.UnivariateDistribution{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:
Real weights: Constructor weight is a specific value (e.g.,
2.5)Missing weights: Constructor weight is
missing, allowing weights to be provided at observation time via joint observations(value = x, weight = w)Zero weights: Handled specially to return
-Infand avoid NaN from0 * -Inf
Examples
using CensoredDistributions, 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_logpdfFields
dist::Distributions.UnivariateDistribution: The underlying distribution being weighted.weight::Union{Missing, Real}: The weight to apply to log-probabilities.
CensoredDistributions.convolve_distributions Method
convolve_distributions(
components::AbstractVector{<:Distributions.UnivariateDistribution};
force_numeric
) -> CensoredDistributions.ConvolvedCreate the distribution of a sum of independent delays (a convolution).
Accepts either two or more positional component distributions, or a single vector/tuple of components. Returns a Convolved distribution.
Arguments
components: Two or moreUnivariateDistributions, or a vector/tuple of them.
Keyword Arguments
force_numeric: Force numeric quadrature even when an analytic convolution is available (default:false), mirroringprimary_censored.
Examples
using CensoredDistributions, Distributions
# Sum of two delays
d = convolve_distributions(Gamma(2.0, 1.0), LogNormal(1.5, 0.5))
cdf_at_5 = cdf(d, 5.0)
# Sum of three delays from a vector
d3 = convolve_distributions([Gamma(2.0, 1.0), Gamma(1.0, 1.0), Normal(0.0, 1.0)])
mean_sample = rand(d3)
# Force numeric quadrature even for an analytic pair
dn = convolve_distributions(Normal(0.0, 1.0), Normal(1.0, 2.0); force_numeric=true)
cdf_numeric = cdf(dn, 2.0)See also
Convolved: The distribution type
CensoredDistributions.double_interval_censored Method
double_interval_censored(
dist::Distributions.UnivariateDistribution;
primary_event,
lower,
upper,
interval,
method,
force_numeric
) -> CensoredDistributions.PrimaryCensored{D1, Distributions.Uniform{Float64}, AnalyticalSolver{CensoredDistributions.GaussLegendre{CensoredDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where D1<:(Distributions.UnivariateDistribution)Create a distribution that combines primary interval censoring, optional truncation, and optional secondary interval censoring in the correct order.
This is a convenience function that applies the following transformations in sequence:
Primary event censoring using
primary_censored(dist, primary_event)Truncation using
truncated(dist; lower=lower, upper=upper)(if bounds are provided)Secondary interval censoring using
interval_censored(dist, interval)(if interval is provided)
The order of operations ensures mathematical correctness, particularly that truncation occurs before secondary interval censoring.
Arguments
dist: The delay distribution from primary event to observation
Keyword Arguments
primary_event: The primary event time distribution. Defaults to uniform distribution over [0, 1].lower: Lower truncation bound. Ifnothing, no lower truncation is applied.upper: Upper truncation bound (e.g., observation timeD). Ifnothing, no upper truncation is applied.interval: Secondary censoring interval width (e.g., daily reporting). Ifnothing, no interval censoring is applied.method: Primary-censoring solver method, anAnalyticalSolverorNumericSolver. Defaults toAnalyticalSolver(). Passing a concrete method keeps the return type concrete when the delay parameters are runtime values.force_numeric: Deprecated. Passmethod = NumericSolver()instead.
Returns
A composed distribution that can be used with all standard Distributions.jl methods (rand, pdf, cdf, etc.).
Examples
using CensoredDistributions, Distributions
# Basic primary censoring only (uses default Uniform(0, 1))
dist1 = double_interval_censored(LogNormal(1.5, 0.75))
# Primary censoring + truncation
dist2 = double_interval_censored(LogNormal(1.5, 0.75); upper=10)
# Primary censoring + secondary interval censoring
dist3 = double_interval_censored(LogNormal(1.5, 0.75); interval=1)
# Full double interval censoring with truncation
dist4 = double_interval_censored(LogNormal(1.5, 0.75); upper=10, interval=1)
# Evaluate distribution functions and compute statistics
pdf_at_3 = pdf(dist4, 3.0) # probability density at 3 days
cdf_at_7 = cdf(dist4, 7.0) # P(X ≤ 7) with full censoring pipeline
ccdf_at_5 = ccdf(dist4, 5.0) # survival function
q25 = quantile(dist4, 0.25) # 25th percentile
median_delay = quantile(dist4, 0.5) # median
q95 = quantile(dist4, 0.95) # 95th percentile
samples = rand(dist4, 100) # random samples
# Custom primary event distribution
dist5 = double_interval_censored(LogNormal(1.5, 0.75); primary_event=Uniform(0, 2))Mathematical Background
This function implements the complete workflow for handling censored delay distributions as described in [1] and [2]:
Primary censoring: Accounts for uncertainty in the primary event timing
Truncation: Handles observation windows and finite study periods
Secondary censoring: Models interval censoring effects (e.g., daily reporting)
CensoredDistributions.get_dist Method
get_dist(d) -> Distributions.UnivariateDistributionExtract the underlying distribution from a wrapped distribution type.
This utility function provides a consistent interface for extracting the core distribution from various wrapper types in the CensoredDistributions ecosystem. 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
using CensoredDistributions, Distributions
# Base distribution - returns unchanged
d1 = Normal(0, 1)
get_dist(d1)
# Primary censored distribution
delay = LogNormal(1.5, 0.75)
window = Uniform(0, 1)
pc = primary_censored(delay, window)
get_dist(pc)
# Interval censored distribution
continuous = Normal(5, 2)
ic = interval_censored(continuous, 1.0)
get_dist(ic)CensoredDistributions.get_dist Method
get_dist(d::CensoredDistributions.Convolved) -> VectorExtract the component distributions from a convolved distribution.
Returns a vector of the independent component distributions being summed. Like the Product method, this returns a vector rather than a single distribution.
CensoredDistributions.get_dist Method
get_dist(
d::CensoredDistributions.IntervalCensored
) -> Distributions.UnivariateDistributionExtract the underlying continuous distribution from an interval censored distribution.
Returns the continuous distribution that was discretised into intervals.
sourceCensoredDistributions.get_dist Method
get_dist(
d::CensoredDistributions.PrimaryCensored
) -> Distributions.UnivariateDistributionExtract the delay distribution from a primary censored distribution.
Returns the underlying delay distribution (the distribution of times from primary event to observation).
sourceCensoredDistributions.get_dist Method
get_dist(
d::CensoredDistributions.Weighted
) -> Distributions.UnivariateDistributionExtract the underlying distribution from a weighted distribution.
Returns the base distribution before weighting was applied.
sourceCensoredDistributions.get_dist Method
get_dist(
d::Distributions.Censored
) -> Distributions.UnivariateDistributionExtract the underlying distribution from a censored distribution.
Returns the uncensored distribution before censoring bounds were applied. This method supports the Censored type from Distributions.jl created by the censored() function.
Examples
using Distributions
# Extract Normal from censored Normal
base = Normal(0, 1)
censored_dist = censored(base, -2, 2)
get_dist(censored_dist)
# Works with any censored distribution
gamma_base = Gamma(2, 1)
censored_gamma = censored(gamma_base, 0.1, 5.0)
get_dist(censored_gamma)CensoredDistributions.get_dist Method
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 distributions for each component of the product distribution. This is useful when working with vectorised distributions or multiple independent observations.
Note
This method has different behaviour from other get_dist methods as it returns a vector of distributions rather than a single distribution.
CensoredDistributions.get_dist Method
get_dist(
d::Distributions.Truncated
) -> Distributions.UnivariateDistributionExtract the untruncated distribution from a truncated distribution.
Returns the underlying continuous distribution before truncation bounds were applied.
Examples
using Distributions
# Extract Normal from truncated Normal
base = Normal(0, 1)
trunc_dist = truncated(base, -2, 2)
get_dist(trunc_dist)
# Works with any truncated distribution
gamma_base = Gamma(2, 1)
trunc_gamma = truncated(gamma_base, 0.1, 5.0)
get_dist(trunc_gamma)CensoredDistributions.get_dist_recursive Method
get_dist_recursive(d) -> AnyRecursively 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. This is useful for deeply nested distributions like IntervalCensored{Truncated{PrimaryCensored{...}}}.
Arguments
d: A distribution or nested wrapped distribution
Returns
The deeply underlying distribution after all unwrapping is complete.
Examples
using CensoredDistributions, Distributions
# Single wrapper - same as get_dist
delay = LogNormal(1.5, 0.75)
window = Uniform(0, 1)
pc = primary_censored(delay, window)
get_dist_recursive(pc)
# Nested wrappers
continuous = Normal(5, 2)
ic = interval_censored(continuous, 1.0)
weighted = weight(ic, 2.0)
get_dist_recursive(weighted)
# Double interval censored distributions (fully recursive)
delay = LogNormal(1.5, 0.75)
full_double = double_interval_censored(delay; upper=10, interval=1)
get_dist_recursive(full_double)
# Base distribution - returns unchanged
d = Normal(0, 1)
get_dist_recursive(d)Note
For Product distributions, this function applies recursive extraction to each component, potentially returning mixed types of underlying distributions.
CensoredDistributions.gl_integrate Method
gl_integrate(f, lo, hi) -> Any
gl_integrate(
f,
lo,
hi,
rule::CensoredDistributions._GL
) -> AnyIntegrate a scalar function f over [lo, hi] by fixed-node Gauss-Legendre quadrature.
The reference domain [-1, 1] is mapped onto [lo, hi] inside the integrand and the result reduced as a weighted dot product, so the accumulator's element type is taken from the integrand and AD Duals and tangents propagate. Returns a typed zero when hi <= lo.
Arguments
f: The scalar integrand.lo: Lower integration bound.hi: Upper integration bound.rule: Gauss-Legendre rule to use (default: the 192-node convolution rule).
Examples
using CensoredDistributions
# Integrate x^2 over [0, 1] (exact value 1/3)
approx = CensoredDistributions.gl_integrate(x -> x^2, 0.0, 1.0)See also
GaussLegendre: The default solver wrapping this rule.integrate: The pluggable entry point.
CensoredDistributions.integrate Method
integrate(
solver::CensoredDistributions.GaussLegendre,
f,
lower,
upper
) -> AnyIntegrate a scalar function f over [lower, upper] using solver.
This is the pluggable integration entry point: every integral in the package calls integrate, dispatching on the solver type. The default GaussLegendre solver routes to gl_integrate. Loading the optional Integrals.jl extension adds a method for Integrals.jl algorithms (e.g. QuadGKJL()), which builds an IntegralProblem and calls solve.
Arguments
solver: The integration backend.GaussLegendreby default; any Integrals.jl algorithm when that extension is loaded.f: The scalar integrand.lower: Lower integration bound.upper: Upper integration bound.
Examples
using CensoredDistributions
solver = CensoredDistributions.GaussLegendre(; n = 64)
approx = CensoredDistributions.integrate(solver, x -> x^2, 0.0, 1.0)See also
GaussLegendre: The default solver.gl_integrate: The default quadrature reduction.
CensoredDistributions.interval_censored Method
interval_censored(
dist::Distributions.UnivariateDistribution,
boundaries::AbstractVector{<:Real}
) -> CensoredDistributions.IntervalCensored{D, <:AbstractVector{var"#s16"}} where {D<:(Distributions.UnivariateDistribution), var"#s16"<:Real}Construct an interval-censored distribution with arbitrary intervals.
Creates a distribution where observations are censored to specified intervals defined by the boundaries. For example, with boundaries=[0, 2, 5, 10], observations fall into [0,2), [2,5), or [5,10).
Arguments
dist: The underlying continuous distributionboundaries: Vector of interval boundaries (must be sorted and strictly increasing, minimum length 2)
Examples
using CensoredDistributions, Distributions
# Age groups: 0-18, 18-65, 65+
age_dist = interval_censored(Normal(40, 20), [0, 18, 65, 100])
q75 = quantile(age_dist, 0.75) # 75th percentile (boundary value)CensoredDistributions.interval_censored Method
interval_censored(
dist::Distributions.UnivariateDistribution,
interval::Real
) -> CensoredDistributions.IntervalCensored{D, <:Real} where D<:(Distributions.UnivariateDistribution)Construct an interval-censored distribution with regular intervals.
Creates a distribution where observations are censored to regular intervals of width interval, starting from 0. For example, with interval=1, observations fall into [0,1), [1,2), [2,3), etc.
Arguments
dist: The underlying continuous distributioninterval: Width of regular intervals (must be positive)
Examples
using CensoredDistributions, Distributions
# Daily reporting intervals
d = interval_censored(Normal(5, 2), 1.0)
# Evaluate distribution functions
pdf_at_5 = pdf(d, 5.0) # probability mass at interval containing 5
q25 = quantile(d, 0.25) # 25th percentile (interval boundary)CensoredDistributions.primary_censored Method
primary_censored(
dist::Distributions.UnivariateDistribution,
primary_event::Distributions.UnivariateDistribution;
method,
solver,
force_numeric
) -> CensoredDistributions.PrimaryCensored{D1, D2, AnalyticalSolver{CensoredDistributions.GaussLegendre{CensoredDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where {D1<:(Distributions.UnivariateDistribution), D2<:(Distributions.UnivariateDistribution)}Create a primary event censored distribution.
Models a process where a primary event occurs within a censoring window, followed by a delay. The primary event time is not observed directly but is known to fall within the censoring distribution's support. The observed time is the sum of the primary event time and the delay.
Method Selection
The CDF computation is handled by primarycensored_cdf, which dispatches on the method:
AnalyticalSolver(the default): closed-form solutions for these distribution pairs with Uniform primary events, falling back to numeric quadrature otherwise:Gammadelay distributionLogNormaldelay distributionWeibulldelay distribution
NumericSolver: always uses quadrature integration, which may be necessary for certain AD backends or when debugging.
Passing the solver method as a concrete object keeps the return type concrete even when the delay parameters are runtime values (e.g. inside a probabilistic model), so it is preferred over the deprecated force_numeric flag.
Arguments
dist: The delay distribution from primary event to observationprimary_event: The distribution of primary event times within the window
Keyword Arguments
method: The solver method, anAnalyticalSolverorNumericSolver. Defaults toAnalyticalSolver(). Each takes an optional quadrature solver, e.g.NumericSolver(QuadGKJL()).solver: Quadrature solver used whenmethodis not given (default:GaussLegendre(; n = 64), AD-friendly; passQuadGKJL()for adaptive accuracy).force_numeric: Deprecated. Passmethod = NumericSolver()instead.
This is useful for modeling:
Infection-to-symptom onset times when infection time is uncertain
Exposure-to-outcome delays with uncertain exposure timing
Any process where the initiating event time has uncertainty
Examples
using CensoredDistributions, Distributions
# Incubation period (delay) with uncertain infection time (primary event)
incubation = LogNormal(1.5, 0.75) # Delay distribution
infection_window = Uniform(0, 1) # Daily infection window
d = primary_censored(incubation, infection_window)
# Evaluate distribution functions
pdf_at_2 = pdf(d, 2.0) # probability density at 2 days
cdf_at_5 = cdf(d, 5.0) # cumulative probability by 5 days
q50 = quantile(d, 0.5) # median
# Force numeric integration for debugging or AD compatibility
d_numeric = primary_censored(incubation, infection_window;
method = NumericSolver())See also
primarycensored_cdf: The underlying CDF computation with method dispatch
CensoredDistributions.primary_censored Method
primary_censored(
dist::Distributions.UnivariateDistribution;
primary_event,
method,
solver,
force_numeric
) -> CensoredDistributions.PrimaryCensored{D1, Distributions.Uniform{Float64}, AnalyticalSolver{CensoredDistributions.GaussLegendre{CensoredDistributions._GL{Vector{Float64}, Vector{Float64}}}}} where D1<:(Distributions.UnivariateDistribution)Create a primary event censored distribution with keyword arguments.
This is a convenience version of primary_censored that uses keyword arguments for consistency with double_interval_censored. The primary event distribution defaults to Uniform(0, 1).
Examples
using CensoredDistributions, Distributions
# Using default Uniform(0, 1) primary event
d1 = primary_censored(LogNormal(1.5, 0.75))
# Custom primary event distribution
d2 = primary_censored(LogNormal(1.5, 0.75); primary_event=Uniform(0, 2))CensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.Gamma,
primary_event::Distributions.Uniform,
x::Real,
_::AnalyticalSolver
) -> AnyAnalytical CDF for Gamma delay with Uniform primary event distribution.
Partial first moment is
y^k and inv(Γ(k+1)) are shared between
CensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.LogNormal,
primary_event::Distributions.Uniform,
x::Real,
_::AnalyticalSolver
) -> AnyAnalytical CDF for LogNormal delay with Uniform primary event distribution.
Partial first moment is
CensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.Weibull,
primary_event::Distributions.Uniform,
x::Real,
_::AnalyticalSolver
) -> AnyAnalytical CDF for Weibull delay with Uniform primary event distribution.
Partial first moment is
CensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.UnivariateDistribution,
primary_event::Distributions.UnivariateDistribution,
x::Real,
method::AnalyticalSolver
) -> AnyGeneric fallback implementation for AnalyticalSolver.
When no specific analytical solution is available for a distribution pair, this method falls back to numerical integration using the solver stored in the AnalyticalSolver.
Specific analytical implementations exist for:
Gamma delay with Uniform primary event
LogNormal delay with Uniform primary event
Weibull delay with Uniform primary event
For all other distribution pairs, numerical integration is used automatically.
sourceCensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.UnivariateDistribution,
primary_event::Distributions.UnivariateDistribution,
x::Real,
method::CensoredDistributions.AbstractSolverMethod
) -> AnyCompute the CDF of a primary event censored distribution.
Dispatches to either analytical or numerical implementation based on the solver method. Analytical solutions are available for specific distribution pairs with Uniform primary events. Use methods(primarycensored_cdf) to see all available analytical implementations.
For distribution pairs without analytical solutions, numerical integration is used automatically when called with an AnalyticalSolver. Use NumericSolver to force numerical integration even when analytical solutions exist (useful for testing and validation).
Arguments
dist: The delay distribution from primary event to observationprimary_event: The primary event time distributionx: Evaluation point for the CDFmethod: Solver method (AnalyticalSolverorNumericSolver)
Returns
The cumulative probability P(X ≤ x) where X is the observed delay time.
Examples
using CensoredDistributions, Distributions
# Analytical solution for Gamma with Uniform primary event. The default
# `GaussLegendre` solver is the numeric fallback.
gamma_dist = Gamma(2.0, 1.5)
primary_uniform = Uniform(0, 2)
analytical_method = AnalyticalSolver()
cdf_val = primarycensored_cdf(gamma_dist, primary_uniform, 3.0, analytical_method)
# Force numerical integration
numeric_method = NumericSolver()
cdf_numeric = primarycensored_cdf(gamma_dist, primary_uniform, 3.0, numeric_method)For improved accuracy, load Integrals.jl and pass an Integrals.jl algorithm (e.g. NumericSolver(QuadGKJL())).
CensoredDistributions.primarycensored_cdf Method
primarycensored_cdf(
dist::Distributions.UnivariateDistribution,
primary_event::Distributions.UnivariateDistribution,
x::Real,
method::NumericSolver
) -> AnyNumerical CDF implementation for primary event censored distributions.
Computes the CDF using numerical integration when no analytical solution is available. The integral computed is:
where F_S is the delay distribution CDF, f_U is the primary event distribution PDF, u_min and u_max are the primary event bounds, and s_min is the delay minimum.
Handles edge cases and uses the solver stored in the NumericSolver method.
sourceCensoredDistributions.primarycensored_logcdf Method
primarycensored_logcdf(
dist::Distributions.UnivariateDistribution,
primary_event::Distributions.UnivariateDistribution,
x::Real,
method::CensoredDistributions.AbstractSolverMethod
) -> AnyCompute the log CDF of a primary event censored distribution.
Dispatches to either analytical or numerical implementation based on the solver method. Computes log(CDF) with appropriate handling for edge cases where CDF = 0. Returns -Inf when the probability is zero or when numerical issues occur.
Arguments
dist: The delay distribution from primary event to observationprimary_event: The primary event time distributionx: Evaluation point for the log CDFmethod: Solver method (AnalyticalSolverorNumericSolver)
Examples
using CensoredDistributions, Distributions
# Create a Gamma delay with uniform primary event
dist = Gamma(2.0, 1.5)
primary_event = Uniform(0.0, 3.0)
method = AnalyticalSolver(nothing)
# Compute log CDF at x = 5.0
log_prob = primarycensored_logcdf(dist, primary_event, 5.0, method)See also
primarycensored_cdf: The underlying CDF computationcdf: Interface method for PrimaryCensored distributionslogcdf: Interface method for PrimaryCensored distributions
CensoredDistributions.primarycensored_uniform_cdf_formula Method
primarycensored_uniform_cdf_formula(
d,
q,
F_T_d,
F_T_q,
M_T_d,
M_T_q,
pwindow
) -> AnyDirect CDF form of the primary-event-censored distribution when the primary event distribution is Uniform. The
Derived by integration by parts on the partial expectation:
where
This helper is the shared arithmetic shape of the three built-in analytical pairs (Gamma / LogNormal / Weibull + Uniform) and is exposed as public (but not exported) API so that downstream code can add its own primarycensored_cdf(::MyDelay, ::Uniform, x, ::AnalyticalSolver) method without re-deriving the formula. Supply
Gamma:
.LogNormal:
.Weibull:
.
When q is clamped to 0 (i.e. F_T_q = 0 and M_T_q = 0; both terms drop out cleanly.
Arguments
d::Real: Primary-event-adjusted evaluation point (x - u_{min}).q::Real: Lower integration endpoint,max(d - w_P, 0).F_T_d::Real: Delay CDF atd,F_T(d).F_T_q::Real: Delay CDF atq,F_T(q)(pass0whenq = 0).M_T_d::Real: Partial first moment atd,M_T(d).M_T_q::Real: Partial first moment atq,M_T(q)(pass0whenq = 0).pwindow::Real: Primary window widthw_P.
Returns
The primary-censored CDF F_{S+}(x).
Example
Reproduces the built-in Gamma analytical pair from first principles:
using CensoredDistributions, Distributions
dist = Gamma(2.0, 1.5)
primary = Uniform(0.0, 1.0)
x = 3.0
pmin = minimum(primary)
pwindow = maximum(primary) - pmin
d_adj = x - pmin
q = max(d_adj - pwindow, 0.0)
# F_T at the two endpoints
F_T_d = cdf(dist, d_adj)
F_T_q = q > 0 ? cdf(dist, q) : 0.0
# Gamma partial first moment: M_T(t) = kθ · F_T(t; k+1, θ)
k = shape(dist); θ = scale(dist); E_T = k * θ
dist_kp1 = Gamma(k + 1, θ)
M_T_d = E_T * cdf(dist_kp1, d_adj)
M_T_q = q > 0 ? E_T * cdf(dist_kp1, q) : 0.0
CensoredDistributions.primarycensored_uniform_cdf_formula(
d_adj, q, F_T_d, F_T_q, M_T_d, M_T_q, pwindow)CensoredDistributions.weight Method
weight(
dists::AbstractVector{<:Distributions.UnivariateDistribution},
weights::AbstractVector{<:Real}
) -> AnyCreate a product distribution of weighted distributions, where each distribution has its own weight.
A Product distribution of Weighted distributions suitable for vectorized observations with different distributions.
Examples
using CensoredDistributions, 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)CensoredDistributions.weight Method
weight(
dists::AbstractVector{<:Distributions.UnivariateDistribution}
) -> AnyCreate 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
using CensoredDistributions, 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]))CensoredDistributions.weight Method
weight(
dist::Distributions.UnivariateDistribution,
weights::AbstractVector{<:Real}
) -> AnyCreate a product distribution of weighted distributions, each with a different weight.
A Product distribution of Weighted distributions suitable for vectorized observations.
Arguments
dist: The univariate distribution to be replicated and weighted for each observationweights: Vector of weights to apply to each copy of the distribution
Examples
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
CensoredDistributions.weight Method
weight(
dist::Distributions.UnivariateDistribution,
w::Real
) -> CensoredDistributions.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).
Examples
# 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)CensoredDistributions.weight Method
weight(
dist::Distributions.UnivariateDistribution
) -> CensoredDistributions.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
using CensoredDistributions, 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))