#![allow(dead_code)]
use serde::Deserialize;
#[derive(Deserialize, Clone, Copy, PartialEq, Eq, Debug, Default)]
#[serde(rename_all = "lowercase")]
pub enum Tier {
#[default]
Bulk,
Tail,
}
#[derive(Deserialize)]
pub struct Row {
pub args: Vec<f64>,
pub expected: Option<f64>,
#[serde(default)]
pub tier: Tier,
#[serde(default)]
pub band: Option<f64>,
}
pub struct Tol {
pub rel: f64,
pub abs: f64,
}
pub fn assert_close(label: &str, got: f64, want: f64, tol: Tol) {
let diff = (got - want).abs();
let t = tol.abs.max(tol.rel * want.abs());
assert!(
diff <= t,
"{label}: got {got:e}, want {want:e}, diff {diff:e} > tol {t:e}"
);
}
pub const TAIL_SLACK: f64 = 4.0;
const SIGN_FLOOR: f64 = 1e-12;
pub fn load(name: &str) -> Vec<Row> {
let path = format!("{}/tests/fixtures/{name}.json", env!("CARGO_MANIFEST_DIR"));
let txt = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("missing fixture {path}: {e} — run scripts/gen_oracle.py"));
serde_json::from_str(&txt).expect("fixture parse")
}
fn graceful(name: &str, args: &[f64], got: f64, want: f64) {
assert!(got.is_finite(), "{name}{args:?}: non-finite result {got:e}");
if want.abs() > SIGN_FLOOR {
assert!(
got.signum() == want.signum(),
"{name}{args:?}: sign mismatch — got {got:e}, want {want:e}"
);
}
}
fn rel_err(got: f64, want: f64) -> f64 {
if want == 0.0 {
got.abs()
} else {
((got - want) / want).abs()
}
}
pub fn check_grid(name: &str, tol: Tol, eval: impl Fn(&[f64]) -> f64) {
for r in load(name) {
let Some(want) = r.expected else { continue }; let got = eval(&r.args);
graceful(name, &r.args, got, want);
match r.tier {
Tier::Bulk => {
let t = tol.abs.max(tol.rel * want.abs());
let diff = (got - want).abs();
assert!(
diff <= t,
"{name}{:?}: got {got:e}, want {want:e}, diff {diff:e} > tol {t:e}",
r.args
);
}
Tier::Tail => {
if let Some(band) = r.band {
let allowed = TAIL_SLACK * band;
let rel = rel_err(got, want);
assert!(
rel <= allowed,
"{name}{:?} tail: rel {rel:e} > slack·band {allowed:e} (band {band:e})",
r.args
);
}
}
}
}
}
pub fn assert_monotone(name: &str, eval: impl Fn(&[f64]) -> f64) {
let mut prev: Option<f64> = None;
for r in load(name) {
let y = eval(&r.args);
if let Some(p) = prev {
assert!(
y >= p - 1e-12,
"{name}{:?}: not monotone↑ — {y:e} < previous {p:e}",
r.args
);
}
prev = Some(y);
}
}
pub fn measure_band(name: &str, eval: impl Fn(&[f64]) -> f64) -> Option<f64> {
let mut worst: Option<f64> = None;
for r in load(name) {
if r.tier != Tier::Tail {
continue;
}
let Some(want) = r.expected else { continue };
let rel = rel_err(eval(&r.args), want);
worst = Some(worst.map_or(rel, |w| w.max(rel)));
}
worst
}