dist_structure is a virtual S3 class that inherits from
univariate_dist and dist. Every concrete
constructor returns an object that participates in the full
algebraic.dist distribution algebra via inheritance:
When you call surv, cdf,
sampler on a dist_structure object, dispatch
goes through three paths in order of specificity:
Specialized closed-form methods (e.g.,
surv.exp_series, surv.wei_homogeneous_series).
Fastest; used when available.
Topology shortcut methods (e.g.,
surv.series_dist). Rare; most specializations land on the
specific parametric class.
The dist_structure default, which composes component distributions through the structure function via the reliability polynomial identity:
S_sys(t) = R(S_1(t), S_2(t), ..., S_m(t))
where R is the multilinear extension of
phi. This is how
coherent_dist(min_paths = ...) gets a surv function for any
topology, even one you specify by hand.
Samplers follow the analogous composition: sample each component
independently, then apply system_lifetime to reduce to a
scalar.
dist.structure provides both general and specialized constructors for common cases. You should prefer the specialization when available:
# General: any components, arbitrary topology
sys_general <- series_dist(replicate(3, exponential(1), simplify = FALSE))
# Specialization: exploits Exp(sum(rates)) closed form
sys_special <- exp_series(c(1, 1, 1))Both return identical distributions, but the specialization’s
surv is a one-liner (exp(-total_rate * t))
while the general version computes prod(exp(-rate_j * t))
per component per t. Same math, different cost.
Verify:
| Constructor | Closed form |
|---|---|
exp_series(rates) |
Exp(sum(rates)) exactly |
wei_series(shapes, scales) |
exp(-sum((t/scale)^shape)) for survival |
wei_homogeneous_series(shape, scales) |
single Weibull with aggregate scale |
gamma_series(shapes, rates) |
product of Gamma upper tails |
lognormal_series(meanlogs, sdlogs) |
product of Lognormal upper tails |
exp_parallel(rates) |
1 - prod(1 - exp(-rate*t)) |
exp_kofn(k, rates) |
subset enumeration (O(2^m)) |
wei_kofn(k, shapes, scales) |
same for Weibull components |
Each has closed-form surv, cdf,
sampler, and (where feasible) density. The
surv / cdf / density methods
registered on these subclasses dispatch before the
dist_structure default.
The base algebraic.dist has min and
max operators on dists that return plain dist objects.
dist.structure provides structure-aware counterparts:
d <- exponential(1)
# Plain min: just a dist, no topology
d_min <- min(d, d, d)
class(d_min)
#> [1] "exponential" "univariate_dist" "continuous_dist" "dist"# Structure-aware: a series_dist, topology preserved
sys_min <- min_iid(d, m = 3)
class(sys_min)
#> [1] "series_dist" "coherent_dist" "dist_structure" "univariate_dist"
#> [5] "continuous_dist" "dist"
dist.structure::min_paths(sys_min)
#> [[1]]
#> [1] 1 2 3Same survival function, but the structured version lets you ask
phi, min_paths,
structural_importance, and so on.
Similarly:
# Parallel: max of iid
sys_max <- max_iid(d, m = 3)
class(sys_max)
#> [1] "parallel_dist" "coherent_dist" "dist_structure" "univariate_dist"
#> [5] "continuous_dist" "dist"
# k-th order statistic
sys_k <- order_statistic(d, k = 2, m = 5)
class(sys_k)
#> [1] "kofn_dist" "coherent_dist" "dist_structure" "univariate_dist"
#> [5] "continuous_dist" "dist"density and hazard have specialized
implementations only where efficient formulas exist:
# Density of exp_series: dexp at the aggregate rate.
f <- density(exp_series(c(0.5, 0.3, 0.2)))
f(1)
#> [1] 0.3678794
dexp(1, rate = 1.0)
#> [1] 0.3678794For general coherent_dist objects, density
is typically computed via -d/dt surv(t) numerically. If you
need density on a system where it matters for performance,
register a specialized method or use a specialization that ships
one.
dist.structure + algebraic.dist
stackalgebraic.dist dist, generics, arithmetic on RVs
|
dist.structure dist with internal component structure
|
specialized + general impls exp_series, kofn_dist, coherent_dist, ...
|
downstream packages serieshaz, kofn, maskedcauses
Downstream packages (e.g., serieshaz’s
dfr_dist_series) inherit from dist_structure
and get topology + importance + composition for free. Users never need
to know whether a given generic is provided by the specialized class,
the dist_structure default, or the algebraic.dist base; S3 dispatch
finds the most specific method and that’s the one that runs.