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_list_convert_to_vec_float_and_do(&mut y.clone(), |yf| {
24            if_list_convert_to_vec_float_and_do(&mut x.clone(), |xf| {
25                if xf.len() != yf.len() {
26                    return Err(EvalAltResult::ErrorArithmetic(
27                        "The arrays must have the same length".into(),
28                        Position::NONE,
29                    )
30                    .into());
31                }
32                let mut trapsum = 0.0;
33
34                for i in 1..xf.len() {
35                    trapsum += (yf[i] + yf[i - 1]) * (xf[i] - xf[i - 1]) / 2.0;
36                }
37                Ok(Dynamic::from_float(trapsum))
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        if arr.is_empty() {
74            return Ok(Array::new());
75        }
76        crate::if_list_do_int_or_do_float(
77            arr,
78            |arr| {
79                let mut new_arr = vec![];
80                for idx in 1..arr.len() {
81                    new_arr.push(Dynamic::from_int(
82                        arr[idx].as_int().unwrap() - arr[idx - 1].as_int().unwrap(),
83                    ));
84                }
85                Ok(new_arr)
86            },
87            |arr| {
88                let mut new_arr = vec![];
89                for idx in 1..arr.len() {
90                    new_arr.push(Dynamic::from_float(
91                        arr[idx].as_float().unwrap() - arr[idx - 1].as_float().unwrap(),
92                    ));
93                }
94                Ok(new_arr)
95            },
96        )
97    }
98}