cxgraph/libcxgraph/src/language/builtins.rs

106 lines
3.8 KiB
Rust

use std::{collections::HashMap, ops, f64::consts::{TAU, E}};
use num_complex::Complex64 as Complex;
#[derive(Clone, Copy)]
pub enum Func {
One(fn(Complex) -> Complex),
Two(fn(Complex, Complex) -> Complex),
}
impl Func {
pub fn argc(&self) -> usize {
match self {
Func::One(_) => 1,
Func::Two(_) => 2,
}
}
}
fn neg(z: Complex) -> Complex { -z }
fn re(z: Complex) -> Complex { Complex::from(z.re) }
fn im(z: Complex) -> Complex { Complex::from(z.im) }
fn abs_sq(z: Complex) -> Complex { Complex::from(z.norm_sqr()) }
fn abs(z: Complex) -> Complex { Complex::from(z.norm()) }
fn arg(z: Complex) -> Complex { Complex::from(z.arg()) }
fn recip(z: Complex) -> Complex { Complex::new(1.0, 0.0) / z }
fn conj(z: Complex) -> Complex { z.conj() }
fn gamma(z: Complex) -> Complex {
let reflect = z.re < 0.5;
let zp = if reflect { 1.0 - z } else { z };
let mut w = gamma_inner(zp + 3.0) / (zp*(zp+1.0)*(zp+2.0)*(zp+3.0));
if reflect {
w = TAU * 0.5 / ((TAU * 0.5 * z).sin() * w);
}
return w;
}
// Yang, ZH., Tian, JF. An accurate approximation formula for gamma function. J Inequal Appl 2018, 56 (2018).
// https://doi.org/10.1186/s13660-018-1646-6
fn gamma_inner(z: Complex) -> Complex {
let z2 = z * z;
let z3 = z2 * z;
let a = (TAU * z).sqrt();
let b = (1.0 / (E * E) * z3 * (1.0/z).sinh()).powc(0.5 * z);
let c = ((7.0/324.0) / (z3 * (35.0 * z2 + 33.0))).exp();
return a * b * c;
}
thread_local! {
pub static BUILTIN_FUNCS: HashMap<&'static str, (&'static str, Func)> = {
let mut m = HashMap::new();
m.insert("pos", ("c_pos", Func::One(std::convert::identity)));
m.insert("neg", ("c_neg", Func::One(neg)));
m.insert("recip", ("c_recip", Func::One(recip)));
m.insert("conj", ("c_conj", Func::One(conj)));
m.insert("re", ("c_re", Func::One(re)));
m.insert("im", ("c_im", Func::One(im)));
m.insert("abs_sq", ("c_abs_sq", Func::One(abs_sq)));
m.insert("abs", ("c_abs", Func::One(abs)));
m.insert("arg", ("c_arg", Func::One(arg)));
m.insert("add", ("c_add", Func::Two(<Complex as ops::Add>::add)));
m.insert("sub", ("c_sub", Func::Two(<Complex as ops::Sub>::sub)));
m.insert("mul", ("c_mul", Func::Two(<Complex as ops::Mul>::mul)));
m.insert("div", ("c_div", Func::Two(<Complex as ops::Div>::div)));
m.insert("pow", ("c_pow", Func::Two(Complex::powc)));
m.insert("exp", ("c_exp", Func::One(Complex::exp)));
m.insert("log", ("c_log", Func::One(Complex::ln)));
m.insert("sqrt", ("c_sqrt", Func::One(Complex::sqrt)));
m.insert("sin", ("c_sin", Func::One(Complex::sin)));
m.insert("cos", ("c_cos", Func::One(Complex::cos)));
m.insert("tan", ("c_tan", Func::One(Complex::tan)));
m.insert("sinh", ("c_sinh", Func::One(Complex::sinh)));
m.insert("cosh", ("c_cosh", Func::One(Complex::cosh)));
m.insert("tanh", ("c_tanh", Func::One(Complex::tanh)));
m.insert("asin", ("c_asin", Func::One(Complex::asin)));
m.insert("acos", ("c_acos", Func::One(Complex::acos)));
m.insert("atan", ("c_atan", Func::One(Complex::atan)));
m.insert("asinh", ("c_asinh", Func::One(Complex::asinh)));
m.insert("acosh", ("c_acosh", Func::One(Complex::acosh)));
m.insert("atanh", ("c_atanh", Func::One(Complex::atanh)));
m.insert("gamma", ("c_gamma", Func::One(gamma)));
m.insert("\u{0393}", ("c_gamma", Func::One(gamma)));
m
};
pub static BUILTIN_CONSTS: HashMap<&'static str, (&'static str, Complex)> = {
let mut m = HashMap::new();
m.insert("tau", ("C_TAU", Complex::new(std::f64::consts::TAU, 0.0)));
m.insert("\u{03C4}", ("C_TAU", Complex::new(std::f64::consts::TAU, 0.0)));
m.insert("e", ("C_E", Complex::new(std::f64::consts::E, 0.0)));
m.insert("i", ("C_I", Complex::new(0.0, 1.0)));
m
}
}