pub fn vigampl(x: f64, nmax: usize, m: usize) -> (Vec<f64>, Vec<f64>) {
let mut dv1 = vec![0.0f64; nmax];
let mut dv2 = vec![0.0f64; nmax];
let dx = x.abs();
if (1.0 - dx).abs() <= 1.0e-10 {
if m != 1 {
return (dv1, dv2);
}
for n in 1..=nmax {
let dn0 = (n as f64) * (n as f64 + 1.0);
let mut dn = 0.5 * dn0.sqrt();
if x < 0.0 {
dn *= if (n + 1) % 2 == 0 { 1.0 } else { -1.0 };
}
dv1[n - 1] = dn;
let mut dn2 = dn;
if x < 0.0 {
dn2 = -dn;
}
dv2[n - 1] = dn2;
}
return (dv1, dv2);
}
let qs = (1.0 - x * x).sqrt();
let qs1 = 1.0 / qs;
let dsi = qs1;
if m == 0 {
let mut d1 = 1.0;
let mut d2 = x;
for n in 1..=nmax {
let qn = n as f64;
let qn1 = (n + 1) as f64;
let qn2 = (2 * n + 1) as f64;
let d3 = (qn2 * x * d2 - qn * d1) / qn1;
let der = qs1 * (qn1 * qn / qn2) * (-d1 + d3);
dv1[n - 1] = d2 * dsi;
dv2[n - 1] = der;
d1 = d2;
d2 = d3;
}
} else {
let qmm = (m * m) as f64;
let mut a = 1.0f64;
for i in 1..=m {
let i2 = 2 * i;
a *= ((i2 as f64 - 1.0) / (i2 as f64)).sqrt() * qs;
}
let mut d1 = 0.0f64;
let mut d2 = a;
for n in m..=nmax {
let qn = n as f64;
let qn2 = (2 * n + 1) as f64;
let qn1 = (n + 1) as f64;
let qnm = (qn * qn - qmm).sqrt();
let qnm1 = (qn1 * qn1 - qmm).sqrt();
let d3 = (qn2 * x * d2 - qnm * d1) / qnm1;
let der = qs1 * (-qn1 * qnm * d1 + qn * qnm1 * d3) / qn2;
dv1[n - 1] = d2 * dsi;
dv2[n - 1] = der;
d1 = d2;
d2 = d3;
}
}
(dv1, dv2)
}
pub fn vig(x: f64, nmax: usize, m: usize) -> (Vec<f64>, Vec<f64>) {
let mut dv1 = vec![0.0f64; nmax];
let mut dv2 = vec![0.0f64; nmax];
let dx = x.abs();
if (1.0 - dx).abs() <= 1.0e-10 {
if m != 1 {
return (dv1, dv2);
}
for n in 1..=nmax {
let dn0 = (n as f64) * (n as f64 + 1.0);
let mut dn = 0.5 * dn0.sqrt();
if x < 0.0 {
dn *= if (n + 1) % 2 == 0 { 1.0 } else { -1.0 };
}
dv1[n - 1] = dn;
let mut dn2 = dn;
if x < 0.0 {
dn2 = -dn;
}
dv2[n - 1] = dn2;
}
return (dv1, dv2);
}
let qs = (1.0 - x * x).sqrt();
let qs1 = 1.0 / qs;
if m == 0 {
let mut d1 = 1.0;
let mut d2 = x;
for n in 1..=nmax {
let qn = n as f64;
let qn1 = (n + 1) as f64;
let qn2 = (2 * n + 1) as f64;
let d3 = (qn2 * x * d2 - qn * d1) / qn1;
let der = qs1 * (qn1 * qn / qn2) * (-d1 + d3);
dv1[n - 1] = d2;
dv2[n - 1] = der;
d1 = d2;
d2 = d3;
}
} else {
let qmm = (m * m) as f64;
let mut a = 1.0f64;
for i in 1..=m {
let i2 = 2 * i;
a *= ((i2 as f64 - 1.0) / (i2 as f64)).sqrt() * qs;
}
let mut d1 = 0.0f64;
let mut d2 = a;
for n in m..=nmax {
let qn = n as f64;
let qn2 = (2 * n + 1) as f64;
let qn1 = (n + 1) as f64;
let qnm = (qn * qn - qmm).sqrt();
let qnm1 = (qn1 * qn1 - qmm).sqrt();
let d3 = (qn2 * x * d2 - qnm * d1) / qnm1;
let der = qs1 * (-qn1 * qnm * d1 + qn * qnm1 * d3) / qn2;
dv1[n - 1] = d2;
dv2[n - 1] = der;
d1 = d2;
d2 = d3;
}
}
(dv1, dv2)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
#[test]
fn vigampl_m0_n1_known_values() {
let (dv1, _) = vigampl(0.0, 3, 0);
assert_abs_diff_eq!(dv1[0], 0.0, epsilon = 1e-14);
}
#[test]
fn vig_symmetric_m_zero() {
let (dv_pos, _) = vig(0.3, 5, 0);
let (dv_neg, _) = vig(-0.3, 5, 0);
for n in 1..=5 {
let sign = if n % 2 == 0 { 1.0 } else { -1.0 };
assert_abs_diff_eq!(dv_pos[n - 1], sign * dv_neg[n - 1], epsilon = 1e-13);
}
}
#[test]
fn vig_m_zero_matches_legendre() {
let x = 0.4;
let (dv, _) = vig(x, 4, 0);
assert_abs_diff_eq!(dv[0], x, epsilon = 1e-14);
assert_abs_diff_eq!(dv[1], 0.5 * (3.0 * x * x - 1.0), epsilon = 1e-14);
assert_abs_diff_eq!(dv[2], 0.5 * (5.0 * x.powi(3) - 3.0 * x), epsilon = 1e-13);
}
}