///|
pub suberror ChoiceError {
Invalid(String)
Budget(String)
Numerical(String)
} derive(@debug.Debug)
///|
fn finite(x : Double) -> Bool {
x == x && x.abs() <= 1.0e300
}
///|
fn checked(x : Double) -> Double raise ChoiceError {
if !finite(x) {
raise Numerical("non-finite or excessively large intermediate")
}
x
}
///|
fn input_number(x : Double) -> Unit raise ChoiceError {
if !finite(x) || x.abs() > 1.0e100 {
raise Invalid("numeric inputs must be finite and bounded by 1e100")
}
}
///|
fn probability(x : Double) -> Unit raise ChoiceError {
if !finite(x) || x < 0.0 || x > 1.0 {
raise Invalid("parameter must be in 0..1")
}
}
///|
fn valid_tolerance(t : Double) -> Unit raise ChoiceError {
if !finite(t) || t < 0.0 || t > 0.01 {
raise Invalid("absolute tie tolerance must be in 0..0.01")
}
}
///|
fn zeros(n : Int32, p : Int32) -> Array[Array[Double]] {
[
for _ in 0.. Array::make(p, 0.0)
]
}
///|
fn maximum(x : Array[Double]) -> Double {
let mut best = x[0]
for v in x {
if v > best {
best = v
}
}
best
}
///|
fn minimum(x : Array[Double]) -> Double {
let mut best = x[0]
for v in x {
if v < best {
best = v
}
}
best
}
///|
fn sum(x : Array[Double]) -> Double {
// Neumaier compensated summation for mixed-sign preference flows.
let mut total = 0.0
let mut correction = 0.0
for value in x {
let next = total + value
correction += if total.abs() >= value.abs() {
total - next + value
} else {
value - next + total
}
total = next
}
total + correction
}
///|
pub extend ChoiceError with @debug.Debug::{to_repr}