use super::super::Expression;
use crate::core::{MathConstant, Number};
use crate::simplify::Simplify;
use num_traits::ToPrimitive;
use std::collections::HashMap;
#[inline]
pub fn evaluate_function_dispatch(name: &str, args: &[Expression]) -> Option<Expression> {
if args.is_empty() {
return None;
}
match name {
"sin" => Some(crate::functions::elementary::trigonometric::sin(&args[0])),
"cos" => Some(crate::functions::elementary::trigonometric::cos(&args[0])),
"tan" => Some(crate::functions::elementary::trigonometric::tan(&args[0])),
"arcsin" | "asin" => Some(crate::functions::elementary::trigonometric::arcsin(
&args[0],
)),
"arccos" | "acos" => Some(crate::functions::elementary::trigonometric::arccos(
&args[0],
)),
"arctan" | "atan" => Some(crate::functions::elementary::trigonometric::arctan(
&args[0],
)),
"abs" => Some(crate::functions::elementary::abs_eval::abs(&args[0])),
"sqrt" => Some(crate::functions::elementary::sqrt_eval::sqrt(&args[0])),
"exp" => Some(crate::functions::elementary::exp_eval::exp(&args[0])),
"ln" => Some(crate::functions::elementary::log_eval::ln(&args[0])),
"log10" | "log" => Some(crate::functions::elementary::log_eval::log10(&args[0])),
"sign" => Some(crate::functions::elementary::rounding::sign(&args[0])),
"floor" => Some(crate::functions::elementary::rounding::floor(&args[0])),
"ceil" => Some(crate::functions::elementary::rounding::ceil(&args[0])),
"round" => Some(crate::functions::elementary::rounding::round(&args[0])),
"sinh" => Some(crate::functions::elementary::hyperbolic_eval::sinh(
&args[0],
)),
"cosh" => Some(crate::functions::elementary::hyperbolic_eval::cosh(
&args[0],
)),
"tanh" => Some(crate::functions::elementary::hyperbolic_eval::tanh(
&args[0],
)),
"gamma" => Some(crate::functions::special::gamma::gamma(&args[0])),
"digamma" => Some(crate::functions::special::digamma(&args[0])),
"polygamma" if args.len() >= 2 => {
if let Expression::Number(Number::Integer(n)) = &args[0] {
return Some(crate::functions::special::polygamma(*n as i32, &args[1]));
}
None
}
"bessel_j" | "besselj" if args.len() >= 2 => {
if let Expression::Number(Number::Integer(n)) = &args[0] {
let order = (*n) as i32;
return Some(crate::functions::special::bessel_j(order, &args[1]));
}
None
}
"bessel_y" | "bessely" if args.len() >= 2 => {
if let Expression::Number(Number::Integer(n)) = &args[0] {
let order = (*n) as i32;
return Some(crate::functions::special::bessel_y(order, &args[1]));
}
None
}
"zeta" => Some(crate::functions::special::zeta(&args[0])),
"erf" => Some(crate::functions::special::erf(&args[0])),
"erfc" => Some(crate::functions::special::erfc(&args[0])),
"factorial" => Some(crate::functions::special::factorial(&args[0])),
"beta" if args.len() >= 2 => Some(crate::functions::special::beta(&args[0], &args[1])),
"gcd" if args.len() >= 2 => Some(args[0].gcd(&args[1])),
"lcm" if args.len() >= 2 => Some(crate::functions::number_theory_eval::lcm(
&args[0], &args[1],
)),
"mod" if args.len() >= 2 => Some(crate::functions::number_theory_eval::modulo(
&args[0], &args[1],
)),
"isprime" => Some(crate::functions::number_theory_eval::isprime(&args[0])),
"degree" if args.len() >= 2 => {
if let Expression::Symbol(var) = &args[1] {
return Some(crate::functions::polynomials::degree(&args[0], var));
}
None
}
"roots" if args.len() >= 2 => {
if let Expression::Symbol(var) = &args[1] {
return Some(crate::functions::polynomials::roots(&args[0], var));
}
None
}
"expand" => Some(crate::functions::polynomials::expand(&args[0])),
"factor" => Some(crate::functions::polynomials::factor(&args[0])),
"undefined" => Some(Expression::constant(MathConstant::Undefined)),
"legendrep" | "legendre_p" if args.len() >= 2 => evaluate_orthogonal_polynomial(
&args[0],
&args[1],
crate::functions::polynomials::symbolic::expand_legendre_symbolic,
),
"chebyshevt" | "chebyshev_t" | "chebyshev_first" if args.len() >= 2 => {
evaluate_orthogonal_polynomial(
&args[0],
&args[1],
crate::functions::polynomials::symbolic::expand_chebyshev_first_symbolic,
)
}
"chebyshevu" | "chebyshev_u" | "chebyshev_second" if args.len() >= 2 => {
evaluate_orthogonal_polynomial(
&args[0],
&args[1],
crate::functions::polynomials::symbolic::expand_chebyshev_second_symbolic,
)
}
"hermiteh" | "hermite" if args.len() >= 2 => evaluate_orthogonal_polynomial(
&args[0],
&args[1],
crate::functions::polynomials::symbolic::expand_hermite_symbolic,
),
"laguerrel" | "laguerre" if args.len() >= 2 => evaluate_orthogonal_polynomial(
&args[0],
&args[1],
crate::functions::polynomials::symbolic::expand_laguerre_symbolic,
),
_ => None,
}
}
pub fn evaluate_orthogonal_polynomial<F>(
degree_arg: &Expression,
var_arg: &Expression,
expander: F,
) -> Option<Expression>
where
F: Fn(usize) -> Expression,
{
let n = match degree_arg {
Expression::Number(Number::Integer(i)) if *i >= 0 => *i as usize,
Expression::Number(Number::BigInteger(bi)) => {
if let Some(n) = bi.to_u64() {
n as usize
} else {
return None;
}
}
_ => return None,
};
let expanded = expander(n);
match var_arg {
Expression::Symbol(sym) if sym.name() == "x" => Some(expanded),
_ => {
let mut subs = HashMap::new();
subs.insert("x".to_owned(), var_arg.clone());
Some(expanded.substitute(&subs).simplify())
}
}
}