ruut_functions/
eval.rs

1use crate::{FType, Func, F1D, F2D, F3D, FND};
2
3impl F1D {
4    /// Evaluates function at x
5    pub fn eval(&self, x: f64) -> f64 {
6        self.0.eval(&[('x', x)])
7    }
8}
9impl F2D {
10    /// Evaluates function at (x,y)
11    pub fn eval(&self, x: f64, y: f64) -> f64 {
12        self.0.eval(&[('x', x), ('y', y)])
13    }
14}
15impl F3D {
16    /// Evaluates function at (x,y,z)
17    pub fn eval(&self, x: f64, y: f64, z: f64) -> f64 {
18        self.0.eval(&[('x', x), ('y', y), ('z', z)])
19    }
20}
21impl FND {
22    /// Evaluates function
23    pub fn eval(&self, val: &[(char, f64)]) -> f64 {
24        self.func.eval(val)
25    }
26}
27
28impl Func {
29    fn eval(&self, val: &[(char, f64)]) -> f64 {
30        match &self {
31            Func::Var(var) => val.iter().find(|&x| x.0 == *var).unwrap().1,
32            Func::Num(val) => *val as f64,
33            Func::E => std::f64::consts::E,
34            Func::PI => std::f64::consts::PI,
35            Func::Param(_, v) => *v,
36            Func::Add(add) => add.iter().map(|term| term.eval(val)).sum::<f64>(),
37            Func::Mul(mul) => mul.iter().map(|term| term.eval(val)).product::<f64>(),
38            Func::Pow(base, exp) => base.eval(val).powf(exp.eval(val)),
39            Func::S(kind, arg) => {
40                let arg = arg.eval(val);
41                match kind {
42                    FType::Ln => arg.ln(),
43                    FType::Sin => arg.sin(),
44                    FType::Cos => arg.cos(),
45                    FType::Tan => arg.tan(),
46                    FType::Cot => 1. / arg.tan(),
47                    FType::Sec => 1. / arg.cos(),
48                    FType::Csc => 1. / arg.sin(),
49                    FType::ASin => arg.asin(),
50                    FType::ACos => arg.acos(),
51                    FType::ATan => arg.atan(),
52                    FType::Sinh => arg.sinh(),
53                    FType::Cosh => arg.cosh(),
54                    FType::Tanh => arg.tanh(),
55                    FType::Coth => 1. / arg.tanh(),
56                    FType::Sech => 1. / arg.cosh(),
57                    FType::Csch => 1. / arg.sinh(),
58                    FType::ASinh => arg.asinh(),
59                    FType::ACosh => arg.acosh(),
60                    FType::ATanh => arg.atanh(),
61                    FType::Abs => arg.abs(),
62                }
63            }
64        }
65    }
66}
67
68/// Evaluates an array of F1D at x
69pub fn eval_vec_f1d(vec: &[F1D], x: f64) -> Vec<f64> {
70    let mut result = Vec::new();
71    for el in vec {
72        result.push(el.eval(x))
73    }
74    result
75}
76/// Evaluates an array of F2D at (x,y)
77pub fn eval_vec_f2d(vec: &[F2D], x: f64, y: f64) -> Vec<f64> {
78    let mut result = Vec::new();
79    for el in vec {
80        result.push(el.eval(x, y))
81    }
82    result
83}
84/// Evaluates an array of F3D at (x,y,z)
85pub fn eval_vec_f3d(vec: &[F3D], x: f64, y: f64, z: f64) -> Vec<f64> {
86    let mut result = Vec::new();
87    for el in vec {
88        result.push(el.eval(x, y, z))
89    }
90    result
91}
92#[test]
93fn test_eval() {
94    use crate::{f1d, f2d, f3d, fnd};
95    assert_eq!(f1d!("(2/3)-(1/3)x").eval(1.), 0.3333333333333333);
96    assert_eq!(f1d!("1/x").eval(0.), f64::INFINITY);
97    assert_eq!(f2d!("xy+sin(x)").eval(3., 5.), 15.141120008059866);
98    assert_eq!(f3d!("xyz*e*pi+1-x").eval(3., 5., 7.), 894.6720933807245);
99    assert_eq!(
100        fnd!("f+g^2", &['f', 'g']).eval(&[('f', 6.), ('g', 7.)]),
101        55.
102    );
103
104    // vecs
105    assert_eq!(
106        eval_vec_f1d(&vec![f1d!("cos(x)"), f1d!("tan(x)sec(x)")], 2.),
107        vec![-0.4161468365471424, 5.25064633769958]
108    );
109
110    assert_eq!(
111        eval_vec_f2d(
112            &vec![f2d!("cot(xy)+csc(y)"), f2d!("asin(y)+acos(y)")],
113            2.,
114            1.
115        ),
116        vec![0.7307375514178355, 1.5707963267948966]
117    );
118
119    assert_eq!(
120        eval_vec_f3d(
121            &vec![
122                f3d!("atan(x)+sinh(y)+cosh(z)+tanh(xy)"),
123                f3d!("coth(x)+sech(y)+csch(z)+asinh(x)+acosh(x)+atanh(y)+abs(x)")
124            ],
125            1.,
126            0.5,
127            0.2
128        ),
129        vec![2.788677381770281, 9.59735546963752]
130    );
131}