clausen 1.0.1

Rust implementation of Clausen functions.
Documentation
use crate::general::{co, si};
use crate::range_reduction::{range_reduce_even, range_reduce_odd};
use num::Complex;
use polylog::Li;

/// Standard Clausen function Cl_n(x) for a real argument
pub fn cln(n: i32, x: f64) -> f64 {
    if n < 1 {
        cln_neg(n, x)
    } else {
        cln_pos(n, x)
    }
}


/// Standard Clausen function Cl_n(x) for a real argument and n < 1
fn cln_neg(n: i32, x: f64) -> f64 {
    let eix = Complex::cis(x); // e^(i*x)

    if is_even(n) {
        if x == 0.0 {
            x
        } else {
            eix.li(n).im
        }
    } else {
        eix.li(n).re
    }
}


/// Standard Clausen function Cl_n(x) for a real argument and n > 0
fn cln_pos(n: i32, x: f64) -> f64 {
    let (r, sgn) = range_reduce(n, x);

    if is_even(n) && r == 0.0 {
        r
    } else if is_even(n) && r == core::f64::consts::PI {
        0.0
    } else if n < 10 {
        sgn*cln_pos_zeta(n, r)
    } else {
        sgn*cln_pos_series(n, r)
    }
}


/// Series expansion of Cl_n(x) in terms of the zeta function from
/// [Jiming Wu, Xiaoping Zhang, Dongjie Liu, "An efficient calculation
/// of the Clausen functions Cl_n(θ)(n >= 2)", Bit Numer Math 50,
/// 193-206 (2010), https://doi.org/10.1007/s10543-009-0246-8].
fn cln_pos_zeta(n: i32, x: f64) -> f64 {
    // first line in Eq.(2.13)
    let term1 = if x == 0.0 {
        0.0
    } else {
        let sgn = if is_even((n + 1)/2) { 1.0 } else { -1.0 };
        sgn*x.powi(n - 1)*inv_fac(n - 1)*(2.0*(0.5*x).sin()).ln()
    };

    // second line in Eq.(2.13)
    let sgn = if is_even(n/2) { 1.0 } else { -1.0 };
    let term2 = pcal(n, x) - sgn*inv_fac(n - 2)*nsum(n, x);

    term1 + term2
}


/// returns 1/n!
fn inv_fac(n: i32) -> f64 {
    [1.0, 1.0, 0.5, 1.0/6.0, 1.0/24.0, 1.0/120.0, 1.0/720.0, 1.0/5040.0, 1.0/40320.0][n as usize]
}


/// returns P_n(x)
fn pcal(n: i32, x: f64) -> f64 {
    let mut sum = 0.0;
    let x2 = x*x;
    let fl = (n - 1)/2;

    for i in (3..=n).step_by(2) {
        let sgn = if is_even(fl + (i - 1)/2) { 1.0 } else { -1.0 };
        sum = x2*sum + sgn*zeta(i)*inv_fac(n - i);
    }

    if is_even(n) {
        sum *= x;
    }

    sum
}


/// returns zeta(n) for n = 2,...,9
fn zeta(n: i32) -> f64 {
    [1.6449340668482264, 1.2020569031595943, 1.0823232337111382,
     1.0369277551433699, 1.0173430619844491, 1.0083492773819228,
     1.0040773561979443, 1.0020083928260822][(n - 2) as usize]
}


/// returns sum in Eq.(2.13), n > 1
fn nsum(n: i32, x: f64) -> f64 {
    let mut sum = 0.0;
    let mut xn = 1.0;

    for i in 0..=(n - 3) {
        sum += binomial(n - 2, i)*xn*ncal(n - 2 - i, x);
        xn *= -x;
    }

    sum + xn*ncal(0, x)
}


/// returns N_n(x) from Eq.(2.11)
fn ncal(n: i32, x: f64) -> f64 {
    let mut sum = 0.0;
    let xn1 = x.powi(n + 1);
    let x2 = x*x;
    let mut xn = xn1*x2; // x^(n + 3)

    for (k, bn) in B.iter().enumerate() {
        let old_sum = sum;
        sum += bn*xn/((2*(k as i32) + n + 3) as f64);
        if sum == old_sum { break; }
        xn *= x2;
    }

    (xn1/((n + 1) as f64) + sum)/((n + 1) as f64)
}


