use g_math::fixed_point::{FixedPoint, FixedVector, FixedMatrix};
use g_math::fixed_point::imperative::OverflowDetected;
#[test]
fn test_fixedpoint_serialization_roundtrip() {
let values = [
fp("0"), fp("1"), fp("-1"), fp("3.14159265358979323846"),
fp("0.5"), fp("-0.333333333333333"), fp("12345.6789"),
];
for &val in &values {
let bytes = val.to_bytes();
let recovered = FixedPoint::from_bytes(&bytes).unwrap();
assert_eq!(val, recovered, "round-trip failed for {}", val);
}
}
#[test]
fn test_fixedpoint_raw_bytes_roundtrip() {
let val = fp("2.718281828459045235360287471352662");
let bytes = val.to_raw_bytes();
let recovered = FixedPoint::from_raw_bytes(&bytes).unwrap();
assert_eq!(val, recovered);
}
#[test]
fn test_fixedpoint_profile_tag() {
let val = fp("1");
let bytes = val.to_bytes();
let tag = bytes[0];
assert!(tag >= 0x01 && tag <= 0x05, "unexpected profile tag: {:#x}", tag);
assert_eq!(tag, FixedPoint::profile_tag());
}
#[test]
fn test_fixedpoint_wrong_profile_tag() {
let val = fp("1");
let mut bytes = val.to_bytes();
bytes[0] = 0xFF; assert!(FixedPoint::from_bytes(&bytes).is_err());
}
#[test]
fn test_fixedpoint_truncated_bytes() {
assert!(FixedPoint::from_bytes(&[0x01]).is_err());
assert!(FixedPoint::from_bytes(&[]).is_err());
}
#[test]
fn test_fixedvector_serialization_roundtrip() {
let v = FixedVector::from_slice(&[fp("1.5"), fp("-2.7"), fp("0"), fp("3.14")]);
let bytes = v.to_bytes();
let recovered = FixedVector::from_bytes(&bytes).unwrap();
assert_eq!(v, recovered);
}
#[test]
fn test_fixedvector_empty_roundtrip() {
let v = FixedVector::new(0);
let bytes = v.to_bytes();
let recovered = FixedVector::from_bytes(&bytes).unwrap();
assert_eq!(v.len(), recovered.len());
}
#[test]
fn test_fixedmatrix_serialization_roundtrip() {
let m = FixedMatrix::from_slice(2, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
]);
let bytes = m.to_bytes();
let recovered = FixedMatrix::from_bytes(&bytes).unwrap();
assert_eq!(m, recovered);
}
#[test]
fn test_fixedmatrix_identity_roundtrip() {
let m = FixedMatrix::identity(4);
let bytes = m.to_bytes();
let recovered = FixedMatrix::from_bytes(&bytes).unwrap();
assert_eq!(m, recovered);
}
#[test]
fn test_serialization_byte_sizes() {
let raw_len = FixedPoint::raw_byte_len();
assert!(raw_len == 4 || raw_len == 8 || raw_len == 16 || raw_len == 32 || raw_len == 64,
"unexpected raw_byte_len: {}", raw_len);
let val = fp("1");
let bytes = val.to_bytes();
assert_eq!(bytes.len(), 1 + raw_len);
let v = FixedVector::from_slice(&[fp("1"), fp("2"), fp("3")]);
let vbytes = v.to_bytes();
assert_eq!(vbytes.len(), 4 + 3 * raw_len);
let m = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let mbytes = m.to_bytes();
assert_eq!(mbytes.len(), 8 + 4 * raw_len); }
fn fp(s: &str) -> FixedPoint {
FixedPoint::from_str(s)
}
#[test]
fn test_vector_add() {
let a = FixedVector::from_slice(&[fp("1.5"), fp("2.5"), fp("3.0")]);
let b = FixedVector::from_slice(&[fp("0.5"), fp("1.0"), fp("-1.0")]);
let c = &a + &b;
assert_eq!(c[0], fp("2.0"));
assert_eq!(c[1], fp("3.5"));
assert_eq!(c[2], fp("2.0"));
}
#[test]
fn test_vector_sub() {
let a = FixedVector::from_slice(&[fp("5.0"), fp("3.0")]);
let b = FixedVector::from_slice(&[fp("2.0"), fp("1.0")]);
let c = &a - &b;
assert_eq!(c[0], fp("3.0"));
assert_eq!(c[1], fp("2.0"));
}
#[test]
fn test_vector_neg() {
let a = FixedVector::from_slice(&[fp("1.0"), fp("-2.0"), fp("3.0")]);
let b = -&a;
assert_eq!(b[0], fp("-1.0"));
assert_eq!(b[1], fp("2.0"));
assert_eq!(b[2], fp("-3.0"));
}
#[test]
fn test_vector_scalar_mul() {
let v = FixedVector::from_slice(&[fp("2.0"), fp("3.0"), fp("4.0")]);
let s = fp("0.5");
let r = &v * s;
assert_eq!(r[0], fp("1.0"));
assert_eq!(r[1], fp("1.5"));
assert_eq!(r[2], fp("2.0"));
}
#[test]
fn test_vector_add_sub_identity() {
let a = FixedVector::from_slice(&[fp("1.23"), fp("4.56"), fp("7.89")]);
let b = FixedVector::from_slice(&[fp("9.87"), fp("6.54"), fp("3.21")]);
let result = &(&a + &b) - &b;
for i in 0..a.len() {
assert_eq!(result[i], a[i], "add-sub identity failed at index {}", i);
}
}
#[test]
fn test_vector_neg_double_identity() {
let a = FixedVector::from_slice(&[fp("1.5"), fp("-2.7"), fp("0.0")]);
let result = -(-a.clone());
assert_eq!(result, a);
}
#[test]
fn test_cross_product_basic() {
let i = FixedVector::from_slice(&[fp("1"), fp("0"), fp("0")]);
let j = FixedVector::from_slice(&[fp("0"), fp("1"), fp("0")]);
let k = i.cross(&j);
assert_eq!(k[0], fp("0"));
assert_eq!(k[1], fp("0"));
assert_eq!(k[2], fp("1"));
}
#[test]
fn test_cross_product_anticommutative() {
let a = FixedVector::from_slice(&[fp("1"), fp("2"), fp("3")]);
let b = FixedVector::from_slice(&[fp("4"), fp("5"), fp("6")]);
let ab = a.cross(&b);
let ba = b.cross(&a);
assert_eq!(ab, -ba);
}
#[test]
fn test_cross_product_self_is_zero() {
let a = FixedVector::from_slice(&[fp("3.5"), fp("-1.2"), fp("7.8")]);
let result = a.cross(&a);
let zero = FixedVector::from_slice(&[fp("0"), fp("0"), fp("0")]);
assert_eq!(result, zero);
}
#[test]
fn test_cross_product_perpendicular() {
let a = FixedVector::from_slice(&[fp("1"), fp("2"), fp("3")]);
let b = FixedVector::from_slice(&[fp("4"), fp("5"), fp("6")]);
let cross = a.cross(&b);
assert_eq!(cross.dot(&a), fp("0"));
assert_eq!(cross.dot(&b), fp("0"));
}
#[test]
fn test_outer_product() {
let u = FixedVector::from_slice(&[fp("1"), fp("2")]);
let v = FixedVector::from_slice(&[fp("3"), fp("4"), fp("5")]);
let m = u.outer_product(&v);
assert_eq!(m.rows(), 2);
assert_eq!(m.cols(), 3);
assert_eq!(m.get(0, 0), fp("3"));
assert_eq!(m.get(0, 1), fp("4"));
assert_eq!(m.get(0, 2), fp("5"));
assert_eq!(m.get(1, 0), fp("6"));
assert_eq!(m.get(1, 1), fp("8"));
assert_eq!(m.get(1, 2), fp("10"));
}
#[test]
fn test_matrix_identity() {
let i3 = FixedMatrix::identity(3);
assert_eq!(i3.rows(), 3);
assert_eq!(i3.cols(), 3);
for r in 0..3 {
for c in 0..3 {
if r == c {
assert_eq!(i3.get(r, c), fp("1"));
} else {
assert_eq!(i3.get(r, c), fp("0"));
}
}
}
}
#[test]
fn test_matrix_diagonal() {
let v = FixedVector::from_slice(&[fp("2"), fp("3"), fp("4")]);
let d = FixedMatrix::diagonal(&v);
assert_eq!(d.get(0, 0), fp("2"));
assert_eq!(d.get(1, 1), fp("3"));
assert_eq!(d.get(2, 2), fp("4"));
assert_eq!(d.get(0, 1), fp("0"));
assert_eq!(d.get(1, 0), fp("0"));
}
#[test]
fn test_matrix_from_fn() {
let m = FixedMatrix::from_fn(2, 2, |r, c| {
FixedPoint::one() / FixedPoint::from_int((r + c + 1) as i32)
});
assert_eq!(m.get(0, 0), fp("1") / fp("1")); assert_eq!(m.get(0, 1), fp("1") / fp("2")); assert_eq!(m.get(1, 0), fp("1") / fp("2")); assert_eq!(m.get(1, 1), fp("1") / fp("3")); }
#[test]
fn test_matrix_transpose() {
let m = FixedMatrix::from_slice(2, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
]);
let t = m.transpose();
assert_eq!(t.rows(), 3);
assert_eq!(t.cols(), 2);
assert_eq!(t.get(0, 0), fp("1"));
assert_eq!(t.get(0, 1), fp("4"));
assert_eq!(t.get(1, 0), fp("2"));
assert_eq!(t.get(1, 1), fp("5"));
assert_eq!(t.get(2, 0), fp("3"));
assert_eq!(t.get(2, 1), fp("6"));
}
#[test]
fn test_matrix_transpose_transpose_identity() {
let m = FixedMatrix::from_slice(2, 3, &[
fp("1.5"), fp("2.7"), fp("3.1"),
fp("4.9"), fp("5.3"), fp("6.8"),
]);
assert_eq!(m.transpose().transpose(), m);
}
#[test]
fn test_matrix_trace() {
let m = FixedMatrix::from_slice(3, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
fp("7"), fp("8"), fp("9"),
]);
assert_eq!(m.trace(), fp("15")); }
#[test]
fn test_matrix_add_sub() {
let a = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let b = FixedMatrix::from_slice(2, 2, &[fp("5"), fp("6"), fp("7"), fp("8")]);
let sum = &a + &b;
assert_eq!(sum.get(0, 0), fp("6"));
assert_eq!(sum.get(1, 1), fp("12"));
let diff = &a - &b;
assert_eq!(diff.get(0, 0), fp("-4"));
assert_eq!(diff.get(1, 1), fp("-4"));
}
#[test]
fn test_matrix_scalar_mul() {
let m = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let s = fp("3");
let r = &m * s;
assert_eq!(r.get(0, 0), fp("3"));
assert_eq!(r.get(0, 1), fp("6"));
assert_eq!(r.get(1, 0), fp("9"));
assert_eq!(r.get(1, 1), fp("12"));
}
#[test]
fn test_matrix_vector_multiply() {
let m = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let v = FixedVector::from_slice(&[fp("5"), fp("6")]);
let r = m.mul_vector(&v);
assert_eq!(r[0], fp("17"));
assert_eq!(r[1], fp("39"));
}
#[test]
fn test_identity_mul_vector() {
let id = FixedMatrix::identity(3);
let v = FixedVector::from_slice(&[fp("1.5"), fp("2.5"), fp("3.5")]);
let r = id.mul_vector(&v);
assert_eq!(r, v);
}
#[test]
fn test_matrix_multiply_2x2() {
let a = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let b = FixedMatrix::from_slice(2, 2, &[fp("5"), fp("6"), fp("7"), fp("8")]);
let c = &a * &b;
assert_eq!(c.get(0, 0), fp("19"));
assert_eq!(c.get(0, 1), fp("22"));
assert_eq!(c.get(1, 0), fp("43"));
assert_eq!(c.get(1, 1), fp("50"));
}
#[test]
fn test_matrix_multiply_identity() {
let a = FixedMatrix::from_slice(2, 2, &[fp("1.5"), fp("2.7"), fp("3.1"), fp("4.9")]);
let id = FixedMatrix::identity(2);
let r = &a * &id;
assert_eq!(r, a);
}
#[test]
fn test_matrix_multiply_identity_left() {
let a = FixedMatrix::from_slice(2, 2, &[fp("1.5"), fp("2.7"), fp("3.1"), fp("4.9")]);
let id = FixedMatrix::identity(2);
let r = &id * &a;
assert_eq!(r, a);
}
#[test]
fn test_matrix_multiply_non_square() {
let a = FixedMatrix::from_slice(2, 3, &[fp("1"), fp("2"), fp("3"), fp("4"), fp("5"), fp("6")]);
let b = FixedMatrix::from_slice(3, 2, &[fp("7"), fp("8"), fp("9"), fp("10"), fp("11"), fp("12")]);
let c = &a * &b;
assert_eq!(c.rows(), 2);
assert_eq!(c.cols(), 2);
assert_eq!(c.get(0, 0), fp("58"));
assert_eq!(c.get(0, 1), fp("64"));
assert_eq!(c.get(1, 0), fp("139"));
assert_eq!(c.get(1, 1), fp("154"));
}
#[test]
fn test_matrix_transpose_multiply_property() {
let a = FixedMatrix::from_slice(2, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
]);
let b = FixedMatrix::from_slice(3, 2, &[
fp("7"), fp("8"),
fp("9"), fp("10"),
fp("11"), fp("12"),
]);
let ab_t = (&a * &b).transpose();
let bt_at = &b.transpose() * &a.transpose();
assert_eq!(ab_t, bt_at);
}
#[test]
fn test_submatrix() {
let m = FixedMatrix::from_slice(3, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
fp("7"), fp("8"), fp("9"),
]);
let sub = m.submatrix(1, 1, 2, 2);
assert_eq!(sub.get(0, 0), fp("5"));
assert_eq!(sub.get(0, 1), fp("6"));
assert_eq!(sub.get(1, 0), fp("8"));
assert_eq!(sub.get(1, 1), fp("9"));
}
#[test]
fn test_set_submatrix() {
let mut m = FixedMatrix::new(3, 3);
let sub = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
m.set_submatrix(1, 1, &sub);
assert_eq!(m.get(0, 0), fp("0"));
assert_eq!(m.get(1, 1), fp("1"));
assert_eq!(m.get(1, 2), fp("2"));
assert_eq!(m.get(2, 1), fp("3"));
assert_eq!(m.get(2, 2), fp("4"));
}
#[test]
fn test_kronecker_product() {
let a = FixedMatrix::from_slice(2, 2, &[fp("1"), fp("2"), fp("3"), fp("4")]);
let b = FixedMatrix::from_slice(2, 2, &[fp("0"), fp("5"), fp("6"), fp("7")]);
let k = a.kronecker(&b);
assert_eq!(k.rows(), 4);
assert_eq!(k.cols(), 4);
assert_eq!(k.get(0, 0), fp("0"));
assert_eq!(k.get(0, 1), fp("5"));
assert_eq!(k.get(0, 2), fp("0"));
assert_eq!(k.get(0, 3), fp("10"));
assert_eq!(k.get(1, 0), fp("6"));
assert_eq!(k.get(1, 1), fp("7"));
assert_eq!(k.get(1, 2), fp("12"));
assert_eq!(k.get(1, 3), fp("14"));
assert_eq!(k.get(2, 0), fp("0"));
assert_eq!(k.get(2, 1), fp("15"));
assert_eq!(k.get(2, 2), fp("0"));
assert_eq!(k.get(2, 3), fp("20"));
assert_eq!(k.get(3, 0), fp("18"));
assert_eq!(k.get(3, 1), fp("21"));
assert_eq!(k.get(3, 2), fp("24"));
assert_eq!(k.get(3, 3), fp("28"));
}
#[test]
fn test_compute_tier_dot_vs_standard_dot() {
let a = FixedVector::from_slice(&[fp("3"), fp("4")]);
let b = FixedVector::from_slice(&[fp("5"), fp("6")]);
assert_eq!(a.dot(&b), fp("39")); assert_eq!(a.dot_precise(&b), fp("39")); }
#[test]
fn test_compute_tier_dot_fractional() {
let a = FixedVector::from_slice(&[fp("0.1"), fp("0.2"), fp("0.3")]);
let b = a.clone();
let standard = a.dot(&b);
let precise = a.dot_precise(&b);
let expected = fp("0.14");
#[cfg(table_format = "q16_16")]
let tolerance = fp("0.01");
#[cfg(not(table_format = "q16_16"))]
let tolerance = fp("0.0000001");
let diff_standard = (standard - expected).abs();
let diff_precise = (precise - expected).abs();
assert!(diff_standard < tolerance,
"standard dot too far: diff={}", diff_standard);
assert!(diff_precise < tolerance,
"compute-tier dot too far: diff={}", diff_precise);
}
#[test]
fn test_matrix_row_col() {
let m = FixedMatrix::from_slice(2, 3, &[
fp("1"), fp("2"), fp("3"),
fp("4"), fp("5"), fp("6"),
]);
let r0 = m.row(0);
assert_eq!(r0, FixedVector::from_slice(&[fp("1"), fp("2"), fp("3")]));
let c1 = m.col(1);
assert_eq!(c1, FixedVector::from_slice(&[fp("2"), fp("5")]));
}
#[test]
fn test_large_identity_multiply() {
let id = FixedMatrix::identity(16);
let result = &id * &id;
assert_eq!(result, id);
}
#[test]
fn test_matrix_multiply_accumulation_16x16() {
let val = fp("0.1");
let a = FixedMatrix::from_fn(16, 16, |_, _| val);
let result = &a * &a;
let expected = fp("0.16");
for r in 0..4 {
for c in 0..4 {
let diff = (result.get(r, c) - expected).abs();
#[cfg(table_format = "q16_16")]
let tolerance = fp("0.01");
#[cfg(not(table_format = "q16_16"))]
let tolerance = fp("0.0000001");
assert!(diff < tolerance,
"16×16 multiply error at ({},{}): got {}, expected {}, diff={}",
r, c, result.get(r, c), expected, diff);
}
}
}
#[test]
fn test_try_sqrt_positive() {
let val = fp("4");
let result = val.try_sqrt();
assert!(result.is_ok());
assert_eq!(result.unwrap(), fp("2"));
}
#[test]
fn test_try_sqrt_negative_returns_domain_error() {
let val = fp("-1");
let result = val.try_sqrt();
assert!(result.is_err());
match result.unwrap_err() {
OverflowDetected::DomainError => {} other => panic!("expected DomainError, got {:?}", other),
}
}
#[test]
fn test_try_exp_normal_value() {
let val = fp("1");
let result = val.try_exp();
assert!(result.is_ok());
let e = result.unwrap();
let diff = (e - fp("2.718281828")).abs();
#[cfg(table_format = "q16_16")]
let exp_tol = fp("0.01");
#[cfg(not(table_format = "q16_16"))]
let exp_tol = fp("0.000000001");
assert!(diff < exp_tol, "exp(1) too far from e: {}", e);
}
#[test]
#[cfg(table_format = "q64_64")]
fn test_try_exp_overflow_returns_tier_overflow() {
let val = fp("44");
let result = val.try_exp();
assert!(result.is_err(), "exp(44) should overflow in this profile, got {:?}", result);
match result.unwrap_err() {
OverflowDetected::TierOverflow => {} other => panic!("expected TierOverflow, got {:?}", other),
}
}
#[test]
#[cfg(not(any(table_format = "q16_16", table_format = "q32_32")))]
fn test_try_exp_near_boundary_succeeds() {
let val = fp("43");
let result = val.try_exp();
assert!(result.is_ok(), "exp(43) should fit in Q64.64, got {:?}", result);
}
#[test]
fn test_try_ln_domain_error() {
let val = fp("-5");
let result = val.try_ln();
assert!(result.is_err());
match result.unwrap_err() {
OverflowDetected::DomainError => {}
other => panic!("expected DomainError for ln(-5), got {:?}", other),
}
}
#[test]
fn test_try_sin_cos_always_succeed() {
let val = fp("100");
assert!(val.try_sin().is_ok());
assert!(val.try_cos().is_ok());
}
#[test]
fn test_try_asin_domain_error() {
let val = fp("2"); let result = val.try_asin();
assert!(result.is_err(), "asin(2) should be domain error");
}