## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, echo = TRUE, comment = "#>" ) # Set to TRUE to regenerate long-running simulation results. # With run_long = FALSE, only small demos run (< 30 seconds total). run_long <- FALSE library(kofn) library(flexhaz) old_opts <- options(digits = 4) ## ----model-setup-------------------------------------------------------------- # Create an exponential parallel system model with 3 components model <- kofn(k = 3, m = 3, component = dfr_exponential()) print(model) ## ----ie-demo------------------------------------------------------------------ lam <- c(0.5, 0.3, 0.2) ie <- ie_expand(lam) # Display the expansion terms data.frame( subset_size = sapply(seq_along(ie$sign), function(k) { sum(as.integer(intToBits(k - 1L))[1:3]) }), sign = ie$sign, rate_sum = ie$rate_sum ) ## ----ie-verify---------------------------------------------------------------- t_val <- 2.0 # Direct product direct <- prod(1 - exp(-lam * t_val)) # Via IE expansion ie_val <- sum(ie$sign * exp(-ie$rate_sum * t_val)) c(direct = direct, ie_expansion = ie_val, difference = direct - ie_val) ## ----ie-functions------------------------------------------------------------- # The three w_j contributions at t = 2 sapply(1:3, function(j) w_j_exact(t_val, lam, j)) # Their sum equals the system density sum(sapply(1:3, function(j) w_j_exact(t_val, lam, j))) # System CDF and survival at t = 2 c(F_sys = F_sys_exp(t_val, lam), S_sys = S_sys_exp(t_val, lam)) ## ----loglik-demo-------------------------------------------------------------- set.seed(42) # Generate data under Scheme 0 (system lifetime only, no censoring) gen <- rdata(model) df <- gen(theta = lam, n = 50) head(df, 5) # Evaluate the log-likelihood at the true parameters ll_fn <- loglik(model) ll_fn(df, lam) # Compare with a wrong parameter vector ll_fn(df, c(1, 1, 1)) ## ----generate-data------------------------------------------------------------ set.seed(123) theta_true <- c(0.5, 0.3, 0.2) n <- 50 gen <- rdata(model) df <- gen(theta = theta_true, n = n) cat("Observations:", nrow(df), "\n") cat("Observation types:\n") table(df$omega) ## ----fit-model---------------------------------------------------------------- fit_fn <- fit(model) result <- fit_fn(df, n_starts = 1L) # MLE estimates coef(result) # Standard errors sqrt(diag(vcov(result))) # 95% confidence intervals confint(result) # Log-likelihood, AIC, BIC c(loglik = logLik(result), AIC = AIC(result), BIC = BIC(result)) ## ----fit-summary-------------------------------------------------------------- summary(result) ## ----compare-truth------------------------------------------------------------ est <- coef(result) se <- sqrt(diag(vcov(result))) ci <- confint(result) comparison <- data.frame( component = 1:3, true = theta_true, estimate = est, se = se, ci_lower = ci[, 1], ci_upper = ci[, 2], covered = theta_true >= ci[, 1] & theta_true <= ci[, 2] ) comparison ## ----permutation-demo--------------------------------------------------------- ll_fn <- loglik(model) # Original parameter order ll_original <- ll_fn(df, theta_true) # Permuted parameters: swap components 1 and 3 theta_permuted <- theta_true[c(3, 1, 2)] ll_permuted <- ll_fn(df, theta_permuted) # Reversed order theta_reversed <- rev(theta_true) ll_reversed <- ll_fn(df, theta_reversed) data.frame( ordering = c("original (0.5, 0.3, 0.2)", "permuted (0.2, 0.5, 0.3)", "reversed (0.2, 0.3, 0.5)"), loglik = c(ll_original, ll_permuted, ll_reversed), difference = c(0, ll_permuted - ll_original, ll_reversed - ll_original) ) ## ----mc-precomputed, include=FALSE, eval=!run_long---------------------------- # When run_long = FALSE, we run a small demo instead of loading precomputed # results. The full simulation (R = 100, n = 300) takes several minutes. ## ----mc-full, eval=run_long, echo=run_long, cache=TRUE------------------------ # set.seed(2026) # # R <- 100 # Monte Carlo replications # n_mc <- 300 # Sample size per replicate # alpha <- 0.05 # Significance level # # theta_true_mc <- c(0.5, 0.3, 0.2) # theta_sorted <- sort(theta_true_mc) # m_mc <- length(theta_true_mc) # # gen_mc <- rdata(model) # fit_mc <- fit(model) # # # Storage # estimates <- matrix(NA, nrow = R, ncol = m_mc) # se_hat <- matrix(NA, nrow = R, ncol = m_mc) # ci_lower <- matrix(NA, nrow = R, ncol = m_mc) # ci_upper <- matrix(NA, nrow = R, ncol = m_mc) # converged <- logical(R) # # for (r in seq_len(R)) { # df_r <- gen_mc(theta = theta_true_mc, n = n_mc) # res_r <- tryCatch(fit_mc(df_r, n_starts = 10L), error = function(e) NULL) # # if (!is.null(res_r) && !any(is.na(coef(res_r)))) { # # Sort estimates ascending for identifiability # ord <- order(coef(res_r)) # estimates[r, ] <- coef(res_r)[ord] # se_r <- sqrt(diag(vcov(res_r))) # se_hat[r, ] <- se_r[ord] # ci_r <- confint(res_r, level = 1 - alpha) # ci_lower[r, ] <- ci_r[ord, 1] # ci_upper[r, ] <- ci_r[ord, 2] # converged[r] <- TRUE # } # } # # # Save for reproducibility # saveRDS( # list(estimates = estimates, se_hat = se_hat, # ci_lower = ci_lower, ci_upper = ci_upper, # converged = converged, R = R, n_mc = n_mc, # theta_sorted = theta_sorted, alpha = alpha), # file.path(tempdir(), "precomputed_exp_parallel.rds") # ) ## ----mc-small, eval=!run_long------------------------------------------------- # Small demo: R = 5 replications for illustration (keeps build < 30 sec). # Set run_long = TRUE above for the full R = 100 simulation. set.seed(2026) R <- 3 n_mc <- 50 alpha <- 0.05 theta_true_mc <- c(0.5, 0.3, 0.2) theta_sorted <- sort(theta_true_mc) m_mc <- length(theta_true_mc) gen_mc <- rdata(model) fit_mc <- fit(model) estimates <- matrix(NA, nrow = R, ncol = m_mc) se_hat <- matrix(NA, nrow = R, ncol = m_mc) ci_lower <- matrix(NA, nrow = R, ncol = m_mc) ci_upper <- matrix(NA, nrow = R, ncol = m_mc) converged <- logical(R) for (r in seq_len(R)) { df_r <- gen_mc(theta = theta_true_mc, n = n_mc) res_r <- tryCatch(fit_mc(df_r, n_starts = 1L), error = function(e) NULL) if (!is.null(res_r) && !any(is.na(coef(res_r)))) { ord <- order(coef(res_r)) estimates[r, ] <- coef(res_r)[ord] se_r <- sqrt(diag(vcov(res_r))) se_hat[r, ] <- se_r[ord] ci_r <- confint(res_r, level = 1 - alpha) ci_lower[r, ] <- ci_r[ord, 1] ci_upper[r, ] <- ci_r[ord, 2] converged[r] <- TRUE } } ## ----mc-results--------------------------------------------------------------- ok <- converged & complete.cases(estimates) cat("Converged replications:", sum(ok), "of", R, "\n\n") est_ok <- estimates[ok, , drop = FALSE] se_ok <- se_hat[ok, , drop = FALSE] ci_lo <- ci_lower[ok, , drop = FALSE] ci_hi <- ci_upper[ok, , drop = FALSE] bias <- colMeans(est_ok) - theta_sorted rmse <- sqrt(colMeans((est_ok - matrix(theta_sorted, nrow = sum(ok), ncol = m_mc, byrow = TRUE))^2)) coverage <- colMeans( ci_lo <= matrix(theta_sorted, nrow = sum(ok), ncol = m_mc, byrow = TRUE) & ci_hi >= matrix(theta_sorted, nrow = sum(ok), ncol = m_mc, byrow = TRUE) ) mean_se <- colMeans(se_ok) mc_table <- data.frame( component = paste0("lambda_(", 1:m_mc, ")"), true = theta_sorted, mean_est = colMeans(est_ok), bias = bias, rmse = rmse, mean_se = mean_se, coverage_95 = coverage ) mc_table ## ----observe-scheme0---------------------------------------------------------- # Different censoring times obs_light <- observe_right_censor(tau = 20) # Light censoring obs_heavy <- observe_right_censor(tau = 5) # Heavy censoring obs_none <- observe_right_censor() # No censoring (tau = Inf) # Example: system fails at t = 8 obs_light(8) # exact obs_heavy(8) # right-censored at tau = 5 obs_none(8) # exact ## ----censoring-effect--------------------------------------------------------- set.seed(99) tau_values <- c(5, Inf) cat(sprintf("%-8s %6s %10s %10s %10s\n", "tau", "n_right", "est_lam1", "est_lam2", "est_lam3")) cat(strrep("-", 56), "\n") for (tau in tau_values) { obs_fn <- if (is.finite(tau)) observe_right_censor(tau) else NULL df_tau <- gen(theta = theta_true, n = 50, observe = obs_fn) n_right <- sum(df_tau$omega == "right") res_tau <- tryCatch( fit_fn(df_tau, n_starts = 1L), error = function(e) NULL ) if (!is.null(res_tau)) { est <- sort(coef(res_tau)) cat(sprintf("%-8s %6d %10.4f %10.4f %10.4f\n", if (is.finite(tau)) as.character(tau) else "Inf", n_right, est[1], est[2], est[3])) } } ## ----observe-scheme1---------------------------------------------------------- obs_periodic <- observe_periodic(delta = 2, tau = 30) # System fails at t = 7.3 -> interval-censored to (6, 8] obs_periodic(7.3) # System survives past tau = 30 -> right-censored obs_periodic(35) ## ----scheme1-demo------------------------------------------------------------- set.seed(42) df_s1 <- gen(theta = theta_true, n = 50, observe = observe_periodic(delta = 2, tau = 50)) table(df_s1$omega) # Fit under interval censoring res_s1 <- fit_fn(df_s1, n_starts = 1L) sort(coef(res_s1)) ## ----cleanup, include = FALSE------------------------------------------------- options(old_opts)