/// returns the binomial coefficient (n, k)
fn binomial(n: i32, k: i32) -> f64 {
    [[1.0, 0.0,  0.0,  0.0,   0.0,   0.0,  0.0,  0.0],
     [1.0, 1.0,  0.0,  0.0,   0.0,   0.0,  0.0,  0.0],
     [1.0, 2.0,  1.0,  0.0,   0.0,   0.0,  0.0,  0.0],
     [1.0, 3.0,  3.0,  1.0,   0.0,   0.0,  0.0,  0.0],
     [1.0, 4.0,  6.0,  4.0,   1.0,   0.0,  0.0,  0.0],
     [1.0, 5.0, 10.0, 10.0,   5.0,   1.0,  0.0,  0.0],
     [1.0, 6.0, 15.0, 20.0,  15.0,   6.0,  1.0,  0.0],
     [1.0, 7.0, 21.0, 35.0,  35.0,  21.0,  7.0,  1.0]
    ][n as usize][k as usize]
}


/// Series expansion of Cl_n(x) in terms of sin(x) and cos(x)
fn cln_pos_series(n: i32, x: f64) -> f64 {
    if is_even(n) {
        si(n, x)
    } else {
        co(n, x)
    }
}


/// map x to [0,pi] using the symmetries of Cl_n(x)
fn range_reduce(n: i32, x: f64) -> (f64, f64) {
    if is_even(n) {
        range_reduce_even(x)
    } else {
        (range_reduce_odd(x), 1.0)
    }
}


fn is_even(n: i32) -> bool {
    n % 2 == 0
}


