Skip to main content

rhai_sci/
integration_and_differentiation.rs

1use rhai::plugin::*;
2
3#[export_module]
4pub mod int_and_diff {
5    use crate::if_list_convert_to_vec_float_and_do;
6    use rhai::{Array, Dynamic, EvalAltResult, Position, FLOAT};
7
8    /// Returns the approximate integral of the curve defined by `y` and `x` using the trapezoidal method.
9    /// ```typescript
10    /// let y = [1.0, 1.5, 2.0];
11    /// let x = [1.0, 2.0, 3.0];
12    /// let A = trapz(x, y);
13    /// assert_eq(A, 3.0);
14    /// ```
15    /// ```typescript
16    /// let y = [1, 2, 3];
17    /// let x = [1, 2, 3];
18    /// let A = trapz(x, y);
19    /// assert_eq(A, 4.0);
20    /// ```
21    #[rhai_fn(name = "trapz", return_raw)]
22    pub fn trapz(x: Array, y: Array) -> Result<Dynamic, Box<EvalAltResult>> {
23        if x.len() != y.len() {
24            Err(EvalAltResult::ErrorArithmetic(
25                "The arrays must have the same length".to_string(),
26                Position::NONE,
27            )
28            .into())
29        } else {
30            if_list_convert_to_vec_float_and_do(&mut y.clone(), |yf| {
31                if_list_convert_to_vec_float_and_do(&mut x.clone(), |xf| {
32                    let mut trapsum = 0.0;
33                    for i in 1..x.len() {
34                        trapsum += (yf[i] + yf[i - 1]) * (xf[i] - xf[i - 1]) / 2.0;
35                    }
36                    Ok(Dynamic::from_float(trapsum))
37                })
38            })
39        }
40    }
41
42    /// Returns the approximate integral of the curve defined by `y` using the trapezoidal method.
43    /// Assumes that x-values have unit spacing.
44    /// ```typescript
45    /// let y = [1.0, 1.5, 2.0];
46    /// let A = trapz(y);
47    /// assert_eq(A, 3.0);
48    /// ```
49    /// ```typescript
50    /// let y = [1, 2, 3];
51    /// let A = trapz(y);
52    /// assert_eq(A, 4.0);
53    /// ```
54    #[rhai_fn(name = "trapz", return_raw, pure)]
55    pub fn trapz_unit(arr: &mut Array) -> Result<Dynamic, Box<EvalAltResult>> {
56        if_list_convert_to_vec_float_and_do(arr, |y| {
57            let mut trapsum = 0.0 as FLOAT;
58            for i in 1..y.len() {
59                trapsum += (y[i] + y[i - 1]) / 2.0;
60            }
61            Ok(Dynamic::from_float(trapsum))
62        })
63    }
64
65    /// Returns the difference between successive elements of a 1-D array.
66    /// ```typescript
67    /// let arr = [2, 5, 1, 7, 8];
68    /// let d = diff(arr);
69    /// assert_eq(d, [3, -4, 6, 1]);
70    /// ```
71    #[rhai_fn(name = "diff", return_raw, pure)]
72    pub fn diff(arr: &mut Array) -> Result<Array, Box<EvalAltResult>> {
73        crate::if_list_do_int_or_do_float(
74            arr,
75            |arr| {
76                let mut new_arr = vec![];
77                for idx in 1..arr.len() {
78                    new_arr.push(Dynamic::from_int(
79                        arr[idx].as_int().unwrap() - arr[idx - 1].as_int().unwrap(),
80                    ));
81                }
82                Ok(new_arr)
83            },
84            |arr| {
85                let mut new_arr = vec![];
86                for idx in 1..arr.len() {
87                    new_arr.push(Dynamic::from_float(
88                        arr[idx].as_float().unwrap() - arr[idx - 1].as_float().unwrap(),
89                    ));
90                }
91                Ok(new_arr)
92            },
93        )
94    }
95}