akar_function/scalar/
utils.rs1use super::{REGEX_CACHE, RNG_STATE};
4
5pub(crate) fn get_cached_regex(pattern: &str) -> Result<regex::Regex, String> {
7 let mut cache = REGEX_CACHE.lock().map_err(|e| format!("Regex cache lock error: {e}"))?;
8 if let Some(re) = cache.get(pattern) {
9 return Ok(re.clone());
10 }
11 let re = regex::Regex::new(pattern).map_err(|e| format!("Regex error: {e}"))?;
12 cache.insert(pattern.to_string(), re.clone());
13 Ok(re)
14}
15
16pub(crate) fn rng_next() -> f64 {
18 RNG_STATE.with(|state| {
19 let old = state.get();
20 let new = old.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
21 state.set(new);
22 (new >> 11) as f64 / (1u64 << 53) as f64
23 })
24}
25
26pub(crate) fn log_gamma(x: f64) -> f64 {
28 if x < 0.5 {
29 let pi = std::f64::consts::PI;
30 let reflection = pi / (pi * x).sin();
31 reflection.abs().ln() - log_gamma(1.0 - x)
32 } else {
33 let xm1 = x - 1.0;
34 let g = 7.0;
35 let c = [
36 0.999_999_999_999_809_9,
37 676.5203681218851,
38 -1259.1392167224028,
39 771.323_428_777_653_1,
40 -176.615_029_162_140_6,
41 12.507343278686905,
42 -0.13857109526572012,
43 9.984_369_578_019_572e-6,
44 1.5056327351493116e-7,
45 ];
46 let t = xm1 + g + 0.5;
47 let mut s = c[0];
48 for (i, &ci) in c[1..].iter().enumerate() {
49 s += ci / (xm1 + (i as f64) + 1.0);
50 }
51 let sqrt_2pi = (2.0 * std::f64::consts::PI).sqrt();
52 (sqrt_2pi * s).ln() + (xm1 + 0.5) * t.ln() - t
53 }
54}
55
56pub(crate) fn gamma_func(x: f64) -> f64 {
58 log_gamma(x).exp()
59}
60
61pub fn set_rng_seed(seed: u64) {
63 RNG_STATE.with(|state| state.set(seed));
64}