peroxide/special/
lanczos.rs1use crate::statistics::ops::{double_factorial, factorial, C};
4use crate::structure::matrix::Matrix;
5use crate::traits::matrix::MatrixTrait;
6use crate::traits::pointer::{Oxide, RedoxCommon};
7use crate::util::non_macro::zeros;
8use crate::util::useful::sgn;
9use std::f64::consts::PI;
10
11const G: f64 = 5f64;
12const N: usize = 7;
13
14const LG5N7: [f64; 7] = [
16 1.000000000189712,
17 76.18009172948503,
18 -86.50532032927205,
19 24.01409824118972,
20 -1.2317395783752254,
21 0.0012086577526594748,
22 -0.00000539702438713199,
23];
24
25pub fn ln_gamma_approx(z: f64) -> f64 {
26 let z = z - 1f64;
27 let base = z + G + 0.5;
28 let mut s = 0f64;
29 for i in 1..N {
30 s += LG5N7[i] / (z + i as f64);
31 }
32 s += LG5N7[0];
33 (2f64 * PI).sqrt().ln() + s.ln() - base + base.ln() * (z + 0.5)
34}
35
36pub fn gamma_approx(z: f64) -> f64 {
37 if z > 1f64 {
38 let z_int = z as usize;
39 if z - (z_int as f64) == 0f64 {
40 return factorial(z_int - 1) as f64;
41 }
42 }
43
44 if z < 0.5 {
45 PI / ((PI * z).sin() * gamma_approx(1f64 - z))
46 } else {
47 ln_gamma_approx(z).exp()
48 }
49}
50
51pub fn tlg1(g: f64, n: usize) -> Vec<f64> {
53 (lanczos_coeff(g, n - 1).ox() * g.exp() / (2f64 * PI).sqrt()).red()
54}
55
56fn lanczos_coeff(g: f64, n: usize) -> Vec<f64> {
57 let m = dr_gen(n) * b_gen(n) * (c_gen(n) * dc_gen(n));
58 let f = f_gen(g, n);
59 m * f
60}
61
62fn b_gen(n: usize) -> Matrix {
63 Matrix::from_index(
64 |i, j| {
65 if i == 0 {
66 1f64
67 } else if j >= i {
68 sgn(j - i) * C(i + j - 1, j - i) as f64
69 } else {
70 0f64
71 }
72 },
73 (n + 1, n + 1),
74 )
75}
76
77fn c_gen(n: usize) -> Matrix {
78 Matrix::from_index(
79 |i, j| {
80 if i == 0 && j == 0 {
81 0.5
82 } else if j > i {
83 0f64
84 } else {
85 sgn(i - j) * 4f64.powi(j as i32) * (i as f64) * (C(i + j, 2 * j) as f64)
86 / (i + j) as f64
87 }
88 },
89 (n + 1, n + 1),
90 )
91}
92
93fn dc_gen(n: usize) -> Matrix {
94 let mut m = zeros(n + 1, n + 1);
95 m[(0, 0)] = 2f64;
96 for i in 1..n + 1 {
97 m[(i, i)] = 2f64 * double_factorial(2 * i - 1) as f64;
98 }
99 m
100}
101
102fn dr_gen(n: usize) -> Matrix {
103 let mut m = zeros(n + 1, n + 1);
104 m[(0, 0)] = 1f64;
105 for i in 1..n + 1 {
106 m[(i, i)] = -((i * C(2 * i - 1, i)) as f64);
107 }
108 m
109}
110
111fn f(g: f64, n: usize) -> f64 {
112 2f64.sqrt() * (n as f64 + 0.5).exp() / (2f64 * (n as f64 + g) + 1f64).powf(n as f64 + 0.5)
113}
114
115fn f_gen(g: f64, n: usize) -> Vec<f64> {
116 let mut v = vec![0f64; n + 1];
117 for i in 0..n + 1 {
118 v[i] = f(g, i);
119 }
120 v
121}