// (-1)^k B_{2k}/(2k)! where B_{2k} are the even Bernoulli numbers
// B(k) = 2*(-1)^(2*k + 1)*SpecialFunctions.zeta(2*k)/(2*pi)^(2*k)
const B: [f64; 202] = [
    -8.3333333333333333e-002,-1.3888888888888889e-003,-3.3068783068783069e-005,-8.2671957671957672e-007,
    -2.0876756987868099e-008,-5.2841901386874932e-010,-1.3382536530684679e-011,-3.3896802963225829e-013,
    -8.5860620562778446e-015,-2.1748686985580619e-016,-5.5090028283602295e-018,-1.3954464685812523e-019,
    -3.5347070396294675e-021,-8.9535174270375469e-023,-2.2679524523376831e-024,-5.7447906688722024e-026,
    -1.4551724756148649e-027,-3.6859949406653102e-029,-9.3367342570950447e-031,-2.3650224157006299e-032,
    -5.9906717624821343e-034,-1.5174548844682903e-035,-3.8437581254541882e-037,-9.7363530726466910e-039,
    -2.4662470442006810e-040,-6.2470767418207437e-042,-1.5824030244644914e-043,-4.0082736859489360e-045,
    -1.0153075855569556e-046,-2.5718041582418717e-048,-6.5144560352338149e-050,-1.6501309906896525e-051,
    -4.1798306285394759e-053,-1.0587634667702909e-054,-2.6818791912607707e-056,-6.7932793511074212e-058,
    -1.7207577616681405e-059,-4.3587303293488938e-061,-1.1040792903684667e-062,-2.7966655133781345e-064,
    -7.0840365016794702e-066,-1.7944074082892241e-067,-4.5452870636110961e-069,-1.1513346631982052e-070,
    -2.9163647710923614e-072,-7.3872382634973376e-074,-1.8712093117637953e-075,-4.7398285577617994e-077,
    -1.2006125993354507e-078,-3.0411872415142924e-080,-7.7034172747051063e-082,-1.9512983909098831e-083,
    -4.9426965651594615e-085,-1.2519996659171848e-086,-3.1713522017635155e-088,-8.0331289707353345e-090,
    -2.0348153391661466e-091,-5.1542474664474739e-093,-1.3055861352149467e-094,-3.3070883141750912e-096,
    -8.3769525600490913e-098,-2.1219068717497138e-099,-5.3748528956122803e-101,-1.3614661432172069e-102,
    -3.4486340279933990e-104,-8.7354920416383551e-106,-2.2127259833925497e-107,-5.6049003928372242e-109,
    -1.4197378549991788e-110,-3.5962379982587627e-112,-9.1093772660782319e-114,-2.3074322171091233e-115,
    -5.8447940852990020e-117,-1.4805036371705745e-118,-3.7501595226227197e-120,-9.4992650419929583e-122,
    -2.4061919444675199e-123,-6.0949553971026848e-125,-1.5438702377042471e-126,-3.9106689968592923e-128,
    -9.9058402898794298e-130,-2.5091786578563553e-131,-6.3558237896024598e-133,-1.6099489734616250e-134,
    -4.0780483898724622e-136,-1.0329817245315190e-137,-2.6165732752609202e-139,-6.6278575334086228e-141,
    -1.6788559257443673e-142,-4.2525917390343006e-144,-1.0771940713664573e-145,-2.7285644580839580e-147,
    -6.9115345134370137e-149,-1.7507121442157682e-150,-4.4346056667239196e-152,-1.1232987378487150e-153,
    -2.8453489425693971e-155,-7.2073530684151368e-157,-1.8256438595501418e-158,-4.6244099189746555e-160,
    -1.1713767165946985e-161,-2.9671318854112523e-163,-7.5158328663197353e-165,-1.9037827051837494e-166,
    -4.8223379271757316e-168,-1.2215124667619569e-169,-3.0941272241548313e-171,-7.8375158172837117e-173,
    -1.9852659485568249e-174,-5.0287373938151486e-176,-1.2737940624195893e-177,-3.2265580530233667e-179,
    -8.1729670255761088e-181,-2.0702367322529201e-182,-5.2439709032927841e-184,-1.3283133472690102e-185,
    -3.3646570148302941e-187,-8.5227757823275058e-189,-2.1588443254591854e-190,-5.4684165588767235e-192,
    -1.3851660959868732e-193,-3.5086667096656512e-195,-8.8875566007447618e-197,-2.2512443861893281e-198,
    -5.7024686469217722e-200,-1.4444521824735857e-201,-3.6588401210745441e-203,-9.2679502956336812e-205,
    -2.3475992347298971e-206,-5.9465383295169881e-208,-1.5062757553029781e-209,-3.8154410604763518e-211,
    -9.6646251091260105e-213,-2.4480781387902631e-214,-6.2010543667790175e-216,-1.5707454206813435e-217,
    -3.9787446306053875e-219,-1.0078277884588346e-220,-2.5528576108572180e-222,-6.4664638700600961e-224,
    -1.6379744332372530e-225,-4.1490377087871461e-227,-1.0509635290775169e-228,-2.6621217182765621e-230,
    -6.7432330873938832e-232,-1.7080808949773099e-233,-4.3266194508991167e-235,-1.0959455098376500e-236,
    -2.7760624066064009e-238,-7.0318482225589324e-240,-1.7811879627573501e-241,-4.5118018169014740e-243,
    -1.1428527511202687e-244,-2.8948798368101921e-246,-7.3328162891986569e-248,-1.8574240646335573e-249,
    -4.7049101188608530e-251,-1.1917676554344843e-252,-3.0187827368818927e-254,-7.6466660014982318e-256,
    -1.9369231254735576e-257,-4.9062835924299293e-259,-1.2427761521749539e-260,-3.1479887685209103e-262,
    -7.9739487029830971e-264,-2.0198248022238287e-265,-5.1162759927867278e-267,-1.2959678485750701e-268,
    -3.2827249095010017e-270,-8.3152393350706909e-272,-2.1062747292467202e-273,-5.3352562160805552e-275,
    -1.3514361871210552e-276,-3.4232278524048296e-278,-8.6711374470768819e-280,-2.1964247741580717e-281,
    -5.5636089474762561e-283,-1.4092786097034883e-284,-3.5697444204246398e-286,-9.0422682494513886e-288,
    -2.2904333046148606e-289,-5.8017353369352214e-291,-1.4695967287946349e-292,-3.7225320009595016e-294,
    -9.4292837120924187e-296,-2.3884654665215509e-297,-6.0500537039203004e-299,-1.5324965059522865e-300,
    -3.8818589977708149e-302,-9.8328637096699497e-304,-2.4906934741438690e-305,-6.3090002722625804e-307,
    -1.5980884379636898e-308,-4.0480053024903931e-310,-1.0253717215969654e-311,-2.5972969126396544e-313,
    -6.5790299364809836e-315,-1.6664877509565689e-316,-4.2212627863094242e-318,-1.0692583549355590e-319,
    -2.7084630535382438e-321,-6.8606170609008831e-323
];