use crate::ffi;
use alloc::{vec, vec::Vec};
use core::ffi::{c_int, c_uint};
pub fn legendre_p(n: u32, x: f64) -> f64 {
unsafe { ffi::math_legendre_p(n as c_int, x) }
}
#[doc(alias = "legendre_p_derivative")]
pub fn legendre_p_prime(n: u32, x: f64) -> f64 {
unsafe { ffi::math_legendre_p_prime(n as c_int, x) }
}
pub fn legendre_p_assoc(n: u32, m: i32, x: f64) -> f64 {
unsafe { ffi::math_legendre_p_assoc(n as c_int, m as c_int, x) }
}
pub fn legendre_p_zeros(n: usize) -> Vec<f64> {
let mut out = vec![f64::NAN; n.div_ceil(2)];
unsafe { ffi::math_legendre_p_zeros(n as c_int, out.as_mut_ptr()) };
out
}
pub fn legendre_q(n: u32, x: f64) -> f64 {
unsafe { ffi::math_legendre_q(n as c_uint, x) }
}
#[inline(always)]
#[allow(non_snake_case)]
#[doc(alias = "legendre_p_next")]
#[doc(alias = "legendre_q_next")]
pub fn legendre_next(n: u32, x: f64, Pn: f64, Pn_prev: f64) -> f64 {
legendre_assoc_next(n, 0, x, Pn, Pn_prev)
}
#[inline(always)]
#[allow(non_snake_case)]
#[doc(alias = "legendre_p_assoc_next")]
pub fn legendre_assoc_next(n: u32, m: i32, x: f64, Pn: f64, Pn_prev: f64) -> f64 {
let n = n as i32;
((2 * n + 1) as f64 * x * Pn - (n + m) as f64 * Pn_prev) / ((n - m + 1) as f64)
}
#[cfg(test)]
mod tests {
use super::*;
const ATOL: f64 = f64::EPSILON;
const LN_3: f64 = 1.098_612_288_668_109_8; const SQRT_3: f64 = 1.732_050_807_568_877_2; const FRAC_1_SQRT_3: f64 = 0.577_350_269_189_625_7; const SQRT_FRAC_3_5: f64 = 0.774_596_669_241_483_4;
#[test]
fn test_legendre_p() {
assert_eq!(legendre_p(0, 0.5), 1.0);
assert_eq!(legendre_p(1, 0.5), 0.5);
assert_eq!(legendre_p(2, 0.5), -0.125);
}
#[test]
fn test_legendre_p_assoc() {
assert_eq!(legendre_p_assoc(0, 0, 0.5), 1.0);
assert_eq!(legendre_p_assoc(1, 0, 0.5), 0.5);
assert_eq!(legendre_p_assoc(2, 0, 0.5), -0.125);
assert_eq!(legendre_p_assoc(0, 1, 0.5), 0.0);
assert_abs_diff_eq!(legendre_p_assoc(1, 1, 0.5), -0.5 * SQRT_3, epsilon = ATOL);
assert_abs_diff_eq!(legendre_p_assoc(2, 1, 0.5), -0.75 * SQRT_3, epsilon = ATOL);
}
#[test]
fn test_legendre_p_prime() {
assert_eq!(legendre_p_prime(0, 0.5), 0.0);
assert_eq!(legendre_p_prime(1, 0.5), 1.0);
assert_eq!(legendre_p_prime(2, 0.5), 1.5);
}
#[test]
fn test_legendre_p_zeros() {
assert_eq!(legendre_p_zeros(0), vec![]);
assert_eq!(legendre_p_zeros(1), vec![0.0]);
assert_eq!(legendre_p_zeros(2), vec![FRAC_1_SQRT_3]);
assert_eq!(legendre_p_zeros(3), vec![0.0, SQRT_FRAC_3_5]);
}
#[test]
fn test_legendre_q() {
assert_abs_diff_eq!(legendre_q(0, 0.5), 0.5 * LN_3, epsilon = ATOL);
assert_abs_diff_eq!(legendre_q(1, 0.5), 0.25 * LN_3 - 1.0, epsilon = ATOL);
assert_abs_diff_eq!(legendre_q(2, 0.5), -0.0625 * LN_3 - 0.75, epsilon = ATOL);
}
}