## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4 ) ## ----mixed-types-------------------------------------------------------------- library(serieshaz) disk <- dfr_weibull(shape = 2, scale = 500) mem <- dfr_exponential(0.001) psu <- dfr_gompertz(a = 0.0001, b = 0.02) server <- dfr_dist_series(list(disk, mem, psu)) ## ----hazard-decomp------------------------------------------------------------ h_disk <- component_hazard(server, 1) h_mem <- component_hazard(server, 2) h_psu <- component_hazard(server, 3) h_sys <- hazard(server) t_grid <- seq(10, 300, by = 10) cat("Time | Disk | Memory | PSU | System\n") cat("-----|----------|----------|----------|--------\n") for (t0 in c(50, 100, 150, 200, 250)) { cat(sprintf("%4d | %.6f | %.6f | %.6f | %.6f\n", t0, h_disk(t0), h_mem(t0), h_psu(t0), h_sys(t0))) } ## ----nested------------------------------------------------------------------- # CPU subsystem: two exponential failure modes cpu <- dfr_dist_series(list( dfr_exponential(0.001), # thermal failure dfr_exponential(0.0005) # electrical failure )) # Storage subsystem: Weibull wear + exponential shock storage <- dfr_dist_series(list( dfr_weibull(shape = 2, scale = 1000), dfr_exponential(0.0002) )) # Full system: CPU + storage + power supply full <- dfr_dist_series(list( cpu, storage, dfr_gompertz(a = 0.0001, b = 0.01) )) cat("Full system components:", ncomponents(full), "\n") cat("Total parameters:", length(params(full)), "\n") ## ----nested-verify------------------------------------------------------------ h_full <- hazard(full) # Manually sum all leaf hazards h_cpu1 <- component_hazard(cpu, 1) h_cpu2 <- component_hazard(cpu, 2) h_stor1 <- component_hazard(storage, 1) h_stor2 <- component_hazard(storage, 2) h_psu <- component_hazard(full, 3) t0 <- 100 nested_sum <- h_cpu1(t0) + h_cpu2(t0) + h_stor1(t0) + h_stor2(t0) + h_psu(t0) system_h <- h_full(t0) cat(sprintf("Sum of leaf hazards: %.8f\n", nested_sum)) cat(sprintf("System hazard: %.8f\n", system_h)) cat(sprintf("Difference: %.2e\n", abs(nested_sum - system_h))) ## ----custom-component--------------------------------------------------------- # Bathtub: h(t) = a/t^b + c*t^d (infant mortality + wear-out) bathtub <- dfr_dist( rate = function(t, par, ...) { a <- par[1]; b <- par[2]; c <- par[3]; d <- par[4] a * t^(-b) + c * t^d }, par = c(0.5, 0.5, 0.0001, 2) ) # Series system with bathtub + exponential random shock sys <- dfr_dist_series(list(bathtub, dfr_exponential(0.001))) h_sys <- hazard(sys) for (t0 in c(1, 10, 50, 100, 200)) { cat(sprintf("t=%3d: h_sys = %.6f\n", t0, h_sys(t0))) } ## ----custom-cumhaz------------------------------------------------------------ cat("Analytical cum_haz available:", !is.null(sys$cum_haz_rate), "\n") # The system still computes survival correctly via numerical integration S <- surv(sys) for (t0 in c(10, 50, 100)) { cat(sprintf("t=%3d: S(t) = %.6f\n", t0, S(t0))) } ## ----failure-attribution------------------------------------------------------ server <- dfr_dist_series(list( dfr_weibull(shape = 2, scale = 200), # mechanical wear dfr_exponential(0.005), # random shock dfr_gompertz(a = 0.0001, b = 0.02) # degradation )) set.seed(42) n <- 10000 mat <- sample_components(server, n = n) # System lifetime = minimum across components t_sys <- apply(mat, 1, min) # Identify the failing component for each observation failing <- apply(mat, 1, which.min) ## ----attribution-props-------------------------------------------------------- props <- table(failing) / n names(props) <- c("Weibull (wear)", "Exp (shock)", "Gompertz (degrad.)") cat("Failure attribution:\n") print(round(props, 3)) ## ----attribution-time--------------------------------------------------------- # Split into early, middle, and late failures breaks <- quantile(t_sys, probs = c(0, 1/3, 2/3, 1)) period <- cut(t_sys, breaks = breaks, labels = c("Early", "Middle", "Late"), include.lowest = TRUE) cat("\nAttribution by time period:\n") for (p in levels(period)) { idx <- which(period == p) props_p <- table(factor(failing[idx], levels = 1:3)) / length(idx) cat(sprintf(" %s (n=%d): Wear=%.1f%% Shock=%.1f%% Degrad=%.1f%%\n", p, length(idx), 100 * props_p[1], 100 * props_p[2], 100 * props_p[3])) } ## ----sensitivity-------------------------------------------------------------- server <- dfr_dist_series(list( dfr_weibull(shape = 2, scale = 100), dfr_exponential(0.01) )) S_fn <- surv(server) base_par <- params(server) # c(2, 100, 0.01) t0 <- 50 cat("Sensitivity of S(50) to Weibull scale parameter:\n") for (scale_val in c(50, 75, 100, 125, 150)) { par_mod <- base_par par_mod[2] <- scale_val # layout tells us par[2] is Weibull scale cat(sprintf(" scale = %3d: S(50) = %.4f\n", scale_val, S_fn(t0, par = par_mod))) } cat("\nSensitivity of S(50) to exponential rate:\n") for (rate_val in c(0.005, 0.01, 0.02, 0.05, 0.1)) { par_mod <- base_par par_mod[3] <- rate_val # layout tells us par[3] is exp rate cat(sprintf(" rate = %.3f: S(50) = %.4f\n", rate_val, S_fn(t0, par = par_mod))) }