mathhook_core/core/expression/evaluation/
dispatch.rs1use super::super::Expression;
11use crate::core::{MathConstant, Number};
12use crate::simplify::Simplify;
13use num_traits::ToPrimitive;
14use std::collections::HashMap;
15
16#[inline]
64pub fn evaluate_function_dispatch(name: &str, args: &[Expression]) -> Option<Expression> {
65 if args.is_empty() {
66 return None;
67 }
68
69 match name {
70 "sin" => Some(crate::functions::elementary::trigonometric::sin(&args[0])),
71 "cos" => Some(crate::functions::elementary::trigonometric::cos(&args[0])),
72 "tan" => Some(crate::functions::elementary::trigonometric::tan(&args[0])),
73 "arcsin" | "asin" => Some(crate::functions::elementary::trigonometric::arcsin(
74 &args[0],
75 )),
76 "arccos" | "acos" => Some(crate::functions::elementary::trigonometric::arccos(
77 &args[0],
78 )),
79 "arctan" | "atan" => Some(crate::functions::elementary::trigonometric::arctan(
80 &args[0],
81 )),
82 "abs" => Some(crate::functions::elementary::abs_eval::abs(&args[0])),
83 "sqrt" => Some(crate::functions::elementary::sqrt_eval::sqrt(&args[0])),
84 "exp" => Some(crate::functions::elementary::exp_eval::exp(&args[0])),
85 "ln" => Some(crate::functions::elementary::log_eval::ln(&args[0])),
86 "log10" | "log" => Some(crate::functions::elementary::log_eval::log10(&args[0])),
87 "sign" => Some(crate::functions::elementary::rounding::sign(&args[0])),
88 "floor" => Some(crate::functions::elementary::rounding::floor(&args[0])),
89 "ceil" => Some(crate::functions::elementary::rounding::ceil(&args[0])),
90 "round" => Some(crate::functions::elementary::rounding::round(&args[0])),
91 "sinh" => Some(crate::functions::elementary::hyperbolic_eval::sinh(
92 &args[0],
93 )),
94 "cosh" => Some(crate::functions::elementary::hyperbolic_eval::cosh(
95 &args[0],
96 )),
97 "tanh" => Some(crate::functions::elementary::hyperbolic_eval::tanh(
98 &args[0],
99 )),
100 "gamma" => Some(crate::functions::special::gamma::gamma(&args[0])),
101 "digamma" => Some(crate::functions::special::digamma(&args[0])),
102 "polygamma" if args.len() >= 2 => {
103 if let Expression::Number(Number::Integer(n)) = &args[0] {
104 return Some(crate::functions::special::polygamma(*n as i32, &args[1]));
105 }
106 None
107 }
108 "bessel_j" | "besselj" if args.len() >= 2 => {
109 if let Expression::Number(Number::Integer(n)) = &args[0] {
110 let order = (*n) as i32;
111 return Some(crate::functions::special::bessel_j(order, &args[1]));
112 }
113 None
114 }
115 "bessel_y" | "bessely" if args.len() >= 2 => {
116 if let Expression::Number(Number::Integer(n)) = &args[0] {
117 let order = (*n) as i32;
118 return Some(crate::functions::special::bessel_y(order, &args[1]));
119 }
120 None
121 }
122 "zeta" => Some(crate::functions::special::zeta(&args[0])),
123 "erf" => Some(crate::functions::special::erf(&args[0])),
124 "erfc" => Some(crate::functions::special::erfc(&args[0])),
125 "factorial" => Some(crate::functions::special::factorial(&args[0])),
126 "beta" if args.len() >= 2 => Some(crate::functions::special::beta(&args[0], &args[1])),
127 "gcd" if args.len() >= 2 => Some(args[0].gcd(&args[1])),
128 "lcm" if args.len() >= 2 => Some(crate::functions::number_theory_eval::lcm(
129 &args[0], &args[1],
130 )),
131 "mod" if args.len() >= 2 => Some(crate::functions::number_theory_eval::modulo(
132 &args[0], &args[1],
133 )),
134 "isprime" => Some(crate::functions::number_theory_eval::isprime(&args[0])),
135 "degree" if args.len() >= 2 => {
136 if let Expression::Symbol(var) = &args[1] {
137 return Some(crate::functions::polynomials::degree(&args[0], var));
138 }
139 None
140 }
141 "roots" if args.len() >= 2 => {
142 if let Expression::Symbol(var) = &args[1] {
143 return Some(crate::functions::polynomials::roots(&args[0], var));
144 }
145 None
146 }
147 "expand" => Some(crate::functions::polynomials::expand(&args[0])),
148 "factor" => Some(crate::functions::polynomials::factor(&args[0])),
149 "undefined" => Some(Expression::constant(MathConstant::Undefined)),
150 "legendrep" | "legendre_p" if args.len() >= 2 => evaluate_orthogonal_polynomial(
151 &args[0],
152 &args[1],
153 crate::functions::polynomials::symbolic::expand_legendre_symbolic,
154 ),
155 "chebyshevt" | "chebyshev_t" | "chebyshev_first" if args.len() >= 2 => {
156 evaluate_orthogonal_polynomial(
157 &args[0],
158 &args[1],
159 crate::functions::polynomials::symbolic::expand_chebyshev_first_symbolic,
160 )
161 }
162 "chebyshevu" | "chebyshev_u" | "chebyshev_second" if args.len() >= 2 => {
163 evaluate_orthogonal_polynomial(
164 &args[0],
165 &args[1],
166 crate::functions::polynomials::symbolic::expand_chebyshev_second_symbolic,
167 )
168 }
169 "hermiteh" | "hermite" if args.len() >= 2 => evaluate_orthogonal_polynomial(
170 &args[0],
171 &args[1],
172 crate::functions::polynomials::symbolic::expand_hermite_symbolic,
173 ),
174 "laguerrel" | "laguerre" if args.len() >= 2 => evaluate_orthogonal_polynomial(
175 &args[0],
176 &args[1],
177 crate::functions::polynomials::symbolic::expand_laguerre_symbolic,
178 ),
179 _ => None,
180 }
181}
182
183pub fn evaluate_orthogonal_polynomial<F>(
206 degree_arg: &Expression,
207 var_arg: &Expression,
208 expander: F,
209) -> Option<Expression>
210where
211 F: Fn(usize) -> Expression,
212{
213 let n = match degree_arg {
214 Expression::Number(Number::Integer(i)) if *i >= 0 => *i as usize,
215 Expression::Number(Number::BigInteger(bi)) => {
216 if let Some(n) = bi.to_u64() {
217 n as usize
218 } else {
219 return None;
220 }
221 }
222 _ => return None,
223 };
224
225 let expanded = expander(n);
226
227 match var_arg {
228 Expression::Symbol(sym) if sym.name() == "x" => Some(expanded),
229 _ => {
230 let mut subs = HashMap::new();
231 subs.insert("x".to_owned(), var_arg.clone());
232 Some(expanded.substitute(&subs).simplify())
233 }
234 }
235}