use crate::error::{SpecialError, SpecialResult};
#[inline]
pub fn airy_ai(x: f64) -> f64 {
crate::airy::ai(x)
}
#[inline]
pub fn airy_bi(x: f64) -> f64 {
crate::airy::bi(x)
}
#[inline]
pub fn airy_ai_prime(x: f64) -> f64 {
crate::airy::aip(x)
}
#[inline]
pub fn airy_bi_prime(x: f64) -> f64 {
crate::airy::bip(x)
}
pub fn airy_ai_zeros(n: usize) -> SpecialResult<Vec<f64>> {
if n == 0 {
return Err(SpecialError::ValueError(
"airy_ai_zeros: n must be >= 1".to_string(),
));
}
let mut zeros = Vec::with_capacity(n);
for k in 1..=n {
let z: f64 = crate::airy::ai_zeros(k)?;
zeros.push(z);
}
Ok(zeros)
}
pub fn airy_bi_zeros(n: usize) -> SpecialResult<Vec<f64>> {
if n == 0 {
return Err(SpecialError::ValueError(
"airy_bi_zeros: n must be >= 1".to_string(),
));
}
let mut zeros = Vec::with_capacity(n);
for k in 1..=n {
let z: f64 = crate::airy::bi_zeros(k)?;
zeros.push(z);
}
Ok(zeros)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_airy_ai_at_zero() {
assert_relative_eq!(airy_ai(0.0), 0.3550280538878172, epsilon = 1e-10);
}
#[test]
fn test_airy_ai_positive() {
assert_relative_eq!(airy_ai(1.0), 0.1352924163128814, epsilon = 1e-10);
assert_relative_eq!(airy_ai(2.0), 0.03492413042327235, epsilon = 1e-10);
}
#[test]
fn test_airy_ai_negative() {
assert_relative_eq!(airy_ai(-1.0), 0.5355608832923521, epsilon = 1e-10);
assert_relative_eq!(airy_ai(-2.0), 0.22740742820168557, epsilon = 1e-10);
}
#[test]
fn test_airy_bi_at_zero() {
assert_relative_eq!(airy_bi(0.0), 0.6149266274460007, epsilon = 1e-10);
}
#[test]
fn test_airy_bi_positive() {
assert_relative_eq!(airy_bi(1.0), 1.2074235949528715, epsilon = 1e-10);
}
#[test]
fn test_airy_bi_negative() {
assert_relative_eq!(airy_bi(-1.0), 0.103_997_389_496_944_6, epsilon = 1e-10);
}
#[test]
fn test_airy_ai_prime_at_zero() {
assert_relative_eq!(airy_ai_prime(0.0), -0.25881940379280678, epsilon = 1e-10);
}
#[test]
fn test_airy_ai_prime_values() {
assert_relative_eq!(airy_ai_prime(1.0), -0.16049975743698353, epsilon = 1e-10);
assert_relative_eq!(airy_ai_prime(-1.0), -0.3271928185544436, epsilon = 1e-10);
}
#[test]
fn test_airy_bi_prime_at_zero() {
assert_relative_eq!(airy_bi_prime(0.0), 0.4482883573538264, epsilon = 1e-10);
}
#[test]
fn test_airy_ai_zeros_count() {
let zeros = airy_ai_zeros(5).expect("airy_ai_zeros(5)");
assert_eq!(zeros.len(), 5);
for z in &zeros {
assert!(*z < 0.0, "zero should be negative, got {z}");
}
}
#[test]
fn test_airy_ai_zeros_values() {
let zeros = airy_ai_zeros(3).expect("airy_ai_zeros(3)");
assert_relative_eq!(zeros[0], -2.338107410459767, epsilon = 1e-8);
assert_relative_eq!(zeros[1], -4.087949444130970, epsilon = 1e-6);
assert_relative_eq!(zeros[2], -5.520559828095551, epsilon = 1e-6);
}
#[test]
fn test_airy_bi_zeros_count() {
let zeros = airy_bi_zeros(5).expect("airy_bi_zeros(5)");
assert_eq!(zeros.len(), 5);
for z in &zeros {
assert!(*z < 0.0, "zero should be negative, got {z}");
}
}
#[test]
fn test_airy_bi_zeros_values() {
let zeros = airy_bi_zeros(3).expect("airy_bi_zeros(3)");
assert_relative_eq!(zeros[0], -1.173713222709128, epsilon = 1e-8);
assert_relative_eq!(zeros[1], -3.271093302836353, epsilon = 1e-6);
assert_relative_eq!(zeros[2], -4.830737841662016, epsilon = 1e-6);
}
#[test]
fn test_airy_zeros_n_zero_error() {
assert!(airy_ai_zeros(0).is_err());
assert!(airy_bi_zeros(0).is_err());
}
#[test]
fn test_airy_wronskian() {
for x in [-2.0, -1.0, 0.0, 1.0, 2.0] {
let ai_val = airy_ai(x);
let bi_val = airy_bi(x);
let aip_val = airy_ai_prime(x);
let bip_val = airy_bi_prime(x);
let wronskian = ai_val * bip_val - aip_val * bi_val;
let expected = 1.0 / std::f64::consts::PI;
let diff = (wronskian - expected).abs();
assert!(diff < 1e-9, "Wronskian at x={x}: got {wronskian}, expected {expected}, diff={diff}");
}
}
}