| Title: | Maximum Likelihood Estimation for k-out-of-n System Data |
|---|---|
| Description: | Maximum likelihood estimation of component lifetime parameters from system-level observations of k-out-of-n systems. Supports exponential and Weibull component distributions under multiple observation schemes: Scheme 0 (system lifetime only), Scheme 1 (periodic inspection), and Scheme 2 (complete monitoring). Provides an EM algorithm for Weibull parallel systems and Fisher information comparison across schemes. The k-out-of-n framework unifies series (k=1) and parallel (k=m) systems as a censoring problem on component lifetimes. Conforms to the 'likelihood.model' generics and returns fitted objects compatible with 'algebraic.mle'. The data-generating process and topology infrastructure (system survival, density, signature, structure function, importance measures) are delegated to the 'dist.structure' package; kofn focuses exclusively on inference for the k-out-of-n family. |
| Authors: | Alexander Towell [aut, cre] (ORCID: <https://orcid.org/0000-0001-6443-9897>) |
| Maintainer: | Alexander Towell <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.4.0 |
| Built: | 2026-05-24 09:31:26 UTC |
| Source: | https://github.com/queelius/kofn |
Returns a character vector listing the assumptions made by the exponential k-out-of-n likelihood model.
## S3 method for class 'exp_kofn' assumptions(model, ...)## S3 method for class 'exp_kofn' assumptions(model, ...)
model |
An |
... |
Additional arguments (ignored). |
Character vector of assumptions.
model <- kofn(k = 3, m = 3, component = dfr_exponential()) assumptions(model)model <- kofn(k = 3, m = 3, component = dfr_exponential()) assumptions(model)
Returns a list of assumptions made by the model.
## S3 method for class 'wei_kofn' assumptions(model, ...)## S3 method for class 'wei_kofn' assumptions(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
A character vector of assumptions.
model <- kofn(k = 2, m = 2, component = dfr_weibull()) assumptions(model)model <- kofn(k = 2, m = 2, component = dfr_weibull()) assumptions(model)
For a given parameter configuration, computes the observed Fisher information under Scheme 0 (system only), Scheme 1 (periodic inspection), and Scheme 2 (complete component data) via simulation.
compare_fisher_info( shapes = NULL, scales = NULL, rates = NULL, n = 200L, delta = 1, n_rep = 50L, component = dfr_exponential() )compare_fisher_info( shapes = NULL, scales = NULL, rates = NULL, n = 200L, delta = 1, n_rep = 50L, component = dfr_exponential() )
shapes |
Numeric vector. Weibull shape parameters (Weibull only,
or |
scales |
Numeric vector. Weibull scale parameters (Weibull only,
or |
rates |
Numeric vector. Exponential rate parameters (exponential
only, alternative to |
n |
Integer. Sample size per replicate. |
delta |
Numeric scalar. Inspection interval width for Scheme 1. |
n_rep |
Integer. Number of Monte Carlo replicates. |
component |
A |
The determinant of the observed information matrix is used as a scalar summary. Efficiency ratios indicate relative information content: a ratio less than 1 means the denominator scheme carries more information.
For Scheme 2 (complete data), the Fisher information is computed analytically:
Exponential: (diagonal).
Weibull: Block-diagonal with per-component 2x2 Fisher information matrices using the standard Weibull FIM formulas.
For Schemes 0 and 1, the observed information is computed numerically
via numDeriv::hessian of the negative log-likelihood evaluated
at the true parameter values.
A list with components:
scheme0_detNumeric vector of Scheme 0 information
determinants (length n_rep).
scheme1_detNumeric vector of Scheme 1 information determinants.
scheme2_detNumeric vector of Scheme 2 (complete data) information determinants.
median_detNamed numeric vector of median determinants across schemes.
efficiency_01Ratio of median Scheme 0 to Scheme 1 determinant (< 1 means Scheme 1 is more informative).
efficiency_02Ratio of median Scheme 0 to Scheme 2 determinant.
efficiency_12Ratio of median Scheme 1 to Scheme 2 determinant.
n_validNamed integer vector of valid (non-NA) replicate counts per scheme.
set.seed(1) result <- compare_fisher_info(rates = c(1, 2), n = 50, delta = 1.0, n_rep = 5) result$median_det result$efficiency_01 # Scheme 0 vs Scheme 1set.seed(1) result <- compare_fisher_info(rates = c(1, 2), n = 50, delta = 1.0, n_rep = 5) result$median_det result$efficiency_01 # Scheme 0 vs Scheme 1
Computes using the
inclusion-exclusion expansion.
F_sys_exp(t, par)F_sys_exp(t, par)
t |
Scalar time point (non-negative numeric). |
par |
Numeric vector of rates (length m). |
Scalar CDF value .
S_sys_exp() for the survival function.
F_sys_exp(1, c(1, 2)) # P(T_sys <= 1) for 2-component parallelF_sys_exp(1, c(1, 2)) # P(T_sys <= 1) for 2-component parallel
Returns a closure that fits the model to Scheme 1 data using multi-start optimization with L-BFGS-B and Nelder-Mead fallback.
fit_scheme1(model, ...)fit_scheme1(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
The solver uses L-BFGS-B as the primary optimization method with positivity constraints, falling back to Nelder-Mead on the log-parameter scale if L-BFGS-B fails to converge.
Standard errors are computed from the numerical Hessian at the MLE.
A function function(df, par0 = NULL, n_starts = 5L) that
returns a fisher_mle object (from the likelihood.model package).
model <- kofn(k = 2, m = 2, component = dfr_exponential()) set.seed(42) df <- rdata_scheme1(model)(c(1, 2), n = 50, delta = 1.0) result <- fit_scheme1(model)(df) coef(result)model <- kofn(k = 2, m = 2, component = dfr_exponential()) set.seed(42) df <- rdata_scheme1(model)(c(1, 2), n = 50, delta = 1.0) result <- fit_scheme1(model)(df) coef(result)
Returns a closure function(df, par0, n_starts) that computes the
maximum likelihood estimate of the component rate parameters.
## S3 method for class 'exp_kofn' fit(object, ...)## S3 method for class 'exp_kofn' fit(object, ...)
object |
An |
... |
Additional arguments (ignored). |
Uses multi-start optimization with L-BFGS-B as primary solver and Nelder-Mead on the log-scale as fallback. Standard errors are computed from the observed Fisher information (negative Hessian) at the MLE.
A function function(df, par0 = NULL, n_starts = 5L) returning
a fisher_mle object (from likelihood.model).
model <- kofn(k = 2, m = 2, component = dfr_exponential()) set.seed(42) df <- rdata(model)(c(1, 2), n = 50) result <- fit(model)(df) coef(result)model <- kofn(k = 2, m = 2, component = dfr_exponential()) set.seed(42) df <- rdata(model)(c(1, 2), n = 50) result <- fit(model)(df) coef(result)
Returns a closure that fits the model to data. Two methods are available:
## S3 method for class 'wei_kofn' fit(object, ...)## S3 method for class 'wei_kofn' fit(object, ...)
object |
A |
... |
Additional arguments (currently unused). |
"em"EM algorithm for parallel systems (k = m only). Treats the identity of the last-failing component as latent data. Uses truncated Weibull moments for the E-step and profile optimization over shape with closed-form scale for the M-step.
"mle"Direct MLE via L-BFGS-B with Nelder-Mead fallback. Works for any k-out-of-n structure.
The returned solver accepts these additional arguments:
par0Initial parameter vector (length 2*m, interleaved
shape/scale). If NULL, method-of-moments initialization is used.
n_startsNumber of multi-start attempts (default: 5).
tolConvergence tolerance for EM (default: 1e-8).
maxiterMaximum EM iterations (default: 2000).
shape_boundsBounds for shape optimization in EM (default:
c(0.05, 15)).
verbosePrint iteration progress (default: FALSE).
A function function(df, par0, ...) that returns a
fisher_mle object (from the likelihood.model package).
model <- kofn(k = 2, m = 2, component = dfr_weibull()) set.seed(42) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 50) result <- fit(model)(df) coef(result)model <- kofn(k = 2, m = 2, component = dfr_weibull()) set.seed(42) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 50) result <- fit(model)(df) coef(result)
Returns a closure function(df, par) that computes the Hessian matrix
of the log-likelihood with respect to the rate parameters.
## S3 method for class 'exp_kofn' hess_loglik(model, ...)## S3 method for class 'exp_kofn' hess_loglik(model, ...)
model |
An |
... |
Additional arguments (ignored). |
Uses numerical differentiation via numDeriv::hessian() applied to the
log-likelihood closure.
A function function(df, par) returning an m x m Hessian matrix.
model <- kofn(k = 2, m = 2, component = dfr_exponential()) H <- hess_loglik(model) set.seed(1) df <- rdata(model)(c(1, 2), n = 30) H(df, c(1, 2)) # 2x2 Hessian matrixmodel <- kofn(k = 2, m = 2, component = dfr_exponential()) H <- hess_loglik(model) set.seed(1) df <- rdata(model)(c(1, 2), n = 30) H(df, c(1, 2)) # 2x2 Hessian matrix
Returns a closure that computes the Hessian matrix of the log-likelihood
via numerical differentiation using numDeriv::hessian.
## S3 method for class 'wei_kofn' hess_loglik(model, ...)## S3 method for class 'wei_kofn' hess_loglik(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
A function function(df, par) returning a square matrix
(the Hessian of the log-likelihood).
model <- kofn(k = 2, m = 2, component = dfr_weibull()) H <- hess_loglik(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) H(df, c(1.5, 2.0, 2.0, 3.0)) # 4x4 Hessian matrixmodel <- kofn(k = 2, m = 2, component = dfr_weibull()) H <- hess_loglik(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) H(df, c(1.5, 2.0, 2.0, 3.0)) # 4x4 Hessian matrix
For a set of exponential rates lam, computes the inclusion-exclusion
expansion of .
ie_expand(lam)ie_expand(lam)
lam |
Numeric vector of positive rates (one per component). |
Returns sign and rate-sum vectors such that:
The number of terms is where is length(lam).
A list with elements:
Integer vector of signs ( or ).
Numeric vector of summed rates for each term.
ie <- ie_expand(c(1, 2)) # Product: (1 - exp(-t)) * (1 - exp(-2t)) # = 1 - exp(-t) - exp(-2t) + exp(-3t) ie$sign # c(1, -1, -1, 1) ie$rate_sum # c(0, 1, 2, 3)ie <- ie_expand(c(1, 2)) # Product: (1 - exp(-t)) * (1 - exp(-2t)) # = 1 - exp(-t) - exp(-2t) + exp(-3t) ie$sign # c(1, -1, -1, 1) ie$rate_sum # c(0, 1, 2, 3)
Test if an object is a kofn model
is_kofn(x)is_kofn(x)
x |
An object to test. |
Logical indicating whether x inherits from "kofn".
is_kofn(kofn(k = 3, m = 3, component = dfr_exponential())) is_kofn(42)is_kofn(kofn(k = 3, m = 3, component = dfr_exponential())) is_kofn(42)
Constructs a likelihood model for component lifetime estimation from
k-out-of-n system data. The system fails when k components have
failed: k=1 is a series system (one failure kills it),
k=m is a parallel system (all must fail).
kofn( k = 1L, m = 2L, component = dfr_exponential(), method = "mle", lifetime = "t", omega = "omega", lifetime_upper = "t_upper" )kofn( k = 1L, m = 2L, component = dfr_exponential(), method = "mle", lifetime = "t", omega = "omega", lifetime_upper = "t_upper" )
k |
System parameter: system fails when k components have failed.
|
m |
Number of components. |
component |
A |
method |
Estimation method: |
lifetime |
Column name for system lifetime (default |
omega |
Column name for observation type (default |
lifetime_upper |
Column name for interval upper bound (default
|
This model satisfies the likelihood_model concept from the
likelihood.model package by providing methods for
loglik,
score, and
hess_loglik.
The class hierarchy is:
"exp_kofn" or "wei_kofn" (distribution-specific dispatch)
"kofn" (shared methods)
"likelihood_model" (generic inference infrastructure)
The concrete subclass is determined by the type of component.
The current closed-form machinery is homogeneous: all m components
share the same distribution family, and component acts as a
prototype for that family.
For non-k-of-n topologies (bridges, arbitrary coherent systems), use
coherent_dist or one of the topology
shortcuts in dist.structure directly. kofn is exclusively for
the k-out-of-n family.
An S3 object of class c("exp_kofn"/"wei_kofn", "kofn",
"likelihood_model").
# Parallel system with 3 exponential components (k = m) model <- kofn(k = 3, m = 3, component = dfr_exponential()) print(model) # Series system (k = 1) model_series <- kofn(k = 1, m = 4, component = dfr_exponential()) # Weibull parallel system with EM estimation model_wei <- kofn(k = 2, m = 2, component = dfr_weibull(), method = "em")# Parallel system with 3 exponential components (k = m) model <- kofn(k = 3, m = 3, component = dfr_exponential()) print(model) # Series system (k = 1) model_series <- kofn(k = 1, m = 4, component = dfr_exponential()) # Weibull parallel system with EM estimation model_wei <- kofn(k = 2, m = 2, component = dfr_weibull(), method = "em")
Computes the log-likelihood for a k-out-of-n system with candidate
failed sets (generalized masking). The data frame must contain columns
for system lifetime, observation type, and Boolean candidate set
indicators (c1, c2, ..., cm).
loglik_masked(model, candset = "c", ...)loglik_masked(model, candset = "c", ...)
model |
A |
candset |
Prefix for candidate set columns (default |
... |
Additional arguments (currently unused). |
At system failure, k components have failed. The candidate set
C_i is a superset of the true failed set. The likelihood
marginalizes over all
possible k-subsets.
For series systems (k = 1), this reduces to the standard
masked cause-of-failure likelihood .
For parallel systems (k = m), the candidate set must be
{1, ..., m} and the likelihood equals the system density.
The function uses the exponential or Weibull distribution functions
directly (not the IE expansion), so it works for any family supported
by parse_params.
A function function(df, par) returning a scalar
log-likelihood.
# 2-out-of-4 system with candidate failed sets model <- kofn(k = 2, m = 4, component = dfr_exponential()) ll <- loglik_masked(model) # Manually construct masked data: k=2 failed, C = {1,2,3} df <- data.frame( t = 1.5, omega = "exact", c1 = TRUE, c2 = TRUE, c3 = TRUE, c4 = FALSE ) ll(df, c(1, 0.8, 0.6, 0.4))# 2-out-of-4 system with candidate failed sets model <- kofn(k = 2, m = 4, component = dfr_exponential()) ll <- loglik_masked(model) # Manually construct masked data: k=2 failed, C = {1,2,3} df <- data.frame( t = 1.5, omega = "exact", c1 = TRUE, c2 = TRUE, c3 = TRUE, c4 = FALSE ) ll(df, c(1, 0.8, 0.6, 0.4))
Returns a closure that computes the log-likelihood under Scheme 1 observation. The likelihood combines the system density at the exact system failure time with interval-censored component contributions.
loglik_scheme1(model, ...)loglik_scheme1(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
The log-likelihood for observation i is:
where is the parallel system density and
is the inspection interval containing
component j's failure time.
A function function(df, par) returning a scalar
log-likelihood.
model <- kofn(k = 2, m = 2, component = dfr_exponential()) ll <- loglik_scheme1(model) set.seed(1) df <- rdata_scheme1(model)(c(1, 2), n = 30, delta = 1.0) ll(df, c(1, 2))model <- kofn(k = 2, m = 2, component = dfr_exponential()) ll <- loglik_scheme1(model) set.seed(1) df <- rdata_scheme1(model)(c(1, 2), n = 30, delta = 1.0) ll(df, c(1, 2))
Returns a closure function(df, par) that computes the log-likelihood of
exponential component rates given system-level data.
## S3 method for class 'exp_kofn' loglik(model, ...)## S3 method for class 'exp_kofn' loglik(model, ...)
model |
An |
... |
Additional arguments (ignored). |
For parallel systems (k = m), the closed-form IE expansion is used,
supporting all four observation types: exact, right, left, and interval
censored. For general k-out-of-n systems, the per-observation
contributions are computed via dist.structure::exp_kofn(k, par) and
the algebraic.dist generics density, surv, and cdf.
A function function(df, par) where df is a data frame with
columns for lifetime, observation type, and (for interval-censored)
upper bounds, and par is a numeric vector of m component rates.
model <- kofn(k = 3, m = 3, component = dfr_exponential()) ll <- loglik(model) set.seed(1) df <- rdata(model)(c(1, 2, 3), n = 30) ll(df, c(1, 2, 3))model <- kofn(k = 3, m = 3, component = dfr_exponential()) ll <- loglik(model) set.seed(1) df <- rdata(model)(c(1, 2, 3), n = 30) ll(df, c(1, 2, 3))
Returns a closure function(df, par) that computes the log-likelihood
for a Weibull k-out-of-n system given data and parameters.
## S3 method for class 'wei_kofn' loglik(model, ...)## S3 method for class 'wei_kofn' loglik(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
For parallel systems (k = m), uses the direct Weibull system density
.
Supports "exact" and "right" observation types.
Left and interval censoring are not supported for Weibull (no IE
expansion); use the exponential model or Scheme 1 for those cases.
For general k, delegates per-observation to
dist.structure::wei_kofn(k, shapes, scales) via the
algebraic.dist generics density, surv, and cdf.
A function function(df, par) returning a scalar log-likelihood.
model <- kofn(k = 2, m = 2, component = dfr_weibull()) ll <- loglik(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) ll(df, c(1.5, 2.0, 2.0, 3.0))model <- kofn(k = 2, m = 2, component = dfr_weibull()) ll <- loglik(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) ll(df, c(1.5, 2.0, 2.0, 3.0))
Returns the number of components m in the k-out-of-n system.
## S3 method for class 'kofn' ncomponents(x, ...)## S3 method for class 'kofn' ncomponents(x, ...)
x |
A |
... |
Additional arguments (ignored). |
Integer number of components.
ncomponents(kofn(k = 5, m = 5, component = dfr_exponential()))ncomponents(kofn(k = 5, m = 5, component = dfr_exponential()))
Creates an observation functor that records the exact failure time with no censoring. This is the trivial case — included for completeness and for explicit use in Fisher information comparisons.
observe_exact()observe_exact()
Observation functor: function(t_true) returning a list
with t (exact time), omega ("exact"), and
t_upper (NA).
obs <- observe_exact() obs(42.5) # list(t = 42.5, omega = "exact", t_upper = NA)obs <- observe_exact() obs(42.5) # list(t = 42.5, omega = "exact", t_upper = NA)
Creates an observation functor that places all failure times into a
fixed window [a, b). Systems failing within the window are
interval-censored; systems failing outside are observed exactly.
observe_interval_censor(a, b)observe_interval_censor(a, b)
a |
Lower bound of censoring window (non-negative numeric). |
b |
Upper bound of censoring window (positive numeric, |
For regular grids, use observe_periodic instead.
Observation functor: function(t_true) returning a list
with t, omega ("interval" or "exact"),
and t_upper.
obs <- observe_interval_censor(a = 5, b = 10) obs(7) # interval: list(t = 5, omega = "interval", t_upper = 10) obs(3) # exact: list(t = 3, omega = "exact", t_upper = NA) obs(12) # exact: list(t = 12, omega = "exact", t_upper = NA)obs <- observe_interval_censor(a = 5, b = 10) obs(7) # interval: list(t = 5, omega = "interval", t_upper = 10) obs(3) # exact: list(t = 3, omega = "exact", t_upper = NA) obs(12) # exact: list(t = 12, omega = "exact", t_upper = NA)
Creates an observation functor that applies left-censoring at time
tau. Systems that fail after tau are observed exactly;
systems that fail before tau are left-censored (we only know
T < tau).
observe_left_censor(tau)observe_left_censor(tau)
tau |
Censoring time (positive numeric). |
Observation functor: function(t_true) returning a list
with t, omega ("left" or "exact"), and
t_upper (NA).
obs <- observe_left_censor(tau = 10) obs(5) # left: list(t = 10, omega = "left", t_upper = NA) obs(15) # exact: list(t = 15, omega = "exact", t_upper = NA)obs <- observe_left_censor(tau = 10) obs(5) # left: list(t = 10, omega = "left", t_upper = NA) obs(15) # exact: list(t = 15, omega = "exact", t_upper = NA)
Creates an observation functor that randomly selects from a set of observation schemes for each observation. This models heterogeneous monitoring environments where different units may be observed under different protocols.
observe_mixture(..., weights = NULL)observe_mixture(..., weights = NULL)
... |
Observation functors (created by |
weights |
Mixing probabilities (numeric vector). If |
Observation functor: function(t_true) that randomly
selects a constituent scheme and returns its output.
obs <- observe_mixture( observe_right_censor(tau = 100), observe_periodic(delta = 10, tau = 100), weights = c(0.7, 0.3) ) set.seed(42) obs(30)obs <- observe_mixture( observe_right_censor(tau = 100), observe_periodic(delta = 10, tau = 100), weights = c(0.7, 0.3) ) set.seed(42) obs(30)
Creates an observation functor for periodic inspections at intervals
of width delta. The failure time is known only to lie within
the inspection interval containing it (interval-censored). Systems
surviving past tau are right-censored.
observe_periodic(delta, tau = Inf)observe_periodic(delta, tau = Inf)
delta |
Inspection interval width (positive numeric). |
tau |
Study end time / right-censoring time (positive numeric or
|
Observation functor: function(t_true) returning a list
with t (interval lower bound or tau),
omega ("interval" or "right"), and
t_upper (interval upper bound or NA).
obs <- observe_periodic(delta = 10, tau = 100) obs(25) # interval: list(t = 20, omega = "interval", t_upper = 30) obs(150) # right: list(t = 100, omega = "right", t_upper = NA)obs <- observe_periodic(delta = 10, tau = 100) obs(25) # interval: list(t = 20, omega = "interval", t_upper = 30) obs(150) # right: list(t = 100, omega = "right", t_upper = NA)
Creates an observation functor that applies right-censoring at time
tau. Systems that fail before tau are observed exactly;
systems surviving past tau are right-censored.
observe_right_censor(tau = Inf)observe_right_censor(tau = Inf)
tau |
Censoring time (positive numeric, or |
Observation functor: function(t_true) returning a list
with t, omega ("exact" or "right"), and
t_upper (NA).
obs <- observe_right_censor(tau = 100) obs(50) # exact: list(t = 50, omega = "exact", t_upper = NA) obs(150) # right: list(t = 100, omega = "right", t_upper = NA) # No censoring obs_all <- observe_right_censor(tau = Inf) obs_all(999) # exact: list(t = 999, omega = "exact", t_upper = NA)obs <- observe_right_censor(tau = 100) obs(50) # exact: list(t = 50, omega = "exact", t_upper = NA) obs(150) # right: list(t = 100, omega = "right", t_upper = NA) # No censoring obs_all <- observe_right_censor(tau = Inf) obs_all(999) # exact: list(t = 999, omega = "exact", t_upper = NA)
Displays a human-readable summary of the k-out-of-n system model, including system type, component distribution, estimation method, and column name conventions.
## S3 method for class 'kofn' print(x, ...)## S3 method for class 'kofn' print(x, ...)
x |
A |
... |
Additional arguments (ignored). |
The model object, invisibly.
print(kofn(k = 3, m = 3, component = dfr_exponential()))print(kofn(k = 3, m = 3, component = dfr_exponential()))
Returns a closure that generates system lifetime data with candidate
failed sets. The true failed set (the k components that failed by
T_sys) is always included in the candidate set. Additional non-failed
components are included independently with probability p_mask.
rdata_masked(model, candset = "c", ...)rdata_masked(model, candset = "c", ...)
model |
A |
candset |
Prefix for candidate set columns (default |
... |
Additional arguments (currently unused). |
A function function(theta, n, p_mask = 0, observe = NULL)
returning a data frame with columns for system lifetime, observation
type, and Boolean candidate set indicators.
model <- kofn(k = 2, m = 4, component = dfr_exponential()) gen <- rdata_masked(model) set.seed(42) df <- gen(theta = c(1, 0.8, 0.6, 0.4), n = 10, p_mask = 0.3) head(df)model <- kofn(k = 2, m = 4, component = dfr_exponential()) gen <- rdata_masked(model) set.seed(42) df <- gen(theta = c(1, 0.8, 0.6, 0.4), n = 10, p_mask = 0.3) head(df)
Returns a closure that generates k-out-of-n system data under periodic inspection. Each observation yields the exact system failure time and interval-censored component failure times.
rdata_scheme1(model, ...)rdata_scheme1(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
Note: The Scheme 1 likelihood uses a composite approximation that
treats the system density and component interval contributions as
independent. This works well for k >= 2 but is unreliable for
series systems (k = 1), where surviving components' intervals should
be conditioned on survival past T_sys. For series systems, use the
maskedcauses package instead.
A function function(theta, n, delta) returning a data frame
with columns:
tSystem failure time (exact).
comp_lower_jLower bound of inspection interval for component j.
comp_upper_jUpper bound of inspection interval for component j.
The data frame has attributes comp_times (true component times),
delta (inspection interval), and par (true parameters).
model <- kofn(k = 2, m = 2, component = dfr_exponential()) gen <- rdata_scheme1(model) set.seed(1) df <- gen(theta = c(1, 2), n = 20, delta = 1.0) head(df)model <- kofn(k = 2, m = 2, component = dfr_exponential()) gen <- rdata_scheme1(model) set.seed(1) df <- gen(theta = c(1, 2), n = 20, delta = 1.0) head(df)
Returns a closure that generates random system-level data from the exponential k-out-of-n data-generating process.
## S3 method for class 'exp_kofn' rdata(model, ...)## S3 method for class 'exp_kofn' rdata(model, ...)
model |
An |
... |
Additional arguments (ignored). |
Workflow:
Generate i.i.d. exponential component lifetimes.
Compute system lifetime as the (m - k + 1)-th order statistic.
Apply the observation functor (exact observation by default).
A function function(theta, n, observe = NULL)
returning a data frame with columns t (system lifetime) and
omega (observation type). Latent component lifetimes, true
critical component, and the true parameters are stored as attributes.
model <- kofn(k = 3, m = 3, component = dfr_exponential()) gen <- rdata(model) set.seed(1) df <- gen(theta = c(1, 2, 3), n = 20) head(df) # With right-censoring df2 <- gen(c(1, 2, 3), n = 20, observe = observe_right_censor(tau = 2)) table(df2$omega)model <- kofn(k = 3, m = 3, component = dfr_exponential()) gen <- rdata(model) set.seed(1) df <- gen(theta = c(1, 2, 3), n = 20) head(df) # With right-censoring df2 <- gen(c(1, 2, 3), n = 20, observe = observe_right_censor(tau = 2)) table(df2$omega)
Returns a closure that generates system lifetime data with observation
scheme support. Component lifetimes are Weibull-distributed with
parameters specified by theta (interleaved shape/scale).
## S3 method for class 'wei_kofn' rdata(model, ...)## S3 method for class 'wei_kofn' rdata(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
The interface matches rdata.exp_kofn: the returned closure
accepts an observe functor for observation schemes (censoring,
periodic inspection, etc.). The output includes an omega column.
A function function(theta, n, observe = NULL)
returning a data frame with columns t (system lifetimes) and
omega (observation type). Attributes:
comp_timesn x m matrix of component lifetimes.
parThe parameter vector used for generation.
model <- kofn(k = 2, m = 2, component = dfr_weibull()) gen <- rdata(model) set.seed(42) df <- gen(theta = c(1.5, 2.0, 2.0, 3.0), n = 50) head(df) # With right-censoring df_cens <- gen(c(1.5, 2.0, 2.0, 3.0), 50, observe = observe_right_censor(tau = 3)) table(df_cens$omega)model <- kofn(k = 2, m = 2, component = dfr_weibull()) gen <- rdata(model) set.seed(42) df <- gen(theta = c(1.5, 2.0, 2.0, 3.0), n = 50) head(df) # With right-censoring df_cens <- gen(c(1.5, 2.0, 2.0, 3.0), 50, observe = observe_right_censor(tau = 3)) table(df_cens$omega)
Computes for a parallel system with
exponential components.
S_sys_exp(t, par)S_sys_exp(t, par)
t |
Scalar time point (non-negative numeric). |
par |
Numeric vector of rates (length m). |
Scalar survival probability .
F_sys_exp() for the CDF.
S_sys_exp(1, c(1, 2)) # P(T_sys > 1) for 2-component parallelS_sys_exp(1, c(1, 2)) # P(T_sys > 1) for 2-component parallel
Returns a closure function(df, par) that computes the gradient of
the log-likelihood with respect to the rate parameters.
## S3 method for class 'exp_kofn' score(model, ...)## S3 method for class 'exp_kofn' score(model, ...)
model |
An |
... |
Additional arguments (ignored). |
Uses numerical differentiation via numDeriv::grad() applied to the
log-likelihood closure.
A function function(df, par) returning a numeric vector of
length m (the score vector).
model <- kofn(k = 2, m = 2, component = dfr_exponential()) sc <- score(model) set.seed(1) df <- rdata(model)(c(1, 2), n = 30) sc(df, c(1, 2)) # gradient at true parametersmodel <- kofn(k = 2, m = 2, component = dfr_exponential()) sc <- score(model) set.seed(1) df <- rdata(model)(c(1, 2), n = 30) sc(df, c(1, 2)) # gradient at true parameters
Returns a closure that computes the score (gradient of log-likelihood)
via numerical differentiation using numDeriv::grad.
## S3 method for class 'wei_kofn' score(model, ...)## S3 method for class 'wei_kofn' score(model, ...)
model |
A |
... |
Additional arguments (currently unused). |
A function function(df, par) returning a numeric vector
(the gradient of the log-likelihood).
model <- kofn(k = 2, m = 2, component = dfr_weibull()) sc <- score(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) sc(df, c(1.5, 2.0, 2.0, 3.0))model <- kofn(k = 2, m = 2, component = dfr_weibull()) sc <- score(model) set.seed(1) df <- rdata(model)(c(1.5, 2.0, 2.0, 3.0), n = 30) sc(df, c(1.5, 2.0, 2.0, 3.0))
Multi-start optimization via compositional.mle: L-BFGS-B
with positivity constraints as the primary solver, Nelder-Mead on
the log-parameter scale as fallback. Runs from n_starts
random perturbations of par0 and returns the best result.
solve_mle(neg_ll, par0, n_par, n_starts = 5L, nobs = NULL)solve_mle(neg_ll, par0, n_par, n_starts = 5L, nobs = NULL)
neg_ll |
Function of |
par0 |
Numeric vector of initial parameter values. |
n_par |
Integer number of parameters. |
n_starts |
Integer number of random restarts (default 5). |
nobs |
Integer number of observations. |
An mle_numerical result object (from algebraic.mle)
with coef(), vcov(), logLik(), etc. Returns
NULL if all starts fail.
# Fit a simple exponential rate from positive data x <- rexp(100, rate = 0.5) neg_ll <- function(rate) -sum(dexp(x, rate, log = TRUE)) fit <- solve_mle(neg_ll, par0 = 1, n_par = 1, nobs = length(x)) coef(fit)# Fit a simple exponential rate from positive data x <- rexp(100, rate = 0.5) neg_ll <- function(rate) -sum(dexp(x, rate, log = TRUE)) fit <- solve_mle(neg_ll, par0 = 1, n_par = 1, nobs = length(x)) coef(fit)
Computes for
simultaneously for a vector of truncation points.
trunc_log_moment_vec(v_max_vec, alpha, beta)trunc_log_moment_vec(v_max_vec, alpha, beta)
v_max_vec |
Numeric vector. Precomputed values of |
alpha |
Numeric scalar. Weibull shape parameter. |
beta |
Numeric scalar. Weibull scale parameter. |
Uses the identity:
where and .
The inner expectation is computed via
central finite difference of the lower incomplete gamma function at .
For very small (below 1e-10), the asymptotic
approximation is used.
For large where numerical issues arise, the untruncated
moment is used as fallback,
where is the digamma function.
Numeric vector of values, same length as
v_max_vec.
# E[log T | T < t] for Weibull(shape=2, scale=1) at t = 0.5, 1.0, 2.0 v_max <- (c(0.5, 1.0, 2.0) / 1)^2 trunc_log_moment_vec(v_max_vec = v_max, alpha = 2, beta = 1)# E[log T | T < t] for Weibull(shape=2, scale=1) at t = 0.5, 1.0, 2.0 v_max <- (c(0.5, 1.0, 2.0) / 1)^2 trunc_log_moment_vec(v_max_vec = v_max, alpha = 2, beta = 1)
Convenience wrapper around trunc_pow_moment_vec() for a single truncation
point. Computes for .
trunc_pow_moment(k, t, alpha, beta)trunc_pow_moment(k, t, alpha, beta)
k |
Numeric scalar. Power parameter (can be non-integer). |
t |
Numeric scalar. Truncation point (positive). |
alpha |
Numeric scalar. Weibull shape parameter. |
beta |
Numeric scalar. Weibull scale parameter. |
Numeric scalar .
trunc_pow_moment_vec() for the vectorized version.
# E[T^1 | T < 2] for Weibull(shape=1.5, scale=1) trunc_pow_moment(k = 1, t = 2, alpha = 1.5, beta = 1)# E[T^1 | T < 2] for Weibull(shape=1.5, scale=1) trunc_pow_moment(k = 1, t = 2, alpha = 1.5, beta = 1)
Computes for
simultaneously for a vector of truncation points.
trunc_pow_moment_vec(k, v_max_vec, alpha, beta)trunc_pow_moment_vec(k, v_max_vec, alpha, beta)
k |
Numeric scalar. Power parameter (can be non-integer). |
v_max_vec |
Numeric vector. Precomputed values of |
alpha |
Numeric scalar. Weibull shape parameter. |
beta |
Numeric scalar. Weibull scale parameter. |
Uses the substitution , so that
and the truncation becomes
. The result is:
where is the lower incomplete gamma function.
Computation is done in log-space for numerical stability.
For very small (below 1e-12), the asymptotic
approximation is used
to avoid numerical issues.
Numeric vector of values, same length as
v_max_vec.
# E[T^2 | T < t] for Weibull(shape=2, scale=1) at t = 0.5, 1.0, 2.0 v_max <- (c(0.5, 1.0, 2.0) / 1)^2 trunc_pow_moment_vec(k = 2, v_max_vec = v_max, alpha = 2, beta = 1)# E[T^2 | T < t] for Weibull(shape=2, scale=1) at t = 0.5, 1.0, 2.0 v_max <- (c(0.5, 1.0, 2.0) / 1)^2 trunc_pow_moment_vec(k = 2, v_max_vec = v_max, alpha = 2, beta = 1)
For component j with rate and other rates
:
w_j_exact(t, par, j)w_j_exact(t, par, j)
t |
Scalar time point (positive numeric). |
par |
Numeric vector of rates (length m), one per component. |
j |
Component index (integer, 1-based). |
Uses the inclusion-exclusion expansion to express this as a finite sum of exponentials.
Scalar value of .
w_j_integral() for the closed-form integral of .
# Component 1 contribution at t = 0.5, rates = c(1, 2, 3) w_j_exact(0.5, c(1, 2, 3), j = 1)# Component 1 contribution at t = 0.5, rates = c(1, 2, 3) w_j_exact(0.5, c(1, 2, 3), j = 1)
Computes in closed form using the
inclusion-exclusion expansion. Each term integrates as:
w_j_integral(a, b, par, j)w_j_integral(a, b, par, j)
a |
Lower bound of integration (non-negative numeric scalar). |
b |
Upper bound of integration (positive numeric scalar, |
par |
Numeric vector of rates (length m). |
j |
Component index (integer, 1-based). |
Scalar integral value.
w_j_exact() for the pointwise evaluation.
# Integral of w_1(t) from 0 to 1, rates = c(1, 2) w_j_integral(0, 1, c(1, 2), j = 1)# Integral of w_1(t) from 0 to 1, rates = c(1, 2) w_j_integral(0, 1, c(1, 2), j = 1)