use crate::{
dawsn, i0, i0e, i1, i1e, iv, ive, j0, j0e, j1, j1e, jn, jne, jv, jve, k0, k0e, k1, k1e, kv,
kve, polygamma, y0, y0e, y1, y1e, yn, yne,
};
use approx::assert_relative_eq;
#[allow(dead_code)]
pub fn test_exponentially_scaled_bessel_consistency() -> Result<(), String> {
println!("Testing exponentially scaled Bessel function consistency...");
let test_values = vec![0.1f64, 0.5, 1.0, 2.0, 5.0, 10.0];
for &x in &test_values {
assert_relative_eq!(j0e(x), j0(x), epsilon = 1e-12);
assert_relative_eq!(j1e(x), j1(x), epsilon = 1e-12);
assert_relative_eq!(jne(5, x), jn(5, x), epsilon = 1e-12);
assert_relative_eq!(jve(2.5, x), jv(2.5, x), epsilon = 1e-12);
if x > 0.0 {
assert_relative_eq!(y0e(x), y0(x), epsilon = 1e-12);
assert_relative_eq!(y1e(x), y1(x), epsilon = 1e-12);
assert_relative_eq!(yne(3, x), yn(3, x), epsilon = 1e-12);
}
let exp_neg_x = (-x).exp();
assert_relative_eq!(i0e(x), i0(x) * exp_neg_x, epsilon = 1e-12);
assert_relative_eq!(i1e(x), i1(x) * exp_neg_x, epsilon = 1e-12);
assert_relative_eq!(ive(2.5, x), iv(2.5, x) * exp_neg_x, epsilon = 1e-12);
if x > 0.0 {
let exp_x = x.exp();
assert_relative_eq!(k0e(x), k0(x) * exp_x, epsilon = 1e-12);
assert_relative_eq!(k1e(x), k1(x) * exp_x, epsilon = 1e-12);
assert_relative_eq!(kve(2.5, x), kv(2.5, x) * exp_x, epsilon = 1e-12);
}
}
println!("✓ Exponentially scaled Bessel functions consistency test passed");
Ok(())
}
#[allow(dead_code)]
pub fn test_dawson_integral_properties() -> Result<(), String> {
println!("Testing Dawson's integral mathematical properties...");
assert_relative_eq!(dawsn(0.0), 0.0, epsilon = 1e-15);
let test_values = vec![0.1f64, 0.5, 1.0, 2.0, 3.0];
for &x in &test_values {
let d_pos = dawsn(x);
let d_neg = dawsn(-x);
assert_relative_eq!(d_pos, -d_neg, epsilon = 1e-14);
}
let d1 = dawsn(1.0);
println!(" dawsn(1.0) = {d1:.16}, reference ≈ 0.5380795069127684");
assert_relative_eq!(d1, 0.5380795069127684, epsilon = 1e-10);
for &x in &[10.0f64, 20.0, 50.0] {
let d_val = dawsn(x);
let asymptotic = 1.0 / (2.0 * x);
let relative_error = (d_val - asymptotic).abs() / asymptotic;
assert!(
relative_error < 2.0,
"dawsn({x}) = {d_val}, asymptotic = {asymptotic}, rel_error = {relative_error}"
);
}
for &x in &[0.001f64, 0.01, 0.1] {
let d_val = dawsn(x);
let relative_error = (d_val - x).abs() / x;
assert!(relative_error < 0.1); }
println!("✓ Dawson's integral properties test passed");
Ok(())
}
#[allow(dead_code)]
pub fn test_polygamma_properties() -> Result<(), String> {
println!("Testing polygamma function mathematical properties...");
for &x in &[1.0f64, 2.0, 3.0, 5.0] {
let psi0 = polygamma(0, x);
let digamma_val = crate::digamma(x);
assert_relative_eq!(psi0, digamma_val, epsilon = 1e-12);
}
let euler_gamma = 0.5772156649015329;
assert_relative_eq!(polygamma(0, 1.0), -euler_gamma, epsilon = 1e-8);
let pi_squared_over_6 = std::f64::consts::PI.powi(2) / 6.0;
let psi1_1: f64 = polygamma(1, 1.0);
println!(" polygamma(1, 1.0) = {psi1_1:.16}, expected π²/6 ≈ {pi_squared_over_6:.16}");
assert_relative_eq!(psi1_1, pi_squared_over_6, epsilon = 1e-8);
let x_vals = [1.0f64, 2.0, 3.0, 4.0, 5.0];
for i in 1..x_vals.len() {
let psi1_prev = polygamma(1, x_vals[i - 1]);
let psi1_curr = polygamma(1, x_vals[i]);
assert!(psi1_curr > 0.0, "trigamma should be positive");
assert!(
psi1_curr < psi1_prev,
"trigamma should be strictly decreasing for positive x"
);
}
for n in 1..=4 {
for &x in &[1.0f64, 2.0, 5.0] {
let psi_n = polygamma(n, x);
assert!(psi_n.is_finite(), "polygamma({n}, {x}) should be finite");
}
}
println!("✓ Polygamma function properties test passed");
Ok(())
}
#[allow(dead_code)]
pub fn test_numerical_stability() -> Result<(), String> {
println!("Testing numerical stability for extreme values...");
let small_vals = vec![1e-10f64, 1e-8, 1e-6];
for &x in &small_vals {
let d_val = dawsn(x);
assert!(d_val.is_finite(), "dawsn({x}) should be finite");
assert!(
d_val.abs() < 1.0,
"dawsn({x}) should be bounded for small x"
);
}
let large_vals = vec![10.0f64, 50.0];
for &x in &large_vals {
let d_val = dawsn(x);
assert!(d_val.is_finite(), "dawsn({x}) should be finite");
assert!(
d_val.abs() < 1.0,
"dawsn({x}) should be bounded for large x"
);
assert!(j0e(x).is_finite(), "j0e({x}) should be finite");
assert!(i0e(x).is_finite(), "i0e({x}) should be finite");
if x > 0.0 {
assert!(k0e(x).is_finite(), "k0e({x}) should be finite");
}
}
for n in 0..=10 {
for &x in &[1.0f64, 2.0, 10.0] {
let psi_n = polygamma(n, x);
assert!(psi_n.is_finite(), "polygamma({n}, {x}) should be finite");
}
}
println!("✓ Numerical stability test passed");
Ok(())
}
#[allow(dead_code)]
pub fn test_reference_values() -> Result<(), String> {
println!("Testing against known reference values...");
let dawson_ref_values = vec![
(0.0, 0.0),
(0.5, 0.4244363835020223), (1.0, 0.5380795069127684), (1.5, 0.4282490710853986), (2.0, 0.30134038892379196), ];
for (x, expected) in dawson_ref_values {
let computed: f64 = dawsn(x);
assert_relative_eq!(computed, expected, epsilon = 1e-10);
}
let polygamma_ref_values = vec![
(0, 1.0, -0.5772156649015329), (0, 2.0, 0.4227843350984671), ];
for (n, x, expected) in polygamma_ref_values {
let computed = polygamma(n, x);
assert_relative_eq!(computed, expected, epsilon = 1e-10);
}
println!("✓ Reference values test passed");
Ok(())
}
#[allow(dead_code)]
pub fn run_extended_validation_tests() -> Result<(), String> {
println!("=== Running Extended Validation Tests ===\n");
test_exponentially_scaled_bessel_consistency()?;
test_dawson_integral_properties()?;
test_polygamma_properties()?;
test_numerical_stability()?;
test_reference_values()?;
println!("\n=== All Extended Validation Tests Passed! ===");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extended_validation() {
run_extended_validation_tests().expect("Extended validation tests should pass");
}
}