Two days ago, I submitted likelihood.model to CRAN—the foundation package for composable statistical inference. Next in line: likelihood.model.series.md, which implements maximum likelihood estimation for series systems where component failure causes are masked.
This package represents the practical culmination of my master’s thesis work. Three years of theoretical development, now packaged for anyone analyzing masked failure data.
The Problem: Masked Component Failures
A series system fails when any of its \(m\) components fails. In reliability testing, you observe the system fail at time \(t\), but two layers of uncertainty obscure the full picture:
Right-censoring: Some systems are still running when testing ends—you know they survived at least until time \(\tau\), but not how much longer they would have lasted.
Masked cause of failure: When a system fails, you often can’t identify which component caused it. Diagnostic tests might narrow it down to a candidate set of possible causes, but the true failure component remains ambiguous.
This happens constantly in practice. Electronic systems fail with only board-level diagnostics. Industrial machinery fails without root-cause teardown. Medical devices fail with symptoms pointing to multiple possible subsystems.
The question: given this incomplete information, can you still estimate the lifetime distribution of each component?
The Package: Three Likelihood Models
likelihood.model.series.md provides three models with different complexity-accuracy tradeoffs:
| Model | Parameters | Use Case |
|---|---|---|
exp_series_md_c1_c2_c3 | \(m\) rates \((\lambda_1, \ldots, \lambda_m)\) | Memoryless components (constant failure rate) |
wei_series_md_c1_c2_c3 | \(2m\) params \((k_1, \beta_1, \ldots, k_m, \beta_m)\) | Weibull with per-component shapes |
wei_series_homogeneous_md_c1_c2_c3 | \(m+1\) params \((k, \beta_1, \ldots, \beta_m)\) | Weibull with shared shape parameter |
Each model implements the full inference stack: loglik(), score(), hess_loglik(), rdata(), and assumptions().
The C1-C2-C3 Conditions
The models assume three conditions that simplify the likelihood:
- C1: The failed component is in the candidate set with probability 1
- C2: Given the failed component is in the candidate set, masking probability is uniform across candidates
- C3: Masking probabilities are independent of system parameters \(\theta\)
Under these conditions, the masking mechanism factors out of the likelihood—you can estimate component parameters without modeling the diagnostic process itself. This is why the package name includes “c1_c2_c3”.
When these conditions don’t hold, see mdrelax for relaxed masking models.
Usage
Basic workflow for exponential series systems:
library(likelihood.model.series.md)
# Create the model
model <- exp_series_md_c1_c2_c3()
# Generate synthetic masked data (for validation)
gen <- rdata(model)
df <- gen(theta = c(1.0, 1.1, 0.95), n = 500, tau = 3, p = 0.3)
# Fit via MLE
solver <- fit(model)
mle <- solver(df, par = c(1, 1, 1))
# Results
mle$theta.hat # estimated failure rates
mle$sigma # asymptotic standard errors
# Log-likelihood, score, and Hessian at the MLE
ll <- loglik(model)
s <- score(model)
H <- hess_loglik(model)
ll(df, par = mle$theta.hat)
s(df, par = mle$theta.hat) # should be near zero
H(df, par = mle$theta.hat) # observed information
For Weibull components with shared shape:
wmodel <- wei_series_homogeneous_md_c1_c2_c3()
wsolver <- fit(wmodel)
# theta: (shape, scale1, scale2, ...)
wmle <- wsolver(data, par = c(1.2, 1000, 900, 850))
Validation Through Simulation
The package includes a standalone Monte Carlo framework (simulations/) for studying MLE properties. Five experiments are pre-configured:
- Bias/variance/MSE under censoring — How censoring rate affects estimation accuracy
- Masking probability sensitivity — Performance as masking becomes more severe
- Sample size requirements — How much data you need for reliable estimates
- Confidence interval coverage — Do BCa intervals achieve nominal 95% coverage?
- Model selection — AIC/BIC for choosing between exponential and Weibull
Key design features:
- Resumable/checkpointed: Atomic
.rdssaves let you stop and restart long simulations - Deterministic seeding: Reproducible results across runs
- Pre-computed results: Fast vignette builds for CRAN (no waiting 10 minutes for
R CMD check)
Simulation results feed directly into the package vignette, so the documentation reflects actual validated performance—not just theoretical claims.
The Ecosystem
This package sits at the top of a layered architecture:
algebraic.mle (on CRAN)
↓ MLE as algebraic objects with compose/transform operations
likelihood.model (submitted 2026-02-03)
↓ Composable statistical inference framework
likelihood.model.series.md (next submission)
↓ Series systems with masked component failures
The key insight: likelihood contributions compose. When observations are independent, the total log-likelihood is a sum of individual contributions. This package provides the contributions for masked series system data; likelihood.model provides the composition machinery; algebraic.mle provides the algebra for working with fitted models.
This design means you’re not locked into my specific models. Define your own likelihood contributions and they plug into the same infrastructure.
Related Packages
| Package | Role |
|---|---|
| algebraic.mle | Core MLE algebra (CRAN) |
| algebraic.dist | Distributions as algebraic objects (CRAN) |
| likelihood.model | Composable inference framework |
| wei.series.md.c1.c2.c3 | Weibull-specific implementations |
| mdrelax | Relaxed masking conditions (C2/C3 violations) |
| md.tools | Masked data encoding/decoding utilities |
CRAN Journey
The submission timeline:
- algebraic.mle: On CRAN since 2024
- algebraic.dist: On CRAN since 2024
- likelihood.model: Submitted 2026-02-03 (2 days ago)
- likelihood.model.series.md: Next submission after likelihood.model is accepted
CRAN-ready features:
- Fast vignette builds using pre-computed simulation results
- Clean
R CMD checkwith no notes or warnings - Documented S3 generics with complete examples
- Minimal dependencies (mostly base R + likelihood.model ecosystem)
Installation
Available now from r-universe:
install.packages("likelihood.model.series.md",
repos = "https://queelius.r-universe.dev")
Or from GitHub:
# install.packages("devtools")
devtools::install_github("queelius/likelihood.model.series.md")
Documentation: queelius.github.io/likelihood.model.series.md
From Thesis to Tools
Three years ago, I was deriving likelihood functions on paper while fighting cancer. The math was interesting—masked data creates a mixture model where the component cause is a latent variable—but the goal was always practical: give engineers tools to estimate component reliability from incomplete field data.
This package is that tool. If you’re analyzing series system reliability with masked failure causes, try it. File issues if something breaks. The technical paper has the mathematical details; the vignette has worked examples.
Watch for the CRAN release once likelihood.model is accepted.
Resources:
Discussion