knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(dist.structure) library(algebraic.dist)
The structure-function framework assumes a monotone binary function
phi: {0, 1}^m -> {0, 1} that maps per-component states to a system
state. This captures a huge class of reliability topologies but not
everything practitioners build. Cold standby is a canonical example.
A cold standby system has m components but only one is active at a time. When the active component fails, a dormant spare instantaneously takes over. System lifetime is the sum of component lifetimes, not an order statistic.
The topology is temporal succession, not a structure function on states. So cold standby:
dist_structure: it has no phi, no min_paths, no
signature, no Birnbaum importance.dist.structure provides cold_standby_dist for this case, with its
own class chain that deliberately does not inherit dist_structure.
sys <- cold_standby_dist(list( exponential(1), exponential(2), exponential(0.5) )) class(sys) dist.structure::is_dist_structure(sys) # FALSE -- not a coherent system
mean is exact when every component has an exact mean method: it sums
the component means.
mean(sys) # 1/1 + 1/2 + 1/0.5 = 3.5
The sampler is also exact: independent samples from each component, summed.
set.seed(1) x <- algebraic.dist::sampler(sys)(5000) mean(x) # empirical ~ 3.5
For general components, the density of a sum-of-independent-RVs has no
closed form (it's a convolution). dist.structure computes surv and
cdf via Monte Carlo sampling. The closure caches the samples on the
first call, so repeated evaluations at different t values are
deterministic given the same mc:
set.seed(42) S <- algebraic.dist::surv(sys) S(c(1, 2, 3, 5), mc = 5000) # survival at multiple t values
A different mc triggers a fresh draw:
S(2, mc = 5000) # uses the same cache S(2, mc = 10000) # new cache with 10000 samples
Because the cache lives inside the closure, using the same S closure
keeps results consistent. cdf has its own closure and its own
cache: cdf(sys)(t) + surv(sys)(t) computed independently is not
exactly 1. If you need that identity, use one surv closure and
compute the CDF from it:
S <- algebraic.dist::surv(sys) F_t <- function(t) 1 - S(t) F_t(2) + S(2) # exactly 1
For reproducibility across separate closure constructions, seed before each one:
set.seed(1); S1 <- algebraic.dist::surv(sys); s1 <- S1(2) set.seed(1); S2 <- algebraic.dist::surv(sys); s2 <- S2(2) all.equal(s1, s2)
A cold standby of m iid Exp(rate) components has system lifetime
Gamma(shape = m, rate = rate):
m <- 4; rate <- 2 sys <- cold_standby_dist(replicate(m, exponential(rate), simplify = FALSE)) # Monte Carlo survival at t = 3 set.seed(1) mc_est <- algebraic.dist::surv(sys)(3, mc = 10000) # Exact via Gamma exact <- pgamma(3, shape = m, rate = rate, lower.tail = FALSE) cat(sprintf("MC: %.4f, Exact: %.4f\n", mc_est, exact))
If you hit this case often, you can avoid the Monte Carlo by
constructing an algebraic.dist::gamma_dist directly.
Generics requiring topology or component-level density/sup fail
cleanly:
dist.structure::phi(sys, c(1, 1, 1, 1))
dist.structure::min_paths(sys)
Methods inherited from algebraic.dist::univariate_dist that require
density or sup (notably vcov, expectation) are also not
supported by default. A specialized subclass with a closed-form
aggregate (e.g., iid exponential -> Gamma) can provide them by
overriding.
When you need the full dist.structure protocol (topology, importance, composition), cold standby is the wrong tool; use a coherent system instead.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.