///|
pub suberror DesignError {
Invalid(String)
Budget(String)
Singular(String)
} derive(Debug, Eq)
///|
pub(all) struct Factor {
name : String
low : Double
high : Double
} derive(Debug, Eq)
///|
pub(all) struct Run {
id : String
block : Int32
point : Array[Double]
} derive(Debug, Eq)
///|
pub(all) struct Plan {
factors : Array[Factor]
runs : Array[Run]
} derive(Debug, Eq)
///|
fn finite(x : Double) -> Bool {
x == x && x.abs() <= 1.0e100
}
///|
fn require_number(x : Double) -> Unit raise DesignError {
if !finite(x) {
raise Invalid("number must be finite with magnitude <= 1e100")
}
}
///|
pub fn factor(
name : String,
low : Double,
high : Double,
) -> Factor raise DesignError {
require_number(low)
require_number(high)
if name.trim().length() == 0 || name.length() > 128 {
raise Invalid("factor name must contain 1..128 characters")
}
if high <= low {
raise Invalid("factor bounds must strictly increase")
}
{ name, low, high, }
}
///|
fn validate_factors(factors : Array[Factor]) -> Unit raise DesignError {
if factors.length() == 0 || factors.length() > 16 {
raise Budget("factor count must be 1..16")
}
for i, f in factors {
ignore(factor(f.name, f.low, f.high))
for j in 0.. Plan raise DesignError {
validate_factors(factors)
if runs.length() == 0 || runs.length() > 4096 {
raise Budget("run count must be 1..4096")
}
for i, r in runs {
if r.id.length() == 0 || r.id.length() > 128 || r.block < 0 {
raise Invalid("invalid run id or block")
}
if r.point.length() != factors.length() {
raise Invalid("run dimension mismatch")
}
for x in r.point {
require_number(x)
}
for j in 0.. { ..r, point: r.point.copy(), }
],
}
}
///|
pub fn coded_plan(
factors : Array[Factor],
points : Array[Array[Double]],
) -> Plan raise DesignError {
plan(
factors,
[
for i, point in points => { id: "r\{i + 1}", block: 0, point, }
],
)
}
///|
pub fn validate_plan(p : Plan) -> Unit raise DesignError {
ignore(plan(p.factors, p.runs))
}
///|
pub extend DesignError with @debug.Debug::{to_repr}
///|
pub extend DesignError with Eq::{equal, not_equal}
///|
pub extend Factor with @debug.Debug::{to_repr}
///|
pub extend Factor with Eq::{equal, not_equal}
///|
pub extend Run with @debug.Debug::{to_repr}
///|
pub extend Run with Eq::{equal, not_equal}
///|
pub extend Plan with @debug.Debug::{to_repr}
///|
pub extend Plan with Eq::{equal, not_equal}