quantwave_core/regimes/
ecld.rs1use statrs::distribution::{ContinuousCDF, Normal};
8use statrs::function::gamma::{gamma, gamma_lr};
9
10#[inline]
15pub fn ecld_pdf(x: f64, mu: f64, sigma: f64, lambda: f64) -> f64 {
16 if (lambda - 1.0).abs() < 1e-12 {
17 return gaussian_pdf(x, mu, sigma);
18 }
19 let beta = 2.0 / lambda;
20 let z = ((x - mu) / sigma).abs();
21 let norm = beta / (2.0 * sigma * gamma(1.0 / beta));
22 norm * (-z.powf(beta)).exp()
23}
24
25#[inline]
26pub fn ecld_log_pdf(x: f64, mu: f64, sigma: f64, lambda: f64) -> f64 {
27 ecld_pdf(x, mu, sigma, lambda).ln()
28}
29
30#[inline]
32pub fn ecld_cdf(x: f64, mu: f64, sigma: f64, lambda: f64) -> f64 {
33 if (lambda - 1.0).abs() < 1e-12 {
34 return Normal::new(mu, sigma)
35 .expect("valid gaussian cdf params")
36 .cdf(x);
37 }
38 let beta = 2.0 / lambda;
39 let u = (x - mu) / sigma;
40 let p = gamma_lr(1.0 / beta, u.abs().powf(beta));
41 if u >= 0.0 {
42 0.5 + 0.5 * p
43 } else {
44 0.5 - 0.5 * p
45 }
46}
47
48#[inline]
50pub fn ecld_variance(sigma: f64, lambda: f64) -> f64 {
51 if (lambda - 1.0).abs() < 1e-12 {
52 return sigma * sigma;
53 }
54 let beta = 2.0 / lambda;
55 let s2 = sigma * sigma;
56 s2 * gamma(3.0 / beta) / gamma(1.0 / beta)
57}
58
59#[inline]
60fn gaussian_pdf(x: f64, mu: f64, sigma: f64) -> f64 {
61 let variance = sigma * sigma;
62 let denom = (2.0 * std::f64::consts::PI * variance).sqrt();
63 let exponent = -((x - mu).powi(2)) / (2.0 * variance);
64 exponent.exp() / denom
65}
66
67pub fn work_to_natural(mu: f64, log_sigma: f64, log_lambda: f64) -> (f64, f64, f64) {
71 (mu, log_sigma.exp(), log_lambda.exp())
72}
73
74pub fn natural_to_work(mu: f64, sigma: f64, lambda: f64) -> (f64, f64, f64) {
75 (mu, sigma.ln(), lambda.ln())
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use approx::assert_relative_eq;
82
83 #[test]
84 fn lambda_one_matches_gaussian() {
85 let x = 0.005;
86 let mu = 0.008;
87 let sigma = 0.018;
88 let g = gaussian_pdf(x, mu, sigma);
89 let l = ecld_pdf(x, mu, sigma, 1.0);
90 assert_relative_eq!(l, g, epsilon = 1e-15);
91 }
92
93 #[test]
94 fn leptokurtic_lambda_increases_center_density() {
95 let x = 0.008; let mu = 0.008;
97 let sigma = 0.018;
98 let g = ecld_pdf(x, mu, sigma, 1.0);
99 let l = ecld_pdf(x, mu, sigma, 1.3);
100 assert!(l > g);
101 }
102}