use g_math::fixed_point::imperative::predicates::{orient2d, orient3d, pd_verdict, PdVerdict, Sign};
#[cfg(not(table_format = "q256_256"))]
use g_math::fixed_point::imperative::predicates::{incircle, insphere};
use g_math::fixed_point::imperative::fused;
use g_math::fixed_point::{DecimalFixed, DecimalInterval, FixedMatrix, FixedPoint, FixedVector, Interval};
#[allow(dead_code)]
mod data {
include!("data/certified_geometry_refs.rs");
}
use data::{decimal_refs, refs};
#[cfg(table_format = "q16_16")]
fn fp_le(b: &[u8]) -> FixedPoint { FixedPoint::from_raw(i32::from_le_bytes(b.try_into().expect("4 bytes"))) }
#[cfg(table_format = "q32_32")]
fn fp_le(b: &[u8]) -> FixedPoint { FixedPoint::from_raw(i64::from_le_bytes(b.try_into().expect("8 bytes"))) }
#[cfg(table_format = "q64_64")]
fn fp_le(b: &[u8]) -> FixedPoint { FixedPoint::from_raw(i128::from_le_bytes(b.try_into().expect("16 bytes"))) }
#[cfg(table_format = "q128_128")]
fn fp_le(b: &[u8]) -> FixedPoint { FixedPoint::from_raw(g_math::fixed_point::I256::from_bytes_le(b)) }
#[cfg(table_format = "q256_256")]
fn fp_le(b: &[u8]) -> FixedPoint { FixedPoint::from_raw(g_math::fixed_point::I512::from_bytes_le(b)) }
fn magnitude_bits(b: &[u8]) -> u32 {
let negative = b[b.len() - 1] & 0x80 != 0;
let mag: Vec<u8> = b.iter().map(|x| if negative { !x } else { *x }).collect();
for (i, byte) in mag.iter().enumerate().rev() {
if *byte != 0 { return i as u32 * 8 + (8 - byte.leading_zeros()); }
}
0
}
fn sign_of(s: i8) -> Sign {
match s {
-1 => Sign::Negative,
0 => Sign::Zero,
1 => Sign::Positive,
_ => panic!("reference sign out of range"),
}
}
fn assert_default_split() {
let one = FixedPoint::one();
let found = refs::SQRT.iter().any(|(x, f, c)| fp_le(x) == one && fp_le(f) == one && fp_le(c) == one);
assert!(found, "references were generated for FRAC_BITS = {}", refs::FRAC_BITS);
}
#[test]
fn sqrt_endpoints_match_independent_references() {
assert_default_split();
for (idx, (x, f, c)) in refs::SQRT.iter().enumerate() {
let iv = Interval::point(fp_le(x)).sqrt();
assert_eq!(iv.lo(), fp_le(f), "sqrt floor, reference {idx}");
assert_eq!(iv.hi(), fp_le(c), "sqrt ceil, reference {idx}");
let scalar = fp_le(x).sqrt();
assert!(
iv.contains(scalar),
"scalar sqrt escaped the certified enclosure: reference {idx}, x = {}, scalar = {}, enclosure = [{}, {}]",
fp_le(x), scalar, iv.lo(), iv.hi()
);
}
assert!(refs::SQRT.len() >= 9);
}
#[test]
fn product_and_quotient_endpoints_match_independent_references() {
assert_default_split();
let mut near_max = 0usize;
for (a, b, f, c) in refs::MUL {
let iv = Interval::point(fp_le(a)) * Interval::point(fp_le(b));
assert_eq!(iv.lo(), fp_le(f), "mul floor");
assert_eq!(iv.hi(), fp_le(c), "mul ceil");
if magnitude_bits(a) >= refs::STORAGE_BITS - 2 { near_max += 1; }
}
for (a, b, f, c) in refs::DIV {
let iv = Interval::point(fp_le(a)) / Interval::point(fp_le(b));
assert_eq!(iv.lo(), fp_le(f), "div floor");
assert_eq!(iv.hi(), fp_le(c), "div ceil");
}
assert!(near_max > 0, "references must exercise operands far above the small-value sweeps");
assert!(refs::MUL.len() >= 50 && refs::DIV.len() >= 50);
}
#[test]
fn quadratic_form_endpoints_and_nearest_match_independent_references() {
assert_default_split();
let mut near_max = 0usize;
let mut rounded_up = 0usize;
for (n, v, m, f, c, near) in refs::QF {
let fv = FixedVector::from_slice(&v.iter().map(|b| fp_le(b)).collect::<Vec<_>>());
let fm = FixedMatrix::from_slice(*n, *n, &m.iter().map(|b| fp_le(b)).collect::<Vec<_>>());
let iv = Interval::quadratic_form(&fv, &fm);
assert_eq!(iv.lo(), fp_le(f), "quadratic form floor, n = {n}");
assert_eq!(iv.hi(), fp_le(c), "quadratic form ceil, n = {n}");
let scalar = fused::quadratic_form(&fv, &fm);
assert_eq!(scalar, fp_le(near), "fused quadratic form nearest, n = {n}");
assert!(iv.contains(scalar));
let k = (refs::STORAGE_BITS - 1 + 2 * refs::FRAC_BITS) / 3 - 2;
if magnitude_bits(v[0]) >= k { near_max += 1; }
if fp_le(near) == fp_le(c) && fp_le(c) != fp_le(f) { rounded_up += 1; }
}
assert!(near_max >= 4, "references must exercise operands near the storage maximum");
assert!(rounded_up >= 2, "references must exercise inexact values rounded upward (the constructed ties)");
assert!(refs::QF.len() >= 20);
}
struct Rng(u64);
impl Rng {
fn next(&mut self) -> u64 {
self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
let x = self.0;
(x >> 33) ^ x
}
fn dyadic(&mut self) -> FixedPoint {
let k = (self.next() % 17) as i32 - 8;
FixedPoint::from_int(k) / FixedPoint::from_int(16)
}
}
fn dyadic_spd(rng: &mut Rng, n: usize) -> FixedMatrix {
let mut a = FixedMatrix::new(n, n);
for i in 0..n {
for j in 0..n {
a.set(i, j, rng.dyadic());
}
}
let mut m = FixedMatrix::new(n, n);
for i in 0..n {
for j in 0..n {
let mut s = FixedPoint::ZERO;
for k in 0..n {
s = s + a.get(k, i) * a.get(k, j);
}
if i == j { s = s + FixedPoint::one(); }
m.set(i, j, s);
}
}
m
}
#[test]
fn interval_cholesky_encloses_the_exact_rational_pivot() {
assert_default_split();
let mut rng = Rng(0x1D7);
for (n, f, c) in refs::PIVOT {
let m = dyadic_spd(&mut rng, *n);
let verdict = pd_verdict(&m).unwrap();
if refs::FRAC_BITS < 16 {
assert!(matches!(verdict, PdVerdict::Inconclusive { .. } | PdVerdict::PositiveDefinite), "{verdict:?}");
if verdict != PdVerdict::PositiveDefinite { continue; }
} else {
assert_eq!(verdict, PdVerdict::PositiveDefinite);
}
let zero = Interval::point(FixedPoint::ZERO);
let mut l = vec![vec![zero; *n]; *n];
let mut last = zero;
for i in 0..*n {
let d = Interval::point(m.get(i, i)) - Interval::dot_intervals(&l[i][..i], &l[i][..i]);
let lii = d.sqrt();
l[i][i] = lii;
for j in (i + 1)..*n {
let num = Interval::point(m.get(j, i)) - Interval::dot_intervals(&l[j][..i], &l[i][..i]);
l[j][i] = num / lii;
}
last = d;
}
let (exact_floor, exact_ceil) = (fp_le(f), fp_le(c));
assert!(last.lo() <= exact_floor, "n = {n}: interval lower endpoint above the exact pivot");
assert!(exact_ceil <= last.hi(), "n = {n}: interval upper endpoint below the exact pivot");
}
let f = refs::FRAC_BITS;
let expected = if refs::STORAGE_BITS == 32 && !(4..=27).contains(&f) { 0 } else { 2 };
assert_eq!(refs::PIVOT.len(), expected);
}
fn pt2(p: &[&[u8]]) -> [FixedPoint; 2] { [fp_le(p[0]), fp_le(p[1])] }
fn pt3(p: &[&[u8]]) -> [FixedPoint; 3] { [fp_le(p[0]), fp_le(p[1]), fp_le(p[2])] }
#[test]
fn predicates_match_independent_references_near_the_storage_maximum() {
assert_default_split();
let mut zeros = 0usize;
for (pts, s) in refs::ORIENT2D {
let got = orient2d(pt2(pts[0]), pt2(pts[1]), pt2(pts[2]));
assert_eq!(got, sign_of(*s), "orient2d");
if got == Sign::Zero { zeros += 1; }
}
for (pts, s) in refs::ORIENT3D {
let got = orient3d(pt3(pts[0]), pt3(pts[1]), pt3(pts[2]), pt3(pts[3]));
assert_eq!(got, sign_of(*s), "orient3d");
if got == Sign::Zero { zeros += 1; }
}
#[cfg(not(table_format = "q256_256"))]
{
for (pts, s) in refs::INCIRCLE {
let got = incircle(pt2(pts[0]), pt2(pts[1]), pt2(pts[2]), pt2(pts[3]));
assert_eq!(got, sign_of(*s), "incircle");
if got == Sign::Zero { zeros += 1; }
}
for (pts, s) in refs::INSPHERE {
let got = insphere(pt3(pts[0]), pt3(pts[1]), pt3(pts[2]), pt3(pts[3]), pt3(pts[4]));
assert_eq!(got, sign_of(*s), "insphere");
if got == Sign::Zero { zeros += 1; }
}
}
assert!(zeros >= 3, "the references must include exact degenerate cases, got {zeros}");
}
fn check_decimal<const D: u8>() {
for (d, x, f, c) in decimal_refs::DSQRT {
if *d != D { continue; }
let iv = DecimalInterval::<D>::point(DecimalFixed::<D>::from_raw(*x)).sqrt();
assert_eq!(iv.lo().raw_value(), *f, "decimal sqrt floor, D = {D}, x = {x}");
assert_eq!(iv.hi().raw_value(), *c, "decimal sqrt ceil, D = {D}, x = {x}");
}
for (d, a, b, f, c) in decimal_refs::DMUL {
if *d != D { continue; }
let iv = DecimalInterval::<D>::point(DecimalFixed::<D>::from_raw(*a)) * DecimalInterval::<D>::point(DecimalFixed::<D>::from_raw(*b));
assert_eq!((iv.lo().raw_value(), iv.hi().raw_value()), (*f, *c), "decimal mul, D = {D}, {a} * {b}");
}
for (d, a, b, f, c) in decimal_refs::DDIV {
if *d != D { continue; }
let iv = DecimalInterval::<D>::point(DecimalFixed::<D>::from_raw(*a)) / DecimalInterval::<D>::point(DecimalFixed::<D>::from_raw(*b));
assert_eq!((iv.lo().raw_value(), iv.hi().raw_value()), (*f, *c), "decimal div, D = {D}, {a} / {b}");
}
}
#[test]
fn decimal_endpoints_match_independent_references() {
check_decimal::<2>();
check_decimal::<9>();
assert!(decimal_refs::DSQRT.len() >= 16 && decimal_refs::DMUL.len() >= 100 && decimal_refs::DDIV.len() >= 100);
}