## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----setup--------------------------------------------------------------------
library(dist.structure)

## -----------------------------------------------------------------------------
alarm_dist <- function(k, sensor_components, master_component) {
  m_sensors <- length(sensor_components)
  stopifnot(k >= 1L, k <= m_sensors,
            inherits(master_component, "dist"),
            all(vapply(sensor_components,
                       function(d) inherits(d, "dist"),
                       logical(1L))))
  structure(
    list(
      k = as.integer(k),
      m_sensors = as.integer(m_sensors),
      m = as.integer(m_sensors + 1L),
      components = c(sensor_components, list(master_component))
    ),
    class = c("alarm_dist", "dist_structure",
              "univariate_dist", "continuous_dist", "dist")
  )
}

## -----------------------------------------------------------------------------
ncomponents.alarm_dist <- function(x) x$m

component.alarm_dist <- function(x, j, ...) {
  stopifnot(j >= 1L, j <= x$m)
  x$components[[j]]
}

phi.alarm_dist <- function(x, state) {
  stopifnot(length(state) == x$m)
  sensor_state <- state[seq_len(x$m_sensors)]
  master_state <- state[x$m]
  as.integer(sum(sensor_state) >= x$k && master_state == 1L)
}

## -----------------------------------------------------------------------------
sensors <- replicate(4, algebraic.dist::exponential(0.5), simplify = FALSE)
master <- algebraic.dist::exponential(0.1)  # master is most reliable
alarm <- alarm_dist(k = 2L, sensors, master)

validate_dist_structure(alarm)

## -----------------------------------------------------------------------------
# Number of components
ncomponents(alarm)

# Structure function evaluation
phi(alarm, c(1, 1, 0, 0, 1))   # 2 sensors + master alive: alarms
phi(alarm, c(1, 1, 1, 1, 0))   # all sensors but no master: silent

# Minimal cut sets (derived from phi via the Berge transversal)
min_cuts(alarm)

# Critical states for component j
critical_states(alarm, 5L)  # the master: critical in every state where >= k sensors are alive

# Reliability at uniform component reliability p
reliability(alarm, 0.9)

# Distribution algebra: system survival via component composition
S <- algebraic.dist::surv(alarm)
S(c(1, 5, 10))

# Sampling: m independent component lifetimes, combined via system_lifetime
withr::with_seed(1, {
  x <- algebraic.dist::sampler(alarm)(1000)
  mean(x)
})

## -----------------------------------------------------------------------------
parallel_of_master_and_sensors <- function(sensor_components, master_component) {
  components <- c(sensor_components, list(master_component))
  m <- length(components)
  obj <- coherent_dist(
    min_paths = list(seq_len(m - 1L), m),  # all sensors as one path; master as another
    components = components,
    m = m
  )
  class(obj) <- c("master_or_sensors_dist", class(obj))
  obj
}

