use crate::elliptic::{ellipe, ellipk};
use crate::gamma::{digamma, gamma, polygamma};
use crate::hypergeometric::hyp1f1;
use crate::{bessel, erf as erf_mod};
#[derive(Debug, Clone)]
pub struct DerivativeRule {
pub function: String,
pub wrt: String,
pub formula: String,
}
pub struct SpecialFunctionDerivatives;
impl SpecialFunctionDerivatives {
pub fn gamma_derivative(x: f64) -> f64 {
let h = 1e-5_f64;
(-gamma(x + 2.0 * h) + 8.0 * gamma(x + h) - 8.0 * gamma(x - h) + gamma(x - 2.0 * h))
/ (12.0 * h)
}
pub fn gamma_nth_derivative(x: f64, n: usize) -> f64 {
let pg_order = if n == 0 { 0u32 } else { (n as u32) - 1 };
let psi = polygamma(pg_order, x);
gamma(x) * psi
}
pub fn hyp1f1_derivative_z(a: f64, b: f64, z: f64) -> f64 {
let ratio = a / b;
let shifted = hyp1f1(a + 1.0, b + 1.0, z).unwrap_or(f64::NAN);
ratio * shifted
}
pub fn hyp1f1_derivative_a(a: f64, b: f64, z: f64) -> f64 {
let h = 1e-5_f64;
let f = |av: f64| hyp1f1(av, b, z).unwrap_or(f64::NAN);
(-f(a + 2.0 * h) + 8.0 * f(a + h) - 8.0 * f(a - h) + f(a - 2.0 * h)) / (12.0 * h)
}
pub fn bessel_j_derivative(n: i32, x: f64) -> f64 {
(bessel::jn(n - 1, x) - bessel::jn(n + 1, x)) / 2.0
}
pub fn bessel_i_derivative(n: i32, x: f64) -> f64 {
let inm1 = bessel::iv(f64::from(n - 1), x);
let inp1 = bessel::iv(f64::from(n + 1), x);
(inm1 + inp1) / 2.0
}
pub fn elliptic_k_derivative(k: f64) -> f64 {
let m = k * k;
let k_val = ellipk(m);
let e_val = ellipe(m);
(e_val - (1.0 - m) * k_val) / (k * (1.0 - m))
}
pub fn complex_step_deriv<F: Fn(f64) -> f64>(f: F, x: f64) -> f64 {
let h = 1e-6_f64;
(-f(x + 2.0 * h) + 8.0 * f(x + h) - 8.0 * f(x - h) + f(x - 2.0 * h)) / (12.0 * h)
}
pub fn rules() -> Vec<DerivativeRule> {
vec![
DerivativeRule {
function: "Gamma".to_string(),
wrt: "x".to_string(),
formula: "Gamma(x) * digamma(x)".to_string(),
},
DerivativeRule {
function: "LogGamma".to_string(),
wrt: "x".to_string(),
formula: "digamma(x)".to_string(),
},
DerivativeRule {
function: "erf".to_string(),
wrt: "x".to_string(),
formula: "(2/sqrt(pi)) * exp(-x^2)".to_string(),
},
DerivativeRule {
function: "erfc".to_string(),
wrt: "x".to_string(),
formula: "-(2/sqrt(pi)) * exp(-x^2)".to_string(),
},
DerivativeRule {
function: "J_n".to_string(),
wrt: "x".to_string(),
formula: "(J_{n-1}(x) - J_{n+1}(x)) / 2".to_string(),
},
DerivativeRule {
function: "I_n".to_string(),
wrt: "x".to_string(),
formula: "(I_{n-1}(x) + I_{n+1}(x)) / 2".to_string(),
},
DerivativeRule {
function: "1F1(a;b;z)".to_string(),
wrt: "z".to_string(),
formula: "(a/b) * 1F1(a+1;b+1;z)".to_string(),
},
DerivativeRule {
function: "K(k)".to_string(),
wrt: "k".to_string(),
formula: "[E(k) - (1-k^2) K(k)] / [k(1-k^2)]".to_string(),
},
]
}
}