use g_math::fixed_point::canonical::{gmath, evaluate, LazyExpr};
use std::time::Instant;
fn gmath_safe(input: &'static str) -> LazyExpr {
if input.starts_with('-') {
let positive: &'static str = unsafe {
std::str::from_utf8_unchecked(
std::slice::from_raw_parts(input.as_ptr().add(1), input.len() - 1)
)
};
-gmath(positive)
} else {
gmath(input)
}
}
fn build_arith_expr(a: &'static str, b: &'static str, op: &str) -> LazyExpr {
match op {
"add" => gmath_safe(a) + gmath_safe(b),
"sub" => gmath_safe(a) - gmath_safe(b),
"mul" => gmath_safe(a) * gmath_safe(b),
"div" => gmath_safe(a) / gmath_safe(b),
_ => panic!("unknown op: {}", op),
}
}
fn rationals_equal(
actual_num: Option<i128>, actual_den: Option<i128>,
expected_num: i128, expected_den: i128,
) -> bool {
let (a_num, a_den) = match (actual_num, actual_den) {
(Some(n), Some(d)) => (n, d),
_ => return false,
};
if a_num == 0 && expected_num == 0 { return true; }
if a_num == 0 || expected_num == 0 { return false; }
match (a_num.checked_mul(expected_den), a_den.checked_mul(expected_num)) {
(Some(lhs), Some(rhs)) => lhs == rhs,
_ => false,
}
}
struct ValidationResult {
name: String,
total: usize,
passed: usize,
max_ulp: u128,
failures: Vec<String>,
errors: Vec<String>,
min_ns: u64,
max_ns: u64,
sum_ns: u64,
times_ns: Vec<u64>,
}
const MAX_RECORDED_DETAILS: usize = 10;
impl ValidationResult {
fn new(name: &str) -> Self {
Self {
name: name.to_string(),
total: 0,
passed: 0,
max_ulp: 0,
failures: Vec::new(),
errors: Vec::new(),
min_ns: u64::MAX,
max_ns: 0,
sum_ns: 0,
times_ns: Vec::new(),
}
}
fn record_timing(&mut self, ns: u64) {
self.times_ns.push(ns);
self.sum_ns = self.sum_ns.saturating_add(ns);
if ns < self.min_ns { self.min_ns = ns; }
if ns > self.max_ns { self.max_ns = ns; }
}
fn record_failure(&mut self, label: &str, detail: &str) {
if self.failures.len() < MAX_RECORDED_DETAILS {
self.failures.push(format!("{}: {}", label, detail));
}
}
fn record_error(&mut self, label: &str, detail: &str) {
if self.errors.len() < MAX_RECORDED_DETAILS {
self.errors.push(format!("{}: {}", label, detail));
}
}
fn avg_ns(&self) -> u64 {
if self.total == 0 { return 0; }
self.sum_ns / self.total as u64
}
fn p99_ns(&self) -> u64 {
if self.times_ns.is_empty() { return 0; }
let mut sorted = self.times_ns.clone();
sorted.sort_unstable();
let idx = ((sorted.len() as f64) * 0.99).ceil() as usize;
sorted[idx.min(sorted.len() - 1)]
}
fn throughput(&self) -> String {
let avg = self.avg_ns();
if avg == 0 { return "N/A".to_string(); }
let ops_sec = 1_000_000_000u64 / avg;
if ops_sec >= 1_000_000 {
format!("{:.1}M ops/s", ops_sec as f64 / 1_000_000.0)
} else if ops_sec >= 1_000 {
format!("{:.1}K ops/s", ops_sec as f64 / 1_000.0)
} else {
format!("{} ops/s", ops_sec)
}
}
fn report(&self) {
let failed = self.total - self.passed;
let min = if self.min_ns == u64::MAX { 0 } else { self.min_ns };
eprintln!(
" {:30} {}/{} passed | {} failures | {} errors | max_ulp={}",
self.name, self.passed, self.total,
failed, self.errors.len(), self.max_ulp,
);
eprintln!(
" {:30} min={}ns | avg={}ns | p99={}ns | max={}ns | {}",
"", min, self.avg_ns(), self.p99_ns(), self.max_ns, self.throughput(),
);
for f in &self.failures {
eprintln!(" FAIL: {}", f);
}
for e in &self.errors {
eprintln!(" ERR: {}", e);
}
}
}
#[cfg(table_format = "q16_16")]
const ACTIVE_PROFILE: &str = "Q16.16";
#[cfg(table_format = "q32_32")]
const ACTIVE_PROFILE: &str = "Q32.32";
#[cfg(table_format = "q64_64")]
const ACTIVE_PROFILE: &str = "Q64.64";
#[cfg(table_format = "q128_128")]
const ACTIVE_PROFILE: &str = "Q128.128";
#[cfg(table_format = "q256_256")]
const ACTIVE_PROFILE: &str = "Q256.256";
include!("data/topology_sweep_decimal.rs");
include!("data/topology_sweep_symbolic.rs");
include!("data/topology_sweep_cross.rs");
fn run_rational_validation(
refs: &[(&'static str, &'static str, i128, i128, &'static str)],
op: &str,
name: &str,
) -> ValidationResult {
let mut result = ValidationResult::new(name);
for &(a_str, b_str, expected_num, expected_den, label) in refs {
result.total += 1;
let start = Instant::now();
let eval_result = evaluate(&build_arith_expr(a_str, b_str, op));
let elapsed_ns = start.elapsed().as_nanos() as u64;
result.record_timing(elapsed_ns);
match eval_result {
Ok(val) => match val.to_rational() {
Ok(rational) => {
let actual_num = rational.numerator_i128();
let actual_den = rational.denominator_i128();
if rationals_equal(actual_num, actual_den, expected_num, expected_den) {
result.passed += 1;
} else {
result.record_failure(label, &format!(
"{} {} {} = {:?}/{:?}, expected {}/{}",
a_str, op, b_str, actual_num, actual_den, expected_num, expected_den
));
}
}
Err(e) => result.record_error(label, &format!("to_rational: {:?}", e)),
},
Err(e) => result.record_error(label, &format!("evaluate: {:?}", e)),
}
}
result
}
#[test]
fn validate_decimal_arithmetic() {
eprintln!("\n Decimal Arithmetic Validation — {}", ACTIVE_PROFILE);
let ops: [(&str, &[(&str, &str, i128, i128, &str)]); 4] = [
("add", TOPO_DECIMAL_ADD_REFS),
("sub", TOPO_DECIMAL_SUB_REFS),
("mul", TOPO_DECIMAL_MUL_REFS),
("div", TOPO_DECIMAL_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_rational_validation(refs, op, &format!("decimal_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Decimal arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
#[test]
fn validate_symbolic_arithmetic() {
eprintln!("\n Symbolic Arithmetic Validation — {}", ACTIVE_PROFILE);
let ops: [(&str, &[(&str, &str, i128, i128, &str)]); 4] = [
("add", TOPO_SYMBOLIC_ADD_REFS),
("sub", TOPO_SYMBOLIC_SUB_REFS),
("mul", TOPO_SYMBOLIC_MUL_REFS),
("div", TOPO_SYMBOLIC_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_rational_validation(refs, op, &format!("symbolic_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Symbolic arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
#[test]
fn validate_cross_domain_arithmetic() {
eprintln!("\n Cross-Domain Arithmetic Validation — {}", ACTIVE_PROFILE);
let ops: [(&str, &[(&str, &str, i128, i128, &str)]); 4] = [
("add", TOPO_CROSS_ADD_REFS),
("sub", TOPO_CROSS_SUB_REFS),
("mul", TOPO_CROSS_MUL_REFS),
("div", TOPO_CROSS_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_rational_validation(refs, op, &format!("cross_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Cross-domain arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
#[allow(dead_code)]
const MAX_ARITHMETIC_ULP: u128 = 1;
#[cfg(table_format = "q64_64")]
mod q64_64_binary {
use super::*;
include!("data/topology_sweep_q64_64.rs");
fn ulp_i128(actual: i128, expected: i128) -> u128 {
(actual - expected).unsigned_abs()
}
fn run_binary_validation(
refs: &[(&'static str, &'static str, i128, &'static str)],
op: &str,
name: &str,
) -> ValidationResult {
let mut result = ValidationResult::new(name);
for &(a_str, b_str, expected, label) in refs {
result.total += 1;
let start = Instant::now();
let eval_result = evaluate(&build_arith_expr(a_str, b_str, op));
let elapsed_ns = start.elapsed().as_nanos() as u64;
result.record_timing(elapsed_ns);
match eval_result {
Ok(val) => match val.as_binary_storage() {
Some(actual) => {
let ulp = ulp_i128(actual, expected);
if ulp > result.max_ulp { result.max_ulp = ulp; }
if ulp <= MAX_ARITHMETIC_ULP {
result.passed += 1;
} else {
result.record_failure(label, &format!(
"{} {} {} = ULP {} (actual=0x{:032x}, expected=0x{:032x})",
a_str, op, b_str, ulp, actual as u128, expected as u128
));
}
}
None => result.record_error(label, "as_binary_storage() returned None"),
},
Err(e) => result.record_error(label, &format!("evaluate: {:?}", e)),
}
}
result
}
#[test]
fn validate_binary_arithmetic() {
eprintln!("\n Binary Arithmetic Validation — Q64.64");
let ops: [(&str, &[(&str, &str, i128, &str)]); 4] = [
("add", TOPO_BINARY_ADD_REFS),
("sub", TOPO_BINARY_SUB_REFS),
("mul", TOPO_BINARY_MUL_REFS),
("div", TOPO_BINARY_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_binary_validation(refs, op, &format!("binary_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Binary Q64.64 arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
}
#[cfg(table_format = "q128_128")]
mod q128_128_binary {
use super::*;
use g_math::fixed_point::domains::binary_fixed::i256::I256;
include!("data/topology_sweep_q128_128.rs");
fn ulp_i256(actual: I256, expected_words: [u64; 4]) -> u128 {
let expected = I256 { words: expected_words };
let diff = actual - expected;
let is_neg = diff.words[3] >> 63 == 1;
let abs_diff = if is_neg { -diff } else { diff };
if abs_diff.words[2] != 0 || abs_diff.words[3] != 0 {
return u128::MAX;
}
abs_diff.words[0] as u128 | ((abs_diff.words[1] as u128) << 64)
}
fn run_binary_validation(
refs: &[(&'static str, &'static str, [u64; 4], &'static str)],
op: &str,
name: &str,
) -> ValidationResult {
let mut result = ValidationResult::new(name);
for &(a_str, b_str, expected_words, label) in refs {
result.total += 1;
let start = Instant::now();
let eval_result = evaluate(&build_arith_expr(a_str, b_str, op));
let elapsed_ns = start.elapsed().as_nanos() as u64;
result.record_timing(elapsed_ns);
match eval_result {
Ok(val) => match val.as_binary_storage() {
Some(actual) => {
let ulp = ulp_i256(actual, expected_words);
if ulp > result.max_ulp { result.max_ulp = ulp; }
if ulp <= MAX_ARITHMETIC_ULP {
result.passed += 1;
} else {
result.record_failure(label, &format!(
"{} {} {} = ULP {}", a_str, op, b_str, ulp
));
}
}
None => result.record_error(label, "as_binary_storage() returned None"),
},
Err(e) => result.record_error(label, &format!("evaluate: {:?}", e)),
}
}
result
}
#[test]
fn validate_binary_arithmetic() {
eprintln!("\n Binary Arithmetic Validation — Q128.128");
let ops: [(&str, &[(&str, &str, [u64; 4], &str)]); 4] = [
("add", TOPO_BINARY_ADD_REFS),
("sub", TOPO_BINARY_SUB_REFS),
("mul", TOPO_BINARY_MUL_REFS),
("div", TOPO_BINARY_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_binary_validation(refs, op, &format!("binary_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Binary Q128.128 arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
}
#[cfg(table_format = "q256_256")]
mod q256_256_binary {
use super::*;
use g_math::fixed_point::domains::binary_fixed::i512::I512;
include!("data/topology_sweep_q256_256.rs");
fn ulp_i512(actual: I512, expected_words: [u64; 8]) -> u128 {
let expected = I512 { words: expected_words };
let diff = actual - expected;
let is_neg = diff.words[7] >> 63 == 1;
let abs_diff = if is_neg { -diff } else { diff };
for i in 2..8 {
if abs_diff.words[i] != 0 {
return u128::MAX;
}
}
abs_diff.words[0] as u128 | ((abs_diff.words[1] as u128) << 64)
}
fn run_binary_validation(
refs: &[(&'static str, &'static str, [u64; 8], &'static str)],
op: &str,
name: &str,
) -> ValidationResult {
let mut result = ValidationResult::new(name);
for &(a_str, b_str, expected_words, label) in refs {
result.total += 1;
let start = Instant::now();
let eval_result = evaluate(&build_arith_expr(a_str, b_str, op));
let elapsed_ns = start.elapsed().as_nanos() as u64;
result.record_timing(elapsed_ns);
match eval_result {
Ok(val) => match val.as_binary_storage() {
Some(actual) => {
let ulp = ulp_i512(actual, expected_words);
if ulp > result.max_ulp { result.max_ulp = ulp; }
if ulp <= MAX_ARITHMETIC_ULP {
result.passed += 1;
} else {
result.record_failure(label, &format!(
"{} {} {} = ULP {}", a_str, op, b_str, ulp
));
}
}
None => result.record_error(label, "as_binary_storage() returned None"),
},
Err(e) => result.record_error(label, &format!("evaluate: {:?}", e)),
}
}
result
}
#[test]
fn validate_binary_arithmetic() {
eprintln!("\n Binary Arithmetic Validation — Q256.256");
let ops: [(&str, &[(&str, &str, [u64; 8], &str)]); 4] = [
("add", TOPO_BINARY_ADD_REFS),
("sub", TOPO_BINARY_SUB_REFS),
("mul", TOPO_BINARY_MUL_REFS),
("div", TOPO_BINARY_DIV_REFS),
];
let mut total_passed = 0usize;
let mut total_tested = 0usize;
for (op, refs) in &ops {
let r = run_binary_validation(refs, op, &format!("binary_{}", op));
r.report();
total_passed += r.passed;
total_tested += r.total;
}
assert_eq!(
total_passed, total_tested,
"Binary Q256.256 arithmetic: {}/{} passed ({} failures)",
total_passed, total_tested, total_tested - total_passed
);
}
}
#[test]
fn validate_sweep_summary() {
let decimal_total =
TOPO_DECIMAL_ADD_REFS.len() + TOPO_DECIMAL_SUB_REFS.len() +
TOPO_DECIMAL_MUL_REFS.len() + TOPO_DECIMAL_DIV_REFS.len();
let symbolic_total =
TOPO_SYMBOLIC_ADD_REFS.len() + TOPO_SYMBOLIC_SUB_REFS.len() +
TOPO_SYMBOLIC_MUL_REFS.len() + TOPO_SYMBOLIC_DIV_REFS.len();
let cross_total =
TOPO_CROSS_ADD_REFS.len() + TOPO_CROSS_SUB_REFS.len() +
TOPO_CROSS_MUL_REFS.len() + TOPO_CROSS_DIV_REFS.len();
let rational_total = decimal_total + symbolic_total + cross_total;
eprintln!("\n Arithmetic Sweep Validation — {}", ACTIVE_PROFILE);
eprintln!(" Decimal: {} points (add={} sub={} mul={} div={})",
decimal_total,
TOPO_DECIMAL_ADD_REFS.len(), TOPO_DECIMAL_SUB_REFS.len(),
TOPO_DECIMAL_MUL_REFS.len(), TOPO_DECIMAL_DIV_REFS.len());
eprintln!(" Symbolic: {} points (add={} sub={} mul={} div={})",
symbolic_total,
TOPO_SYMBOLIC_ADD_REFS.len(), TOPO_SYMBOLIC_SUB_REFS.len(),
TOPO_SYMBOLIC_MUL_REFS.len(), TOPO_SYMBOLIC_DIV_REFS.len());
eprintln!(" Cross: {} points (add={} sub={} mul={} div={})",
cross_total,
TOPO_CROSS_ADD_REFS.len(), TOPO_CROSS_SUB_REFS.len(),
TOPO_CROSS_MUL_REFS.len(), TOPO_CROSS_DIV_REFS.len());
eprintln!(" Binary: (profile-specific, see validate_binary_arithmetic)");
eprintln!(" Rational: {} total mpmath-verified reference points", rational_total);
}