Load factor to the limit
64-bitThe factor by which every load can be multiplied before the design's utilization reaches 1.
find λ with util(λ) = 1: double λ until util ≥ 1, then bisect with mid = √(lo × hi) until hi − lo ≤ 10⁻⁴ × hi
The result is (lo + hi) ÷ 2, the middle of the final bracket, so it is known to about 0.005 % and may lie on the failing side; the comment above the loop says the passing side is reported. The loop also ends after 80 evaluations, in which case the bracket can be wider than the tolerance.
/**
* The load factor λ at which `util(λ)` reaches 1. `util` is the utilisation of the design when every load is multiplied by λ, computed by
* the design's own solver (so nonlinear interaction formulas are honoured); it is assumed to rise with λ and to be 0 at 0. If util(1) is
* already ≥ 1 the factor is below 1 (the design fails as loaded). If nothing fails up to `max`, `bounded` is false and `factor` is
* Infinity (the design holds at least `atLeast`). `evals` counts the solves, so a caller can bound the cost.
*/
export async function reserve(util, { max = LIMITS.factorMax, tol = 1e-4, maxEvals = LIMITS.evals, cancelled = () => false } = {}) {
let evals = 0;
const f = async (l) => { evals++; const u = await util(l); if (!finite(u)) throw new Error('The check did not give a number.'); return u; }; // i18n-ignore: a programming error
const u1 = await f(1);
let lo, hi;
if (u1 >= 1) { lo = 0; hi = 1; }
else {
lo = 1; hi = 2;
for (;;) {
if (cancelled() || evals >= maxEvals) return { factor: null, bounded: false, evals, cancelled: true };
if (hi > max) return { factor: Infinity, bounded: false, atLeast: lo, evals };
if ((await f(hi)) >= 1) break;
lo = hi; hi *= 2;
}
}
// lo holds (util < 1, or λ = 0), hi fails. Bisection on the ratio; the factor reported is the passing side, so "holds up to" is true.
while (hi - lo > tol * hi && evals < maxEvals && !cancelled()) {
const mid = lo > 0 ? Math.sqrt(lo * hi) : hi / 2;
if ((await f(mid)) >= 1) hi = mid; else lo = mid;
}
return { factor: (lo + hi) / 2, bounded: true, evals, utilAsLoaded: u1 };
}