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}