Composition and substitution

library(dist.structure)
library(algebraic.dist)

Building new systems from old

dist.structure provides two compositional operations:

These let you build hierarchical reliability networks without writing min_paths by hand.

Substituting a component

Start with a 3-component parallel system, then upgrade one component to a longer-lived Weibull:

sys <- parallel_dist(list(
  exponential(1),
  exponential(1),
  exponential(1)
))

# Survival at t = 1 for the all-exponential parallel:
algebraic.dist::surv(sys)(1)
#> [1] 0.7474195

sys2 <- substitute_component(sys, j = 1,
  new_component = weibull_dist(shape = 2, scale = 2))

# Survival improves because component 1 is now longer-lived:
algebraic.dist::surv(sys2)(1)
#> [1] 0.911614

substitute_component returns a coherent_dist with the same min_paths and the modified component list. Topology queries work identically:

length(min_paths(sys2))                # still 3 (parallel)
#> [1] 3
ncomponents(sys2)                      # still 3
#> [1] 3

Hierarchical composition

compose_systems nests: give an outer topology and a list of inner systems (one per outer component), and get back a flattened system whose min_paths combine both levels of topology.

Series of parallels

A common redundant design: two parallel blocks in series.

inner_a <- parallel_dist(list(exponential(1), exponential(1)))
inner_b <- parallel_dist(list(exponential(1), exponential(1)))

# Outer: series of 2 "slots" (the components are placeholder; they get
# replaced by the inners during compose_systems).
outer <- series_dist(list(exponential(1), exponential(1)))

sys <- compose_systems(outer, list(inner_a, inner_b))
ncomponents(sys)                       # 4 total leaf components
#> [1] 4
length(min_paths(sys))                 # 4 composed paths
#> [1] 4

The composed paths are the Cartesian product of inner paths within each outer path. Outer path is {1, 2}; inner_a min_paths = {1}, {2}; inner_b shifted min_paths = {3}, {4}. Four combinations: {1, 3}, {1, 4}, {2, 3}, {2, 4}.

min_paths(sys)
#> [[1]]
#> [1] 1 3
#> 
#> [[2]]
#> [1] 2 3
#> 
#> [[3]]
#> [1] 1 4
#> 
#> [[4]]
#> [1] 2 4

Parallel of series

The dual: two series blocks in parallel.

inner_a <- series_dist(list(exponential(1), exponential(1)))
inner_b <- series_dist(list(exponential(1), exponential(1)))

outer <- parallel_dist(list(exponential(1), exponential(1)))

sys <- compose_systems(outer, list(inner_a, inner_b))
ncomponents(sys)                       # 4 total
#> [1] 4
length(min_paths(sys))                 # 2 composed paths
#> [1] 2
min_paths(sys)                         # {1, 2} and {3, 4}
#> [[1]]
#> [1] 1 2
#> 
#> [[2]]
#> [1] 3 4

Mixing a sub-system with a plain dist

compose_systems handles a mix of dist_structure inner systems and plain dist inner components. A plain dist is treated as a single- component atomic sub-system:

# Series of: (a 2-parallel block) + (a single exponential)
inner_par <- parallel_dist(list(exponential(1), exponential(1)))
outer <- series_dist(list(exponential(1), exponential(1)))

sys <- compose_systems(outer, list(inner_par, exponential(1)))
ncomponents(sys)                       # 3: two from parallel + one single
#> [1] 3
min_paths(sys)                         # {1, 3} and {2, 3}
#> [[1]]
#> [1] 1 3
#> 
#> [[2]]
#> [1] 2 3

Component 3 is the atomic component from the second outer slot; it must function jointly with either component 1 or component 2 for the system to function.

Arbitrary depth

Composition is arbitrarily nestable:

# A parallel of two different sub-systems:
sub_a <- series_dist(list(exponential(1), exponential(1)))     # simple series
sub_b <- bridge_dist(replicate(5, exponential(1), simplify = FALSE))  # bridge

outer <- parallel_dist(list(exponential(1), exponential(1)))
combined <- compose_systems(outer, list(sub_a, sub_b))

ncomponents(combined)                  # 2 + 5 = 7 total
#> [1] 7
length(min_paths(combined))            # = 1 + 4 (series has 1 path, bridge has 4)
#> [1] 5

The structural richness compounds: you can analyze the whole system via the full dist.structure protocol (sampler, surv, system_signature, importance measures, dual, etc.).

Substitution vs composition

Both produce objects that participate in the full dist.structure protocol, so further substitutions and compositions compose cleanly.