///|
/// Series, parallel and k-out-of-n block reliability calculations.
pub(all) enum SystemLogic {
Series
Parallel
KOutOfN(Int)
}
///|
pub struct ReliabilitySystem {
name : String
logic : SystemLogic
component_reliabilities : Array[Double]
reliability : Double
importance : Array[Double]
}
///|
pub fn reliability_system(
name~ : String,
logic~ : SystemLogic,
component_reliabilities~ : Array[Double],
reliability~ : Double,
importance~ : Array[Double],
) -> ReliabilitySystem {
{ name, logic, component_reliabilities, reliability, importance }
}
///|
pub fn series_reliability(components : Array[Double]) -> Double {
components.fold(init=1.0, (total, value) => total * value)
}
///|
pub fn parallel_reliability(components : Array[Double]) -> Double {
1.0 - components.fold(init=1.0, (total, value) => total * (1.0 - value))
}
///|
pub fn k_out_of_n_reliability(
k : Int,
component_reliability : Double,
n : Int,
) -> Double {
if k <= 0 {
return 1.0
}
if k > n {
return 0.0
}
let mut result = 0.0
for successes in k..<=n {
result += choose(n, successes) *
@math.pow(component_reliability, successes.to_double()) *
@math.pow(1.0 - component_reliability, (n - successes).to_double())
}
result
}
///|
pub fn k_out_of_n_components(k : Int, components : Array[Double]) -> Double {
if k <= 0 {
return 1.0
}
if k > components.length() {
return 0.0
}
let mut probability = 0.0
let mut states = 1
for _ in 0..= k {
probability += state_probability
}
}
probability
}
///|
pub fn SystemLogic::evaluate(
self : SystemLogic,
components : Array[Double],
) -> Double {
match self {
Series => series_reliability(components)
Parallel => parallel_reliability(components)
KOutOfN(k) => k_out_of_n_components(k, components)
}
}
///|
pub fn build_reliability_system(
name : String,
logic : SystemLogic,
components : Array[Double],
) -> ReliabilitySystem {
let value = logic.evaluate(components)
let importance = component_importance(logic, components)
reliability_system(
name~,
logic~,
component_reliabilities=components.copy(),
reliability=value,
importance~,
)
}
///|
pub fn component_importance(
logic : SystemLogic,
components : Array[Double],
) -> Array[Double] {
Array::makei(components.length(), i => {
let degraded = components.copy()
degraded[i] = 0.0
logic.evaluate(components) - logic.evaluate(degraded)
})
}
///|
pub fn series_hazard(models : Array[ReliabilityModel], time : Double) -> Double {
models.fold(init=0.0, (total, model) => total + model_hazard(model, time))
}
///|
pub fn parallel_hazard(
models : Array[ReliabilityModel],
time : Double,
) -> Double {
let survival = models.fold(init=1.0, (total, model) => {
total * model.survival(time)
})
let mut numerator = 0.0
for model in models {
numerator += model_hazard(model, time) * model.survival(time)
}
if survival <= 1.0e-300 {
1.0e300
} else {
numerator / survival
}
}
///|
pub fn repairable_availability(
failure_rate : Double,
repair_rate : Double,
) -> Double {
if failure_rate < 0.0 || repair_rate <= 0.0 {
abort("invalid repairable rates")
}
repair_rate / (failure_rate + repair_rate)
}
///|
pub fn steady_state_unavailability(
failure_rate : Double,
repair_rate : Double,
) -> Double {
1.0 - repairable_availability(failure_rate, repair_rate)
}
///|
pub fn common_cause_adjustment(independent : Double, beta : Double) -> Double {
if beta < 0.0 || beta > 1.0 {
abort("beta must be in [0, 1]")
}
independent * (1.0 - beta)
}
///|
pub fn choose(n : Int, k : Int) -> Double {
if k < 0 || k > n {
return 0.0
}
let reduced = k.min(n - k)
let mut result = 1.0
for i in 1..<=reduced {
result *= (n - reduced + i).to_double() / i.to_double()
}
result
}